Module: Await::ThreadExtension

Included in:
Thread
Defined in:
lib/await.rb

Instance Method Summary collapse

Instance Method Details

#awaitObject



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 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) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 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