module Await::ThreadExtension
Public Instance Methods
await() { || ... }
click to toggle source
# File lib/await.rb, line 6 def await # Capture the current context to properly chain this await in parent = @deferred deferred = @deferred = { :fiber => Fiber.current } if (parent) parent[deferred] = true end yield if (block_given?) # So long as there is at least one outstanding defer block, this fiber # must continue to yield. while (deferred.size > 1) fiber, trigger, block, args = Fiber.yield deferred.delete(trigger) if (block) # Always introduce the correct context here by setting the # thread-local @deferred instance variable. @deferred = deferred block.call(*args) end end # If this was part of an existing await call then remove the current # await operation from the list of pending entries. if (parent) if (deferred[:fiber] == Fiber.current) parent.delete(deferred) else parent[:fiber].transfer([ Fiber.current, deferred ]) end end true end
defer(&block)
click to toggle source
# File lib/await.rb, line 48 def defer(&block) deferred = @deferred trigger = lambda do |*args| if (deferred[:fiber] == Fiber.current) # Within the same fiber, remove this from the pending list deferred.delete(trigger) block.call(*args) else # If this is executing in a different fiber, transfer control back # to the original fiber for reasons of continuity. deferred[:fiber].transfer([ Fiber.current, trigger, block, args ]) end end deferred[trigger] = true trigger end