async 1.32.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/lib/async/barrier.md +36 -0
 - data/lib/async/barrier.rb +14 -6
 - data/lib/async/clock.rb +11 -0
 - data/lib/async/condition.md +31 -0
 - data/lib/async/condition.rb +27 -16
 - data/lib/async/node.rb +27 -12
 - data/lib/async/notification.rb +4 -4
 - data/lib/async/queue.rb +8 -21
 - data/lib/async/reactor.rb +11 -320
 - data/lib/async/scheduler.rb +235 -48
 - data/lib/async/semaphore.md +41 -0
 - data/lib/async/semaphore.rb +8 -24
 - data/lib/async/task.rb +68 -114
 - data/lib/async/version.rb +1 -1
 - data/lib/async/wrapper.rb +19 -179
 - data/lib/async.rb +0 -5
 - data/lib/kernel/async.rb +26 -2
 - data/lib/kernel/sync.rb +14 -4
 - metadata +10 -10
 - data/lib/async/debug/monitor.rb +0 -47
 - data/lib/async/debug/selector.rb +0 -82
 - data/lib/async/logger.rb +0 -28
 
| 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            A synchronization primitive, which limits access to a given resource, such as a limited number of database connections, open files, or network connections.
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Example
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ~~~ ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'async'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'async/semaphore'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'net/http'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            Sync do
         
     | 
| 
      
 11 
     | 
    
         
            +
            	# Only allow two concurrent tasks at a time:
         
     | 
| 
      
 12 
     | 
    
         
            +
            	semaphore = Async::Semaphore.new(2)
         
     | 
| 
      
 13 
     | 
    
         
            +
            	
         
     | 
| 
      
 14 
     | 
    
         
            +
            	# Generate an array of 10 numbers:
         
     | 
| 
      
 15 
     | 
    
         
            +
            	terms = ['ruby', 'python', 'go', 'java', 'c++'] 
         
     | 
| 
      
 16 
     | 
    
         
            +
            	
         
     | 
| 
      
 17 
     | 
    
         
            +
            	# Search for the terms:
         
     | 
| 
      
 18 
     | 
    
         
            +
            	terms.each do |term|
         
     | 
| 
      
 19 
     | 
    
         
            +
            		semaphore.async do |task|
         
     | 
| 
      
 20 
     | 
    
         
            +
            			Console.logger.info("Searching for #{term}...")
         
     | 
| 
      
 21 
     | 
    
         
            +
            			response = Net::HTTP.get(URI "https://www.google.com/search?q=#{term}")
         
     | 
| 
      
 22 
     | 
    
         
            +
            			Console.logger.info("Got response #{response.size} bytes.")
         
     | 
| 
      
 23 
     | 
    
         
            +
            		end
         
     | 
| 
      
 24 
     | 
    
         
            +
            	end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
            ~~~
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            ### Output
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            ~~~
         
     | 
| 
      
 31 
     | 
    
         
            +
            0.0s     info: Searching for ruby... [ec=0x3c] [pid=50523]
         
     | 
| 
      
 32 
     | 
    
         
            +
            0.04s     info: Searching for python... [ec=0x21c] [pid=50523]
         
     | 
| 
      
 33 
     | 
    
         
            +
            1.7s     info: Got response 182435 bytes. [ec=0x3c] [pid=50523]
         
     | 
| 
      
 34 
     | 
    
         
            +
            1.71s     info: Searching for go... [ec=0x834] [pid=50523]
         
     | 
| 
      
 35 
     | 
    
         
            +
            3.0s     info: Got response 204854 bytes. [ec=0x21c] [pid=50523]
         
     | 
| 
      
 36 
     | 
    
         
            +
            3.0s     info: Searching for java... [ec=0xf64] [pid=50523]
         
     | 
| 
      
 37 
     | 
    
         
            +
            4.32s     info: Got response 103235 bytes. [ec=0x834] [pid=50523]
         
     | 
| 
      
 38 
     | 
    
         
            +
            4.32s     info: Searching for c++... [ec=0x12d4] [pid=50523]
         
     | 
| 
      
 39 
     | 
    
         
            +
            4.65s     info: Got response 109697 bytes. [ec=0xf64] [pid=50523]
         
     | 
| 
      
 40 
     | 
    
         
            +
            6.64s     info: Got response 87249 bytes. [ec=0x12d4] [pid=50523]
         
     | 
| 
      
 41 
     | 
    
         
            +
            ~~~
         
     | 
    
        data/lib/async/semaphore.rb
    CHANGED
    
    | 
         @@ -21,8 +21,11 @@ 
     | 
|
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
            module Async
         
     | 
| 
       24 
     | 
    
         
            -
            	# A  
     | 
| 
      
 24 
     | 
    
         
            +
            	# A synchronization primitive, which limits access to a given resource.
         
     | 
| 
      
 25 
     | 
    
         
            +
            	# @public Since `stable-v1`.
         
     | 
| 
       25 
26 
     | 
    
         
             
            	class Semaphore
         
     | 
| 
      
 27 
     | 
    
         
            +
            		# @parameter limit [Integer] The maximum number of times the semaphore can be acquired before it blocks.
         
     | 
| 
      
 28 
     | 
    
         
            +
            		# @parameter parent [Task | Semaphore | Nil] The parent for holding any children tasks.
         
     | 
| 
       26 
29 
     | 
    
         
             
            		def initialize(limit = 1, parent: nil)
         
     | 
| 
       27 
30 
     | 
    
         
             
            			@count = 0
         
     | 
| 
       28 
31 
     | 
    
         
             
            			@limit = limit
         
     | 
| 
         @@ -40,25 +43,6 @@ module Async 
     | 
|
| 
       40 
43 
     | 
    
         
             
            		# The tasks waiting on this semaphore.
         
     | 
| 
       41 
44 
     | 
    
         
             
            		attr :waiting
         
     | 
| 
       42 
45 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
            		# Allow setting the limit. This is useful for cases where the semaphore is used to limit the number of concurrent tasks, but the number of tasks is not known in advance or needs to be modified.
         
     | 
| 
       44 
     | 
    
         
            -
            		#
         
     | 
| 
       45 
     | 
    
         
            -
            		# On increasing the limit, some tasks may be immediately resumed. On decreasing the limit, some tasks may execute until the count is < than the limit. 
         
     | 
| 
       46 
     | 
    
         
            -
            		#
         
     | 
| 
       47 
     | 
    
         
            -
            		# @parameter limit [Integer] The new limit.
         
     | 
| 
       48 
     | 
    
         
            -
            		def limit= limit
         
     | 
| 
       49 
     | 
    
         
            -
            			difference = limit - @limit
         
     | 
| 
       50 
     | 
    
         
            -
            			@limit = limit
         
     | 
| 
       51 
     | 
    
         
            -
            			
         
     | 
| 
       52 
     | 
    
         
            -
            			# We can't suspend 
         
     | 
| 
       53 
     | 
    
         
            -
            			if difference > 0
         
     | 
| 
       54 
     | 
    
         
            -
            				difference.times do
         
     | 
| 
       55 
     | 
    
         
            -
            					break unless fiber = @waiting.shift
         
     | 
| 
       56 
     | 
    
         
            -
            					
         
     | 
| 
       57 
     | 
    
         
            -
            					fiber.resume
         
     | 
| 
       58 
     | 
    
         
            -
            				end
         
     | 
