You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: lib/async/task.rb
+28-10Lines changed: 28 additions & 10 deletions
Original file line number
Diff line number
Diff line change
@@ -18,13 +18,24 @@
18
18
moduleAsync
19
19
# Raised when a task is explicitly stopped.
20
20
classStop < Exception
21
+
# Represents the source of the stop operation.
22
+
classCause < Exception
23
+
end
24
+
25
+
# Create a new stop operation.
26
+
definitialize(message="Task was stopped")
27
+
super(message)
28
+
end
29
+
21
30
# Used to defer stopping the current task until later.
22
31
classLater
23
32
# Create a new stop later operation.
24
33
#
25
34
# @parameter task [Task] The task to stop later.
26
-
definitialize(task)
35
+
# @parameter cause [Exception] The cause of the stop operation.
36
+
definitialize(task,cause=nil)
27
37
@task=task
38
+
@cause=cause
28
39
end
29
40
30
41
# @returns [Boolean] Whether the task is alive.
@@ -34,7 +45,7 @@ def alive?
34
45
35
46
# Transfer control to the operation - this will stop the task.
36
47
deftransfer
37
-
@task.stop
48
+
@task.stop(false,cause: @cause)
38
49
end
39
50
end
40
51
end
@@ -266,7 +277,14 @@ def wait
266
277
# If `later` is false, it means that `stop` has been invoked directly. When `later` is true, it means that `stop` is invoked by `stop_children` or some other indirect mechanism. In that case, if we encounter the "current" fiber, we can't stop it right away, as it's currently performing `#stop`. Stopping it immediately would interrupt the current stop traversal, so we need to schedule the stop to occur later.
267
278
#
268
279
# @parameter later [Boolean] Whether to stop the task later, or immediately.
269
-
defstop(later=false)
280
+
# @parameter cause [Exception] The cause of the stop operation.
281
+
defstop(later=false,cause: $!)
282
+
# If no cause is given, we generate one from the current call stack:
283
+
unlesscause
284
+
cause=Stop::Cause.new("Stop requested!")
285
+
cause.set_backtrace(caller_locations(1..-1))
286
+
end
287
+
270
288
ifself.stopped?
271
289
# If the task is already stopped, a `stop` state transition re-enters the same state which is a no-op. However, we will also attempt to stop any running children too. This can happen if the children did not stop correctly the first time around. Doing this should probably be considered a bug, but it's better to be safe than sorry.
272
290
returnstopped!
@@ -280,27 +298,27 @@ def stop(later = false)
280
298
# If we are deferring stop...
281
299
if@defer_stop == false
282
300
# Don't stop now... but update the state so we know we need to stop later.
283
-
@defer_stop=true
301
+
@defer_stop=cause
284
302
returnfalse
285
303
end
286
304
287
305
ifself.current?
288
306
# If the fiber is current, and later is `true`, we need to schedule the fiber to be stopped later, as it's currently invoking `stop`:
289
307
iflater
290
308
# If the fiber is the current fiber and we want to stop it later, schedule it:
291
-
Fiber.scheduler.push(Stop::Later.new(self))
309
+
Fiber.scheduler.push(Stop::Later.new(self,cause))
292
310
else
293
311
# Otherwise, raise the exception directly:
294
-
raiseStop,"Stopping current task!"
312
+
raiseStop,"Stopping current task!",cause: cause
295
313
end
296
314
else
297
315
# If the fiber is not curent, we can raise the exception directly:
298
316
begin
299
317
# There is a chance that this will stop the fiber that originally called stop. If that happens, the exception handling in `#stopped` will rescue the exception and re-raise it later.
300
-
Fiber.scheduler.raise(@fiber,Stop)
318
+
Fiber.scheduler.raise(@fiber,Stop,cause: cause)
301
319
rescueFiberError
302
320
# In some cases, this can cause a FiberError (it might be resumed already), so we schedule it to be stopped later:
303
-
Fiber.scheduler.push(Stop::Later.new(self))
321
+
Fiber.scheduler.push(Stop::Later.new(self,cause))
304
322
end
305
323
end
306
324
else
@@ -340,7 +358,7 @@ def defer_stop
340
358
341
359
# If we were asked to stop, we should do so now:
342
360
ifdefer_stop
343
-
raiseStop,"Stopping current task (was deferred)!"
361
+
raiseStop,"Stopping current task (was deferred)!",cause: defer_stop
344
362
end
345
363
end
346
364
else
@@ -351,7 +369,7 @@ def defer_stop
351
369
352
370
# @returns [Boolean] Whether stop has been deferred.
353
371
defstop_deferred?
354
-
@defer_stop
372
+
!!@defer_stop
355
373
end
356
374
357
375
# Lookup the {Task} for the current fiber. Raise `RuntimeError` if none is available.
0 commit comments