lib/libuv/loop.rb in libuv-0.10.2 vs lib/libuv/loop.rb in libuv-0.10.3

- old
+ new

@@ -3,31 +3,41 @@ module Libuv class Loop include Resource, Assertions + LOOPS = ThreadSafe::Cache.new + + module ClassMethods # Get default loop # # @return [::Libuv::Loop] def default - create(::Libuv::Ext.default_loop) + return current || create(::Libuv::Ext.default_loop) end # Create new Libuv loop # # @return [::Libuv::Loop] def new - create(::Libuv::Ext.loop_new) + return current || create(::Libuv::Ext.loop_new) end # Build a Ruby Libuv loop from an existing loop pointer # # @return [::Libuv::Loop] def create(pointer) allocate.tap { |i| i.send(:initialize, FFI::AutoPointer.new(pointer, ::Libuv::Ext.method(:loop_delete))) } end + + # Checks for the existence of a loop on the current thread + # + # @return [::Libuv::Loop | nil] + def current + LOOPS[Thread.current] + end end extend ClassMethods # Initialize a loop using an FFI::Pointer to a libuv loop @@ -57,10 +67,12 @@ @queue_proc.call end # Create an async call for ending the loop @stop_loop = Async.new @loop do + LOOPS.delete(@reactor_thread) + @reactor_thread = nil @process_queue.close @stop_loop.close @next_tick.close ::Libuv::Ext.stop(@pointer) @@ -73,21 +85,23 @@ # # @param run_type [:UV_RUN_DEFAULT, :UV_RUN_ONCE, :UV_RUN_NOWAIT] # @yieldparam promise [::Libuv::Q::Promise] Yields a promise that can be used for logging unhandled # exceptions on the loop. def run(run_type = :UV_RUN_DEFAULT) - @loop_notify = @loop.defer + if @reactor_thread.nil? + @loop_notify = @loop.defer - begin - @reactor_thread = Thread.current - yield @loop_notify.promise if block_given? - ::Libuv::Ext.run(@pointer, run_type) # This is blocking - ensure - @reactor_thread = nil - @run_queue.clear + begin + @reactor_thread = Thread.current + LOOPS[@reactor_thread] = @loop + yield @loop_notify.promise if block_given? + ::Libuv::Ext.run(@pointer, run_type) # This is blocking + ensure + @reactor_thread = nil + @run_queue.clear + end end - @loop end # Creates a deferred result object for where the result of an operation may only be returned @@ -137,11 +151,11 @@ # @return nil def update_time ::Libuv::Ext.update_time(@pointer) end - # Get current time in microseconds + # Get current time in milliseconds # # @return [Fixnum] def now ::Libuv::Ext.now(@pointer) end @@ -202,19 +216,19 @@ end # Get a new Prepare handle # # @return [::Libuv::Prepare] - def prepare - Prepare.new(@loop) + def prepare(callback = nil, &blk) + Prepare.new(@loop, callback || blk) end # Get a new Check handle # # @return [::Libuv::Check] - def check - Check.new(@loop) + def check(callback = nil, &blk) + Check.new(@loop, callback || blk) end # Get a new Idle handle # # @param callback [Proc] the callback to be called on idle trigger @@ -291,11 +305,11 @@ # @raise [ArgumentError] if block is not given def schedule(callback = nil, &block) callback ||= block assert_block(callback) - if @reactor_thread == Thread.current + if reactor_thread? block.call else @run_queue << callback @process_queue.call end @@ -308,11 +322,11 @@ def next_tick(callback = nil, &block) callback ||= block assert_block(callback) @run_queue << callback - if @reactor_thread == Thread.current + if reactor_thread? # Create a next tick timer if not @next_tick_scheduled @next_tick.start(0) @next_tick_scheduled = true end @@ -331,8 +345,29 @@ end # Closes handles opened by the loop class and completes the current loop iteration (thread safe) def stop @stop_loop.call + end + + # True if the calling thread is the same thread as the reactor. + # + # @return [Boolean] + def reactor_thread? + @reactor_thread == Thread.current + end + + # Exposed to allow joining on the thread, when run in a multithreaded environment. Performing other actions on the thread has undefined semantics (read: a dangerous endevor). + # + # @return [Thread] + def reactor_thread + @reactor_thread + end + + # Tells you whether the Libuv reactor loop is currently running. + # + # @return [Boolean] + def reactor_running? + !@reactor_thread.nil? end end end