| 
       59 
     | 
    
         
            -
            			end
         
     | 
| 
       60 
     | 
    
         
            -
            		end
         
     | 
| 
       61 
     | 
    
         
            -
            		
         
     | 
| 
       62 
46 
     | 
    
         
             
            		# Is the semaphore currently acquired?
         
     | 
| 
       63 
47 
     | 
    
         
             
            		def empty?
         
     | 
| 
       64 
48 
     | 
    
         
             
            			@count.zero?
         
     | 
| 
         @@ -86,8 +70,8 @@ module Async 
     | 
|
| 
       86 
70 
     | 
    
         | 
| 
       87 
71 
     | 
    
         
             
            		# Acquire the semaphore, block if we are at the limit.
         
     | 
| 
       88 
72 
     | 
    
         
             
            		# If no block is provided, you must call release manually.
         
     | 
| 
       89 
     | 
    
         
            -
            		# @ 
     | 
| 
       90 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 73 
     | 
    
         
            +
            		# @yields {...} When the semaphore can be acquired.
         
     | 
| 
      
 74 
     | 
    
         
            +
            		# @returns The result of the block if invoked.
         
     | 
| 
       91 
75 
     | 
    
         
             
            		def acquire
         
     | 
| 
       92 
76 
     | 
    
         
             
            			wait
         
     | 
| 
       93 
77 
     | 
    
         | 
| 
         @@ -108,7 +92,7 @@ module Async 
     | 
|
| 
       108 
92 
     | 
    
         | 
| 
       109 
93 
     | 
    
         
             
            			while (@limit - @count) > 0 and fiber = @waiting.shift
         
     | 
| 
       110 
94 
     | 
    
         
             
            				if fiber.alive?
         
     | 
| 
       111 
     | 
    
         
            -
            					 
     | 
| 
      
 95 
     | 
    
         
            +
            					Fiber.scheduler.resume(fiber)
         
     | 
| 
       112 
96 
     | 
    
         
             
            				end
         
     | 
| 
       113 
97 
     | 
    
         
             
            			end
         
     | 
| 
       114 
98 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -121,7 +105,7 @@ module Async 
     | 
|
| 
       121 
105 
     | 
    
         | 
| 
       122 
106 
     | 
    
         
             
            			if blocking?
         
     | 
| 
       123 
107 
     | 
    
         
             
            				@waiting << fiber
         
     | 
| 
       124 
     | 
    
         
            -
            				 
     | 
| 
      
 108 
     | 
    
         
            +
            				Fiber.scheduler.transfer while blocking?
         
     | 
| 
       125 
109 
     | 
    
         
             
            			end
         
     | 
| 
       126 
110 
     | 
    
         
             
            		rescue Exception
         
     | 
| 
       127 
111 
     | 
    
         
             
            			@waiting.delete(fiber)
         
     | 
    
        data/lib/async/task.rb
    CHANGED
    
    | 
         @@ -21,7 +21,6 @@ 
     | 
|
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
            require 'fiber'
         
     | 
| 
       24 
     | 
    
         
            -
            require 'forwardable'
         
     | 
| 
       25 
24 
     | 
    
         | 
| 
       26 
25 
     | 
    
         
             
            require_relative 'node'
         
     | 
| 
       27 
26 
     | 
    
         
             
            require_relative 'condition'
         
     | 
| 
         @@ -38,57 +37,45 @@ module Async 
     | 
|
| 
       38 
37 
     | 
    
         
             
            				true
         
     | 
| 
       39 
38 
     | 
    
         
             
            			end
         
     | 
| 
       40 
39 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
            			def  
     | 
| 
      
 40 
     | 
    
         
            +
            			def transfer
         
     | 
| 
       42 
41 
     | 
    
         
             
            				@task.stop
         
     | 
| 
       43 
42 
     | 
    
         
             
            			end
         
     | 
| 
       44 
43 
     | 
    
         
             
            		end
         
     | 
| 
       45 
44 
     | 
    
         
             
            	end
         
     | 
| 
       46 
45 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
            	#  
     | 
| 
       48 
     | 
    
         
            -
            	#  
     | 
| 
      
 46 
     | 
    
         
            +
            	# Raised if a timeout occurs on a specific Fiber. Handled gracefully by `Task`.
         
     | 
| 
      
 47 
     | 
    
         
            +
            	# @public Since `stable-v1`.
         
     | 
| 
      
 48 
     | 
    
         
            +
            	class TimeoutError < StandardError
         
     | 
| 
      
 49 
     | 
    
         
            +
            		def initialize(message = "execution expired")
         
     | 
| 
      
 50 
     | 
    
         
            +
            			super
         
     | 
| 
      
 51 
     | 
    
         
            +
            		end
         
     | 
| 
      
 52 
     | 
    
         
            +
            	end
         
     | 
| 
      
 53 
     | 
    
         
            +
            	
         
     | 
| 
      
 54 
     | 
    
         
            +
            	# Encapsulates the state of a running task and it's result.
         
     | 
| 
      
 55 
     | 
    
         
            +
            	# @public Since `stable-v1`.
         
     | 
| 
       49 
56 
     | 
    
         
             
            	class Task < Node
         
     | 
| 
       50 
     | 
    
         
            -
            		 
     | 
| 
       51 
     | 
    
         
            -
            		
         
     | 
| 
       52 
     | 
    
         
            -
            		# Yield the unerlying `result` for the task. If the result
         
     | 
| 
       53 
     | 
    
         
            -
            		# is an Exception, then that result will be raised an its
         
     | 
| 
       54 
     | 
    
         
            -
            		# exception.
         
     | 
| 
       55 
     | 
    
         
            -
            		# @return [Object] result of the task
         
     | 
| 
       56 
     | 
    
         
            -
            		# @raise [Exception] if the result is an exception
         
     | 
| 
       57 
     | 
    
         
            -
            		# @yield [result] result of the task if a block if given.
         
     | 
| 
      
 57 
     | 
    
         
            +
            		# @deprecated With no replacement.
         
     | 
| 
       58 
58 
     | 
    
         
             
            		def self.yield
         
     | 
| 
       59 
     | 
    
         
            -
            			 
     | 
| 
       60 
     | 
    
         
            -
            				result = yield
         
     | 
| 
       61 
     | 
    
         
            -
            			else
         
     | 
| 
       62 
     | 
    
         
            -
            				result = Fiber.yield
         
     | 
| 
       63 
     | 
    
         
            -
            			end
         
     | 
| 
       64 
     | 
    
         
            -
            			
         
     | 
| 
       65 
     | 
    
         
            -
            			if result.is_a? Exception
         
     | 
| 
       66 
     | 
    
         
            -
            				raise result
         
     | 
| 
       67 
     | 
    
         
            -
            			else
         
     | 
| 
       68 
     | 
    
         
            -
            				return result
         
     | 
| 
       69 
     | 
    
         
            -
            			end
         
     | 
| 
      
 59 
     | 
    
         
            +
            			Fiber.scheduler.transfer
         
     | 
| 
       70 
60 
     | 
    
         
             
            		end
         
     | 
| 
       71 
61 
     | 
    
         | 
| 
       72 
62 
     | 
    
         
             
            		# Create a new task.
         
     | 
| 
       73 
     | 
    
         
            -
            		# @ 
     | 
| 
       74 
     | 
    
         
            -
            		# @ 
     | 
| 
       75 
     | 
    
         
            -
            		def initialize( 
     | 
| 
       76 
     | 
    
         
            -
            			super(parent 
     | 
| 
       77 
     | 
    
         
            -
            			
         
     | 
| 
       78 
     | 
    
         
            -
            			@reactor = reactor
         
     | 
| 
      
 63 
     | 
    
         
            +
            		# @parameter reactor [Reactor] the reactor this task will run within.
         
     | 
| 
      
 64 
     | 
    
         
            +
            		# @parameter parent [Task] the parent task.
         
     | 
| 
      
 65 
     | 
    
         
            +
            		def initialize(parent = Task.current?, finished: nil, **options, &block)
         
     | 
| 
      
 66 
     | 
    
         
            +
            			super(parent, **options)
         
     | 
| 
       79 
67 
     | 
    
         | 
| 
       80 
68 
     | 
    
         
             
            			@status = :initialized
         
     | 
| 
       81 
69 
     | 
    
         
             
            			@result = nil
         
     | 
| 
       82 
70 
     | 
    
         
             
            			@finished = finished
         
     | 
| 
       83 
71 
     | 
    
         | 
| 
       84 
     | 
    
         
            -
            			@ 
     | 
| 
       85 
     | 
    
         
            -
            			
         
     | 
| 
       86 
     | 
    
         
            -
            			@fiber = make_fiber(&block)
         
     | 
| 
       87 
     | 
    
         
            -
            			
         
     | 
| 
       88 
     | 
    
         
            -
            			@defer_stop = nil
         
     | 
| 
      
 72 
     | 
    
         
            +
            			@block = block
         
     | 
| 
      
 73 
     | 
    
         
            +
            			@fiber = nil
         
     | 
| 
       89 
74 
     | 
    
         
             
            		end
         
     | 
| 
       90 
75 
     | 
    
         | 
| 
       91 
     | 
    
         
            -
            		 
     | 
| 
      
 76 
     | 
    
         
            +
            		def reactor
         
     | 
| 
      
 77 
     | 
    
         
            +
            			self.root
         
     | 
| 
      
 78 
     | 
    
         
            +
            		end
         
     | 
| 
       92 
79 
     | 
    
         | 
| 
       93 
80 
     | 
    
         
             
            		if Fiber.current.respond_to?(:backtrace)
         
     | 
| 
       94 
81 
     | 
    
         
             
            			def backtrace(*arguments)
         
     | 
| 
         @@ -100,14 +87,19 @@ module Async 
     | 
|
| 
       100 
87 
     | 
    
         
             
            			"\#<#{self.description} (#{@status})>"
         
     | 
| 
       101 
88 
     | 
    
         
             
            		end
         
     | 
| 
       102 
89 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
            		# @ 
     | 
| 
       104 
     | 
    
         
            -
            		 
     | 
| 
      
 90 
     | 
    
         
            +
            		# @deprecated Prefer {Kernel#sleep} except when compatibility with `stable-v1` is required.
         
     | 
| 
      
 91 
     | 
    
         
            +
            		def sleep(duration = nil)
         
     | 
| 
      
 92 
     | 
    
         
            +
            			super
         
     | 
| 
      
 93 
     | 
    
         
            +
            		end
         
     | 
| 
       105 
94 
     | 
    
         | 
| 
       106 
     | 
    
         
            -
            		 
     | 
| 
      
 95 
     | 
    
         
            +
            		# @deprecated Replaced by {Scheduler#timeout_after}.
         
     | 
| 
      
 96 
     | 
    
         
            +
            		def with_timeout(timeout, exception = TimeoutError, message = "execution expired", &block)
         
     | 
| 
      
 97 
     | 
    
         
            +
            			Fiber.scheduler.timeout_after(timeout, exception, message, &block)
         
     | 
| 
      
 98 
     | 
    
         
            +
            		end
         
     | 
| 
       107 
99 
     | 
    
         | 
| 
       108 
100 
     | 
    
         
             
            		# Yield back to the reactor and allow other fibers to execute.
         
     | 
| 
       109 
101 
     | 
    
         
             
            		def yield
         
     | 
| 
       110 
     | 
    
         
            -
            			 
     | 
| 
      
 102 
     | 
    
         
            +
            			Fiber.scheduler.yield
         
     | 
| 
       111 
103 
     | 
    
         
             
            		end
         
     | 
| 
       112 
104 
     | 
    
         | 
| 
       113 
105 
     | 
    
         
             
            		# @attr fiber [Fiber] The fiber which is being used for the execution of this task.
         
     | 
| 
         @@ -125,14 +117,14 @@ module Async 
     | 
|
| 
       125 
117 
     | 
    
         
             
            			if @status == :initialized
         
     | 
| 
       126 
118 
     | 
    
         
             
            				@status = :running
         
     | 
| 
       127 
119 
     | 
    
         | 
| 
       128 
     | 
    
         
            -
            				 
     | 
| 
      
 120 
     | 
    
         
            +
            				schedule(arguments)
         
     | 
| 
       129 
121 
     | 
    
         
             
            			else
         
     | 
| 
       130 
122 
     | 
    
         
             
            				raise RuntimeError, "Task already running!"
         
     | 
| 
       131 
123 
     | 
    
         
             
            			end
         
     | 
| 
       132 
124 
     | 
    
         
             
            		end
         
     | 
| 
       133 
125 
     | 
    
         | 
| 
       134 
126 
     | 
    
         
             
            		def async(*arguments, **options, &block)
         
     | 
| 
       135 
     | 
    
         
            -
            			task = Task.new( 
     | 
| 
      
 127 
     | 
    
         
            +
            			task = Task.new(self, **options, &block)
         
     | 
| 
       136 
128 
     | 
    
         | 
| 
       137 
129 
     | 
    
         
             
            			task.run(*arguments)
         
     | 
| 
       138 
130 
     | 
    
         | 
| 
         @@ -140,22 +132,26 @@ module Async 
     | 
|
| 
       140 
132 
     | 
    
         
             
            		end
         
     | 
| 
       141 
133 
     | 
    
         | 
| 
       142 
134 
     | 
    
         
             
            		# Retrieve the current result of the task. Will cause the caller to wait until result is available.
         
     | 
| 
       143 
     | 
    
         
            -
            		# @ 
     | 
| 
       144 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 135 
     | 
    
         
            +
            		# @raises[RuntimeError] If the task's fiber is the current fiber.
         
     | 
| 
      
 136 
     | 
    
         
            +
            		# @returns [Object] The final expression/result of the task's block.
         
     | 
| 
       145 
137 
     | 
    
         
             
            		def wait
         
     | 
| 
       146 
     | 
    
         
            -
            			raise  
     | 
| 
      
 138 
     | 
    
         
            +
            			raise "Cannot wait on own fiber" if Fiber.current.equal?(@fiber)
         
     | 
| 
       147 
139 
     | 
    
         | 
| 
       148 
140 
     | 
    
         
             
            			if running?
         
     | 
| 
       149 
141 
     | 
    
         
             
            				@finished ||= Condition.new
         
     | 
| 
       150 
142 
     | 
    
         
             
            				@finished.wait
         
     | 
| 
      
 143 
     | 
    
         
            +
            			end
         
     | 
| 
      
 144 
     | 
    
         
            +
            			
         
     | 
| 
      
 145 
     | 
    
         
            +
            			case @result
         
     | 
| 
      
 146 
     | 
    
         
            +
            			when Exception
         
     | 
| 
      
 147 
     | 
    
         
            +
            				raise @result
         
     | 
| 
       151 
148 
     | 
    
         
             
            			else
         
     | 
| 
       152 
     | 
    
         
            -
            				 
     | 
| 
      
 149 
     | 
    
         
            +
            				return @result
         
     | 
| 
       153 
150 
     | 
    
         
             
            			end
         
     | 
| 
       154 
151 
     | 
    
         
             
            		end
         
     | 
| 
       155 
152 
     | 
    
         | 
| 
       156 
     | 
    
         
            -
            		#  
     | 
| 
       157 
     | 
    
         
            -
            		 
     | 
| 
       158 
     | 
    
         
            -
            		# Soon to become attr :result
         
     | 
| 
      
 153 
     | 
    
         
            +
            		# Access the result of the task without waiting. May be nil if the task is not completed.
         
     | 
| 
      
 154 
     | 
    
         
            +
            		attr :result
         
     | 
| 
       159 
155 
     | 
    
         | 
| 
       160 
156 
     | 
    
         
             
            		# Stop the task and all of its children.
         
     | 
| 
       161 
157 
     | 
    
         
             
            		def stop(later = false)
         
     | 
| 
         @@ -164,25 +160,18 @@ module Async 
     | 
|
| 
       164 
160 
     | 
    
         
             
            				return
         
     | 
| 
       165 
161 
     | 
    
         
             
            			end
         
     | 
| 
       166 
162 
     | 
    
         | 
| 
       167 
     | 
    
         
            -
            			# If we are deferring stop...
         
     | 
| 
       168 
     | 
    
         
            -
            			if @defer_stop == false
         
     | 
| 
       169 
     | 
    
         
            -
            				# Don't stop now... but update the state so we know we need to stop later.
         
     | 
| 
       170 
     | 
    
         
            -
            				@defer_stop = true
         
     | 
| 
       171 
     | 
    
         
            -
            				return false
         
     | 
| 
       172 
     | 
    
         
            -
            			end
         
     | 
| 
       173 
     | 
    
         
            -
            			
         
     | 
| 
       174 
163 
     | 
    
         
             
            			if self.running?
         
     | 
| 
       175 
164 
     | 
    
         
             
            				if self.current?
         
     | 
| 
       176 
165 
     | 
    
         
             
            					if later
         
     | 
| 
       177 
     | 
    
         
            -
            						 
     | 
| 
      
 166 
     | 
    
         
            +
            						Fiber.scheduler.push Stop::Later.new(self)
         
     | 
| 
       178 
167 
     | 
    
         
             
            					else
         
     | 
| 
       179 
168 
     | 
    
         
             
            						raise Stop, "Stopping current task!"
         
     | 
| 
       180 
169 
     | 
    
         
             
            					end
         
     | 
| 
       181 
170 
     | 
    
         
             
            				elsif @fiber&.alive?
         
     | 
| 
       182 
171 
     | 
    
         
             
            					begin
         
     | 
| 
       183 
     | 
    
         
            -
            						@fiber 
     | 
| 
      
 172 
     | 
    
         
            +
            						Fiber.scheduler.raise(@fiber, Stop)
         
     | 
| 
       184 
173 
     | 
    
         
             
            					rescue FiberError
         
     | 
| 
       185 
     | 
    
         
            -
            						 
     | 
| 
      
 174 
     | 
    
         
            +
            						Fiber.scheduler.push Stop::Later.new(self)
         
     | 
| 
       186 
175 
     | 
    
         
             
            					end
         
     | 
| 
       187 
176 
     | 
    
         
             
            				end
         
     | 
| 
       188 
177 
     | 
    
         
             
            			else
         
     | 
| 
         @@ -191,50 +180,15 @@ module Async 
     | 
|
| 
       191 
180 
     | 
    
         
             
            			end
         
     | 
| 
       192 
181 
     | 
    
         
             
            		end
         
     | 
| 
       193 
182 
     | 
    
         | 
| 
       194 
     | 
    
         
            -
            		# Defer the handling of stop. During the execution of the given block, if a stop is requested, it will be deferred until the block exits. This is useful for ensuring graceful shutdown of servers and other long-running tasks. You should wrap the response handling code in a defer_stop block to ensure that the task is stopped when the response is complete but not before.
         
     | 
| 
       195 
     | 
    
         
            -
            		#
         
     | 
| 
       196 
     | 
    
         
            -
            		# You can nest calls to defer_stop, but the stop will only be deferred until the outermost block exits.
         
     | 
| 
       197 
     | 
    
         
            -
            		#
         
     | 
| 
       198 
     | 
    
         
            -
            		# If stop is invoked a second time, it will be immediately executed.
         
     | 
| 
       199 
     | 
    
         
            -
            		#
         
     | 
| 
       200 
     | 
    
         
            -
            		# @yields {} The block of code to execute.
         
     | 
| 
       201 
     | 
    
         
            -
            		def defer_stop
         
     | 
| 
       202 
     | 
    
         
            -
            			# Tri-state variable for controlling stop:
         
     | 
| 
       203 
     | 
    
         
            -
            			# - nil: defer_stop has not been called.
         
     | 
| 
       204 
     | 
    
         
            -
            			# - false: defer_stop has been called and we are not stopping.
         
     | 
| 
       205 
     | 
    
         
            -
            			# - true: defer_stop has been called and we will stop when exiting the block.
         
     | 
| 
       206 
     | 
    
         
            -
            			if @defer_stop.nil?
         
     | 
| 
       207 
     | 
    
         
            -
            				# If we are not deferring stop already, we can defer it now:
         
     | 
| 
       208 
     | 
    
         
            -
            				@defer_stop = false
         
     | 
| 
       209 
     | 
    
         
            -
            				
         
     | 
| 
       210 
     | 
    
         
            -
            				begin
         
     | 
| 
       211 
     | 
    
         
            -
            					yield
         
     | 
| 
       212 
     | 
    
         
            -
            				rescue Stop
         
     | 
| 
       213 
     | 
    
         
            -
            					# If we are exiting due to a stop, we shouldn't try to invoke stop again:
         
     | 
| 
       214 
     | 
    
         
            -
            					@defer_stop = nil
         
     | 
| 
       215 
     | 
    
         
            -
            					raise
         
     | 
| 
       216 
     | 
    
         
            -
            				ensure
         
     | 
| 
       217 
     | 
    
         
            -
            					# If we were asked to stop, we should do so now:
         
     | 
| 
       218 
     | 
    
         
            -
            					if @defer_stop
         
     | 
| 
       219 
     | 
    
         
            -
            						@defer_stop = nil
         
     | 
| 
       220 
     | 
    
         
            -
            						self.stop
         
     | 
| 
       221 
     | 
    
         
            -
            					end
         
     | 
| 
       222 
     | 
    
         
            -
            				end
         
     | 
| 
       223 
     | 
    
         
            -
            			else
         
     | 
| 
       224 
     | 
    
         
            -
            				# If we are deferring stop already, entering it again is a no-op.
         
     | 
| 
       225 
     | 
    
         
            -
            				yield
         
     | 
| 
       226 
     | 
    
         
            -
            			end
         
     | 
| 
       227 
     | 
    
         
            -
            		end
         
     | 
| 
       228 
     | 
    
         
            -
            		
         
     | 
| 
       229 
183 
     | 
    
         
             
            		# Lookup the {Task} for the current fiber. Raise `RuntimeError` if none is available.
         
     | 
| 
       230 
     | 
    
         
            -
            		# @ 
     | 
| 
       231 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 184 
     | 
    
         
            +
            		# @returns [Task]
         
     | 
| 
      
 185 
     | 
    
         
            +
            		# @raises[RuntimeError] If task was not {set!} for the current fiber.
         
     | 
| 
       232 
186 
     | 
    
         
             
            		def self.current
         
     | 
| 
       233 
187 
     | 
    
         
             
            			Thread.current[:async_task] or raise RuntimeError, "No async task available!"
         
     | 
| 
       234 
188 
     | 
    
         
             
            		end
         
     | 
| 
       235 
189 
     | 
    
         | 
| 
       236 
190 
     | 
    
         
             
            		# Check if there is a task defined for the current fiber.
         
     | 
| 
       237 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 191 
     | 
    
         
            +
            		# @returns [Task | Nil]
         
     | 
| 
       238 
192 
     | 
    
         
             
            		def self.current?
         
     | 
| 
       239 
193 
     | 
    
         
             
            			Thread.current[:async_task]
         
     | 
| 
       240 
194 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -244,13 +198,13 @@ module Async 
     | 
|
| 
       244 
198 
     | 
    
         
             
            		end
         
     | 
| 
       245 
199 
     | 
    
         | 
| 
       246 
200 
     | 
    
         
             
            		# Check if the task is running.
         
     | 
| 
       247 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 201 
     | 
    
         
            +
            		# @returns [Boolean]
         
     | 
| 
       248 
202 
     | 
    
         
             
            		def running?
         
     | 
| 
       249 
203 
     | 
    
         
             
            			@status == :running
         
     | 
| 
       250 
204 
     | 
    
         
             
            		end
         
     | 
| 
       251 
205 
     | 
    
         | 
| 
       252 
206 
     | 
    
         
             
            		# Whether we can remove this node from the reactor graph.
         
     | 
| 
       253 
     | 
    
         
            -
            		# @ 
     | 
| 
      
 207 
     | 
    
         
            +
            		# @returns [Boolean]
         
     | 
| 
       254 
208 
     | 
    
         
             
            		def finished?
         
     | 
| 
       255 
209 
     | 
    
         
             
            			super && @status != :running
         
     | 
| 
       256 
210 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -274,35 +228,34 @@ module Async 
     | 
|
| 
       274 
228 
     | 
    
         
             
            		private
         
     | 
| 
       275 
229 
     | 
    
         | 
| 
       276 
230 
     | 
    
         
             
            		# This is a very tricky aspect of tasks to get right. I've modelled it after `Thread` but it's slightly different in that the exception can propagate back up through the reactor. If the user writes code which raises an exception, that exception should always be visible, i.e. cause a failure. If it's not visible, such code fails silently and can be very difficult to debug.
         
     | 
| 
       277 
     | 
    
         
            -
            		 
     | 
| 
      
 231 
     | 
    
         
            +
            		# As an explcit choice, the user can start a task which doesn't propagate exceptions. This only applies to `StandardError` and derived tasks. This allows tasks to internally capture their error state which is raised when invoking `Task#result` similar to how `Thread#join` works. This mode makes {ruby Async::Task} behave more like a promise, and you would need to ensure that someone calls `Task#result` otherwise you might miss important errors.
         
     | 
| 
      
 232 
     | 
    
         
            +
            		def fail!(exception = nil, propagate = true)
         
     | 
| 
       278 
233 
     | 
    
         
             
            			@status = :failed
         
     | 
| 
       279 
234 
     | 
    
         
             
            			@result = exception
         
     | 
| 
       280 
235 
     | 
    
         | 
| 
       281 
     | 
    
         
            -
            			if  
     | 
| 
       282 
     | 
    
         
            -
            				 
     | 
| 
       283 
     | 
    
         
            -
             
     | 
| 
       284 
     | 
    
         
            -
            				 
     | 
| 
       285 
     | 
    
         
            -
             
     | 
| 
       286 
     | 
    
         
            -
             
     | 
| 
       287 
     | 
    
         
            -
            				 
     | 
| 
       288 
     | 
    
         
            -
            					Console.logger.debug(self, exception)
         
     | 
| 
       289 
     | 
    
         
            -
            				end
         
     | 
| 
      
 236 
     | 
    
         
            +
            			if propagate
         
     | 
| 
      
 237 
     | 
    
         
            +
            				raise
         
     | 
| 
      
 238 
     | 
    
         
            +
            			elsif @finished.nil?
         
     | 
| 
      
 239 
     | 
    
         
            +
            				# If no one has called wait, we log this as an error:
         
     | 
| 
      
 240 
     | 
    
         
            +
            				Console.logger.error(self) {$!}
         
     | 
| 
      
 241 
     | 
    
         
            +
            			else
         
     | 
| 
      
 242 
     | 
    
         
            +
            				Console.logger.debug(self) {$!}
         
     | 
| 
       290 
243 
     | 
    
         
             
            			end
         
     | 
| 
       291 
244 
     | 
    
         
             
            		end
         
     | 
| 
       292 
245 
     | 
    
         | 
| 
       293 
246 
     | 
    
         
             
            		def stop!
         
     | 
| 
       294 
     | 
    
         
            -
            			# logger. 
     | 
| 
      
 247 
     | 
    
         
            +
            			# Console.logger.info(self, self.annotation) {"Task was stopped with #{@children&.size.inspect} children!"}
         
     | 
| 
       295 
248 
     | 
    
         
             
            			@status = :stopped
         
     | 
| 
       296 
249 
     | 
    
         | 
| 
       297 
250 
     | 
    
         
             
            			stop_children(true)
         
     | 
| 
       298 
251 
     | 
    
         
             
            		end
         
     | 
| 
       299 
252 
     | 
    
         | 
| 
       300 
     | 
    
         
            -
            		def  
     | 
| 
       301 
     | 
    
         
            -
            			Fiber.new do 
     | 
| 
      
 253 
     | 
    
         
            +
            		def schedule(arguments)
         
     | 
| 
      
 254 
     | 
    
         
            +
            			@fiber = Fiber.new do
         
     | 
| 
       302 
255 
     | 
    
         
             
            				set!
         
     | 
| 
       303 
256 
     | 
    
         | 
| 
       304 
257 
     | 
    
         
             
            				begin
         
     | 
| 
       305 
     | 
    
         
            -
            					@result =  
     | 
| 
      
 258 
     | 
    
         
            +
            					@result = @block.call(self, *arguments)
         
     | 
| 
       306 
259 
     | 
    
         
             
            					@status = :complete
         
     | 
| 
       307 
260 
     | 
    
         
             
            					# Console.logger.debug(self) {"Task was completed with #{@children.size} children!"}
         
     | 
| 
       308 
261 
     | 
    
         
             
            				rescue Stop
         
     | 
| 
         @@ -312,10 +265,12 @@ module Async 
     | 
|
| 
       312 
265 
     | 
    
         
             
            				rescue Exception => exception
         
     | 
| 
       313 
266 
     | 
    
         
             
            					fail!(exception, true)
         
     | 
| 
       314 
267 
     | 
    
         
             
            				ensure
         
     | 
| 
       315 
     | 
    
         
            -
            					# Console.logger. 
     | 
| 
      
 268 
     | 
    
         
            +
            					# Console.logger.info(self) {"Task ensure $! = #{$!} with #{@children&.size.inspect} children!"}
         
     | 
| 
       316 
269 
     | 
    
         
             
            					finish!
         
     | 
| 
       317 
270 
     | 
    
         
             
            				end
         
     | 
| 
       318 
271 
     | 
    
         
             
            			end
         
     | 
| 
      
 272 
     | 
    
         
            +
            			
         
     | 
| 
      
 273 
     | 
    
         
            +
            			self.root.resume(@fiber)
         
     | 
| 
       319 
274 
     | 
    
         
             
            		end
         
     | 
| 
       320 
275 
     | 
    
         | 
| 
       321 
276 
     | 
    
         
             
            		# Finish the current task, and all bound bound IO objects.
         
     | 
| 
         @@ -336,7 +291,6 @@ module Async 
     | 
|
| 
       336 
291 
     | 
    
         
             
            		def set!
         
     | 
| 
       337 
292 
     | 
    
         
             
            			# This is actually fiber-local:
         
     | 
| 
       338 
293 
     | 
    
         
             
            			Thread.current[:async_task] = self
         
     | 
| 
       339 
     | 
    
         
            -
            			Console.logger = @logger if @logger
         
     | 
| 
       340 
294 
     | 
    
         
             
            		end
         
     | 
| 
       341 
295 
     | 
    
         
             
            	end
         
     | 
| 
       342 
296 
     | 
    
         
             
            end
         
     | 
    
        data/lib/async/version.rb
    CHANGED
    
    
    
        data/lib/async/wrapper.rb
    CHANGED
    
    | 
         @@ -20,220 +20,60 @@ 
     | 
|
| 
       20 
20 
     | 
    
         
             
            # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         
     | 
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
            require 'nio'
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
23 
     | 
    
         
             
            module Async
         
     | 
| 
       26 
24 
     | 
    
         
             
            	# Represents an asynchronous IO within a reactor.
         
     | 
| 
      
 25 
     | 
    
         
            +
            	# @deprecated With no replacement. Prefer native interfaces.
         
     | 
| 
       27 
26 
     | 
    
         
             
            	class Wrapper
         
     | 
| 
      
 27 
     | 
    
         
            +
            		# An exception that occurs when the asynchronous operation was cancelled.
         
     | 
| 
       28 
28 
     | 
    
         
             
            		class Cancelled < StandardError
         
     | 
| 
       29 
     | 
    
         
            -
            			class From
         
     | 
| 
       30 
     | 
    
         
            -
            				def initialize
         
     | 
| 
       31 
     | 
    
         
            -
            					@backtrace = caller[5..-1]
         
     | 
| 
       32 
     | 
    
         
            -
            				end
         
     | 
| 
       33 
     | 
    
         
            -
            				
         
     | 
| 
       34 
     | 
    
         
            -
            				attr :backtrace
         
     | 
| 
       35 
     | 
    
         
            -
            				
         
     | 
| 
       36 
     | 
    
         
            -
            				def cause
         
     | 
| 
       37 
     | 
    
         
            -
            					nil
         
     | 
| 
       38 
     | 
    
         
            -
            				end
         
     | 
| 
       39 
     | 
    
         
            -
            				
         
     | 
| 
       40 
     | 
    
         
            -
            				def message
         
     | 
| 
       41 
     | 
    
         
            -
            					"Cancelled"
         
     | 
| 
       42 
     | 
    
         
            -
            				end
         
     | 
| 
       43 
     | 
    
         
            -
            			end
         
     | 
| 
       44 
     | 
    
         
            -
            			
         
     | 
| 
       45 
     | 
    
         
            -
            			def initialize
         
     | 
| 
       46 
     | 
    
         
            -
            				super "The operation has been cancelled!"
         
     | 
| 
       47 
     | 
    
         
            -
            				
         
     | 
| 
       48 
     | 
    
         
            -
            				@cause = From.new
         
     | 
| 
       49 
     | 
    
         
            -
            			end
         
     | 
| 
       50 
     | 
    
         
            -
            			
         
     | 
| 
       51 
     | 
    
         
            -
            			attr :cause
         
     | 
| 
       52 
29 
     | 
    
         
             
            		end
         
     | 
| 
       53 
30 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
            		#  
     | 
| 
       55 
     | 
    
         
            -
            		 
     | 
| 
       56 
     | 
    
         
            -
            			def initialize
         
     | 
| 
       57 
     | 
    
         
            -
            				super "A fiber is already waiting!"
         
     | 
| 
       58 
     | 
    
         
            -
            			end
         
     | 
| 
       59 
     | 
    
         
            -
            		end
         
     | 
| 
       60 
     | 
    
         
            -
            		
         
     | 
| 
       61 
     | 
    
         
            -
            		# @param io the native object to wrap.
         
     | 
| 
       62 
     | 
    
         
            -
            		# @param reactor [Reactor] the reactor that is managing this wrapper, or not specified, it's looked up by way of {Task.current}.
         
     | 
| 
      
 31 
     | 
    
         
            +
            		# @parameter io the native object to wrap.
         
     | 
| 
      
 32 
     | 
    
         
            +
            		# @parameter reactor [Reactor] the reactor that is managing this wrapper, or not specified, it's looked up by way of {Task.current}.
         
     | 
| 
       63 
33 
     | 
    
         
             
            		def initialize(io, reactor = nil)
         
     | 
| 
       64 
34 
     | 
    
         
             
            			@io = io
         
     | 
| 
       65 
     | 
    
         
            -
            			
         
     | 
| 
       66 
35 
     | 
    
         
             
            			@reactor = reactor
         
     | 
| 
       67 
     | 
    
         
            -
            			@monitor = nil
         
     | 
| 
       68 
36 
     | 
    
         | 
| 
       69 
     | 
    
         
            -
            			@ 
     | 
| 
       70 
     | 
    
         
            -
            			@writable = nil
         
     | 
| 
       71 
     | 
    
         
            -
            			@any = nil
         
     | 
| 
      
 37 
     | 
    
         
            +
            			@timeout = nil
         
     | 
| 
       72 
38 
     | 
    
         
             
            		end
         
     | 
| 
       73 
39 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
            		 
     | 
| 
       75 
     | 
    
         
            -
            			self.class.new(@io.dup, @reactor)
         
     | 
| 
       76 
     | 
    
         
            -
            		end
         
     | 
| 
      
 40 
     | 
    
         
            +
            		attr_accessor :reactor
         
     | 
| 
       77 
41 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
            		def  
     | 
| 
       79 
     | 
    
         
            -
            			 
     | 
| 
       80 
     | 
    
         
            -
            			return unless @monitor
         
     | 
| 
       81 
     | 
    
         
            -
            			
         
     | 
| 
       82 
     | 
    
         
            -
            			readiness = @monitor.readiness
         
     | 
| 
       83 
     | 
    
         
            -
            			
         
     | 
| 
       84 
     | 
    
         
            -
            			if @readable and (readiness == :r or readiness == :rw)
         
     | 
| 
       85 
     | 
    
         
            -
            				@readable.resume(*arguments)
         
     | 
| 
       86 
     | 
    
         
            -
            			end
         
     | 
| 
       87 
     | 
    
         
            -
            			
         
     | 
| 
       88 
     | 
    
         
            -
            			if @writable and (readiness == :w or readiness == :rw)
         
     | 
| 
       89 
     | 
    
         
            -
            				@writable.resume(*arguments)
         
     | 
| 
       90 
     | 
    
         
            -
            			end
         
     | 
| 
       91 
     | 
    
         
            -
            			
         
     | 
| 
       92 
     | 
    
         
            -
            			if @any
         
     | 
| 
       93 
     | 
    
         
            -
            				@any.resume(*arguments)
         
     | 
| 
       94 
     | 
    
         
            -
            			end
         
     | 
| 
      
 42 
     | 
    
         
            +
            		def dup
         
     | 
| 
      
 43 
     | 
    
         
            +
            			self.class.new(@io.dup)
         
     | 
| 
       95 
44 
     | 
    
         
             
            		end
         
     | 
| 
       96 
45 
     | 
    
         | 
| 
       97 
46 
     | 
    
         
             
            		# The underlying native `io`.
         
     | 
| 
       98 
47 
     | 
    
         
             
            		attr :io
         
     | 
| 
       99 
48 
     | 
    
         | 
| 
       100 
     | 
    
         
            -
            		#  
     | 
| 
       101 
     | 
    
         
            -
            		 
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
            		# The monitor for this wrapper, if any.
         
     | 
| 
       104 
     | 
    
         
            -
            		attr :monitor
         
     | 
| 
       105 
     | 
    
         
            -
            		
         
     | 
| 
       106 
     | 
    
         
            -
            		# Bind this wrapper to a different reactor. Assign nil to convert to an unbound wrapper (can be used from any reactor/task but with slightly increased overhead.)
         
     | 
| 
       107 
     | 
    
         
            -
            		# Binding to a reactor is purely a performance consideration. Generally, I don't like APIs that exist only due to optimisations. This is borderline, so consider this functionality semi-private.
         
     | 
| 
       108 
     | 
    
         
            -
            		def reactor= reactor
         
     | 
| 
       109 
     | 
    
         
            -
            			return if @reactor.equal?(reactor)
         
     | 
| 
       110 
     | 
    
         
            -
            			
         
     | 
| 
       111 
     | 
    
         
            -
            			cancel_monitor
         
     | 
| 
       112 
     | 
    
         
            -
            			
         
     | 
| 
       113 
     | 
    
         
            -
            			@reactor = reactor
         
     | 
| 
      
 49 
     | 
    
         
            +
            		# Wait for the io to become readable.
         
     | 
| 
      
 50 
     | 
    
         
            +
            		def wait_readable(timeout = @timeout)
         
     | 
| 
      
 51 
     | 
    
         
            +
            			@io.to_io.wait_readable(timeout) or raise TimeoutError
         
     | 
| 
       114 
52 
     | 
    
         
             
            		end
         
     | 
| 
       115 
53 
     | 
    
         | 
| 
       116 
     | 
    
         
            -
            		# Wait for the io to become  
     | 
| 
       117 
     | 
    
         
            -
            		def  
     | 
| 
       118 
     | 
    
         
            -
            			 
     | 
| 
       119 
     | 
    
         
            -
            			
         
     | 
| 
       120 
     | 
    
         
            -
            			self.reactor = Task.current.reactor
         
     | 
| 
       121 
     | 
    
         
            -
            			
         
     | 
| 
       122 
     | 
    
         
            -
            			begin
         
     | 
| 
       123 
     | 
    
         
            -
            				@readable = Fiber.current
         
     | 
| 
       124 
     | 
    
         
            -
            				wait_for(timeout)
         
     | 
| 
       125 
     | 
    
         
            -
            			ensure
         
     | 
| 
       126 
     | 
    
         
            -
            				@readable = nil
         
     | 
| 
       127 
     | 
    
         
            -
            				@monitor.interests = interests if @monitor
         
     | 
| 
       128 
     | 
    
         
            -
            			end
         
     | 
| 
      
 54 
     | 
    
         
            +
            		# Wait for the io to become writable.
         
     | 
| 
      
 55 
     | 
    
         
            +
            		def wait_priority(timeout = @timeout)
         
     | 
| 
      
 56 
     | 
    
         
            +
            			@io.to_io.wait_priority(timeout) or raise TimeoutError
         
     | 
| 
       129 
57 
     | 
    
         
             
            		end
         
     | 
| 
       130 
58 
     | 
    
         | 
| 
       131 
59 
     | 
    
         
             
            		# Wait for the io to become writable.
         
     | 
| 
       132 
     | 
    
         
            -
            		def wait_writable(timeout =  
     | 
| 
       133 
     | 
    
         
            -
            			 
     | 
| 
       134 
     | 
    
         
            -
            			
         
     | 
| 
       135 
     | 
    
         
            -
            			self.reactor = Task.current.reactor
         
     | 
| 
       136 
     | 
    
         
            -
            			
         
     | 
| 
       137 
     | 
    
         
            -
            			begin
         
     | 
| 
       138 
     | 
    
         
            -
            				@writable = Fiber.current
         
     | 
| 
       139 
     | 
    
         
            -
            				wait_for(timeout)
         
     | 
| 
       140 
     | 
    
         
            -
            			ensure
         
     | 
| 
       141 
     | 
    
         
            -
            				@writable = nil
         
     | 
| 
       142 
     | 
    
         
            -
            				@monitor.interests = interests if @monitor
         
     | 
| 
       143 
     | 
    
         
            -
            			end
         
     | 
| 
      
 60 
     | 
    
         
            +
            		def wait_writable(timeout = @timeout)
         
     | 
| 
      
 61 
     | 
    
         
            +
            			@io.to_io.wait_writable(timeout) or raise TimeoutError
         
     | 
| 
       144 
62 
     | 
    
         
             
            		end
         
     | 
| 
       145 
63 
     | 
    
         | 
| 
       146 
64 
     | 
    
         
             
            		# Wait fo the io to become either readable or writable.
         
     | 
| 
       147 
     | 
    
         
            -
            		# @ 
     | 
| 
       148 
     | 
    
         
            -
            		def wait_any(timeout =  
     | 
| 
       149 
     | 
    
         
            -
            			 
     | 
| 
       150 
     | 
    
         
            -
            			
         
     | 
| 
       151 
     | 
    
         
            -
            			self.reactor = Task.current.reactor
         
     | 
| 
       152 
     | 
    
         
            -
            			
         
     | 
| 
       153 
     | 
    
         
            -
            			begin
         
     | 
| 
       154 
     | 
    
         
            -
            				@any = Fiber.current
         
     | 
| 
       155 
     | 
    
         
            -
            				wait_for(timeout)
         
     | 
| 
       156 
     | 
    
         
            -
            			ensure
         
     | 
| 
       157 
     | 
    
         
            -
            				@any = nil
         
     | 
| 
       158 
     | 
    
         
            -
            				@monitor.interests = interests if @monitor
         
     | 
| 
       159 
     | 
    
         
            -
            			end
         
     | 
| 
      
 65 
     | 
    
         
            +
            		# @parameter duration [Float] timeout after the given duration if not `nil`.
         
     | 
| 
      
 66 
     | 
    
         
            +
            		def wait_any(timeout = @timeout)
         
     | 
| 
      
 67 
     | 
    
         
            +
            			@io.wait_any(timeout) or raise TimeoutError
         
     | 
| 
       160 
68 
     | 
    
         
             
            		end
         
     | 
| 
       161 
69 
     | 
    
         | 
| 
       162 
70 
     | 
    
         
             
            		# Close the io and monitor.
         
     | 
| 
       163 
71 
     | 
    
         
             
            		def close
         
     | 
| 
       164 
     | 
    
         
            -
            			cancel_monitor
         
     | 
| 
       165 
     | 
    
         
            -
            			
         
     | 
| 
       166 
72 
     | 
    
         
             
            			@io.close
         
     | 
| 
       167 
73 
     | 
    
         
             
            		end
         
     | 
| 
       168 
74 
     | 
    
         | 
| 
       169 
75 
     | 
    
         
             
            		def closed?
         
     | 
| 
       170 
76 
     | 
    
         
             
            			@io.closed?
         
     | 
| 
       171 
77 
     | 
    
         
             
            		end
         
     | 
| 
       172 
     | 
    
         
            -
            		
         
     | 
| 
       173 
     | 
    
         
            -
            		private
         
     | 
| 
       174 
     | 
    
         
            -
            		
         
     | 
| 
       175 
     | 
    
         
            -
            		# What an abomination.
         
     | 
| 
       176 
     | 
    
         
            -
            		def interests
         
     | 
| 
       177 
     | 
    
         
            -
            			if @any
         
     | 
| 
       178 
     | 
    
         
            -
            				return :rw
         
     | 
| 
       179 
     | 
    
         
            -
            			elsif @readable
         
     | 
| 
       180 
     | 
    
         
            -
            				if @writable
         
     | 
| 
       181 
     | 
    
         
            -
            					return :rw
         
     | 
| 
       182 
     | 
    
         
            -
            				else
         
     | 
| 
       183 
     | 
    
         
            -
            					return :r
         
     | 
| 
       184 
     | 
    
         
            -
            				end
         
     | 
| 
       185 
     | 
    
         
            -
            			elsif @writable
         
     | 
| 
       186 
     | 
    
         
            -
            				return :w
         
     | 
| 
       187 
     | 
    
         
            -
            			end
         
     | 
| 
       188 
     | 
    
         
            -
            			
         
     | 
| 
       189 
     | 
    
         
            -
            			return nil
         
     | 
| 
       190 
     | 
    
         
            -
            		end
         
     | 
| 
       191 
     | 
    
         
            -
            		
         
     | 
| 
       192 
     | 
    
         
            -
            		def cancel_monitor
         
     | 
| 
       193 
     | 
    
         
            -
            			if @readable
         
     | 
| 
       194 
     | 
    
         
            -
            				readable = @readable
         
     | 
| 
       195 
     | 
    
         
            -
            				@readable = nil
         
     | 
| 
       196 
     | 
    
         
            -
            				
         
     | 
| 
       197 
     | 
    
         
            -
            				readable.resume(Cancelled.new)
         
     | 
| 
       198 
     | 
    
         
            -
            			end
         
     | 
| 
       199 
     | 
    
         
            -
            			
         
     | 
| 
       200 
     | 
    
         
            -
            			if @writable
         
     | 
| 
       201 
     | 
    
         
            -
            				writable = @writable
         
     | 
| 
       202 
     | 
    
         
            -
            				@writable = nil
         
     | 
| 
       203 
     | 
    
         
            -
            				
         
     | 
| 
       204 
     | 
    
         
            -
            				writable.resume(Cancelled.new)
         
     | 
| 
       205 
     | 
    
         
            -
            			end
         
     | 
| 
       206 
     | 
    
         
            -
            			
         
     | 
| 
       207 
     | 
    
         
            -
            			if @any
         
     | 
| 
       208 
     | 
    
         
            -
            				any = @any
         
     | 
| 
       209 
     | 
    
         
            -
            				@any = nil
         
     | 
| 
       210 
     | 
    
         
            -
            				
         
     | 
| 
       211 
     | 
    
         
            -
            				any.resume(Cancelled.new)
         
     | 
| 
       212 
     | 
    
         
            -
            			end
         
     | 
| 
       213 
     | 
    
         
            -
            			
         
     | 
| 
       214 
     | 
    
         
            -
            			if @monitor
         
     | 
| 
       215 
     | 
    
         
            -
            				@monitor.close
         
     | 
| 
       216 
     | 
    
         
            -
            				@monitor = nil
         
     | 
| 
       217 
     | 
    
         
            -
            			end
         
     | 
| 
       218 
     | 
    
         
            -
            		end
         
     | 
| 
       219 
     | 
    
         
            -
            		
         
     | 
| 
       220 
     | 
    
         
            -
            		def wait_for(timeout)
         
     | 
| 
       221 
     | 
    
         
            -
            			if @monitor
         
     | 
| 
       222 
     | 
    
         
            -
            				@monitor.interests = interests
         
     | 
| 
       223 
     | 
    
         
            -
            			else
         
     | 
| 
       224 
     | 
    
         
            -
            				@monitor = @reactor.register(@io, interests, self)
         
     | 
| 
       225 
     | 
    
         
            -
            			end
         
     | 
| 
       226 
     | 
    
         
            -
            			
         
     | 
| 
       227 
     | 
    
         
            -
            			# If the user requested an explicit timeout for this operation:
         
     | 
| 
       228 
     | 
    
         
            -
            			if timeout
         
     | 
| 
       229 
     | 
    
         
            -
            				@reactor.with_timeout(timeout) do
         
     | 
| 
       230 
     | 
    
         
            -
            					Task.yield
         
     | 
| 
       231 
     | 
    
         
            -
            				end
         
     | 
| 
       232 
     | 
    
         
            -
            			else
         
     | 
| 
       233 
     | 
    
         
            -
            				Task.yield
         
     | 
| 
       234 
     | 
    
         
            -
            			end
         
     | 
| 
       235 
     | 
    
         
            -
            			
         
     | 
| 
       236 
     | 
    
         
            -
            			return true
         
     | 
| 
       237 
     | 
    
         
            -
            		end
         
     | 
| 
       238 
78 
     | 
    
         
             
            	end
         
     | 
| 
       239 
79 
     | 
    
         
             
            end
         
     | 
    
        data/lib/async.rb
    CHANGED
    
    | 
         @@ -21,15 +21,10 @@ 
     | 
|
| 
       21 
21 
     | 
    
         
             
            # THE SOFTWARE.
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
            require_relative "async/version"
         
     | 
| 
       24 
     | 
    
         
            -
            require_relative "async/logger"
         
     | 
| 
       25 
24 
     | 
    
         
             
            require_relative "async/reactor"
         
     | 
| 
       26 
25 
     | 
    
         | 
| 
       27 
26 
     | 
    
         
             
            require_relative "kernel/async"
         
     | 
| 
       28 
27 
     | 
    
         
             
            require_relative "kernel/sync"
         
     | 
| 
       29 
28 
     | 
    
         | 
| 
       30 
29 
     | 
    
         
             
            module Async
         
     | 
| 
       31 
     | 
    
         
            -
            	# Invoke `Reactor.run` with all arguments/block.
         
     | 
| 
       32 
     | 
    
         
            -
            	def self.run(*arguments, &block)
         
     | 
| 
       33 
     | 
    
         
            -
            		Reactor.run(*arguments, &block)
         
     | 
| 
       34 
     | 
    
         
            -
            	end
         
     | 
| 
       35 
30 
     | 
    
         
             
            end
         
     |