concurrent-ruby 0.7.0.rc0-x86-solaris-2.11
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 +7 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +166 -0
 - data/ext/concurrent_ruby_ext/atomic_reference.c +78 -0
 - data/ext/concurrent_ruby_ext/atomic_reference.h +12 -0
 - data/ext/concurrent_ruby_ext/extconf.rb +59 -0
 - data/ext/concurrent_ruby_ext/rb_concurrent.c +28 -0
 - data/lib/concurrent.rb +45 -0
 - data/lib/concurrent/actress.rb +221 -0
 - data/lib/concurrent/actress/ad_hoc.rb +20 -0
 - data/lib/concurrent/actress/context.rb +98 -0
 - data/lib/concurrent/actress/core.rb +228 -0
 - data/lib/concurrent/actress/core_delegations.rb +42 -0
 - data/lib/concurrent/actress/envelope.rb +41 -0
 - data/lib/concurrent/actress/errors.rb +14 -0
 - data/lib/concurrent/actress/reference.rb +64 -0
 - data/lib/concurrent/actress/type_check.rb +48 -0
 - data/lib/concurrent/agent.rb +232 -0
 - data/lib/concurrent/async.rb +319 -0
 - data/lib/concurrent/atomic.rb +46 -0
 - data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
 - data/lib/concurrent/atomic/atomic_fixnum.rb +162 -0
 - data/lib/concurrent/atomic/condition.rb +67 -0
 - data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +118 -0
 - data/lib/concurrent/atomic/copy_on_write_observer_set.rb +117 -0
 - data/lib/concurrent/atomic/count_down_latch.rb +116 -0
 - data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
 - data/lib/concurrent/atomic/event.rb +98 -0
 - data/lib/concurrent/atomic/thread_local_var.rb +117 -0
 - data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
 - data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
 - data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
 - data/lib/concurrent/atomic_reference/jruby.rb +8 -0
 - data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
 - data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
 - data/lib/concurrent/atomic_reference/rbx.rb +16 -0
 - data/lib/concurrent/atomic_reference/ruby.rb +16 -0
 - data/lib/concurrent/atomics.rb +10 -0
 - data/lib/concurrent/channel/buffered_channel.rb +85 -0
 - data/lib/concurrent/channel/channel.rb +41 -0
 - data/lib/concurrent/channel/unbuffered_channel.rb +34 -0
 - data/lib/concurrent/channel/waitable_list.rb +40 -0
 - data/lib/concurrent/channels.rb +5 -0
 - data/lib/concurrent/collection/blocking_ring_buffer.rb +71 -0
 - data/lib/concurrent/collection/priority_queue.rb +305 -0
 - data/lib/concurrent/collection/ring_buffer.rb +59 -0
 - data/lib/concurrent/collections.rb +3 -0
 - data/lib/concurrent/configuration.rb +158 -0
 - data/lib/concurrent/dataflow.rb +91 -0
 - data/lib/concurrent/delay.rb +112 -0
 - data/lib/concurrent/dereferenceable.rb +101 -0
 - data/lib/concurrent/errors.rb +30 -0
 - data/lib/concurrent/exchanger.rb +34 -0
 - data/lib/concurrent/executor/cached_thread_pool.rb +44 -0
 - data/lib/concurrent/executor/executor.rb +229 -0
 - data/lib/concurrent/executor/fixed_thread_pool.rb +33 -0
 - data/lib/concurrent/executor/immediate_executor.rb +16 -0
 - data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
 - data/lib/concurrent/executor/java_fixed_thread_pool.rb +33 -0
 - data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
 - data/lib/concurrent/executor/java_thread_pool_executor.rb +187 -0
 - data/lib/concurrent/executor/per_thread_executor.rb +24 -0
 - data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
 - data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +32 -0
 - data/lib/concurrent/executor/ruby_single_thread_executor.rb +73 -0
 - data/lib/concurrent/executor/ruby_thread_pool_executor.rb +286 -0
 - data/lib/concurrent/executor/ruby_thread_pool_worker.rb +72 -0
 - data/lib/concurrent/executor/safe_task_executor.rb +35 -0
 - data/lib/concurrent/executor/serialized_execution.rb +90 -0
 - data/lib/concurrent/executor/single_thread_executor.rb +35 -0
 - data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
 - data/lib/concurrent/executor/timer_set.rb +143 -0
 - data/lib/concurrent/executors.rb +9 -0
 - data/lib/concurrent/future.rb +124 -0
 - data/lib/concurrent/ivar.rb +111 -0
 - data/lib/concurrent/logging.rb +17 -0
 - data/lib/concurrent/mvar.rb +200 -0
 - data/lib/concurrent/obligation.rb +171 -0
 - data/lib/concurrent/observable.rb +40 -0
 - data/lib/concurrent/options_parser.rb +46 -0
 - data/lib/concurrent/promise.rb +169 -0
 - data/lib/concurrent/scheduled_task.rb +78 -0
 - data/lib/concurrent/supervisor.rb +343 -0
 - data/lib/concurrent/timer_task.rb +341 -0
 - data/lib/concurrent/tvar.rb +252 -0
 - data/lib/concurrent/utilities.rb +3 -0
 - data/lib/concurrent/utility/processor_count.rb +150 -0
 - data/lib/concurrent/utility/timeout.rb +35 -0
 - data/lib/concurrent/utility/timer.rb +21 -0
 - data/lib/concurrent/version.rb +3 -0
 - data/lib/concurrent_ruby.rb +1 -0
 - data/lib/concurrent_ruby_ext.so +0 -0
 - data/lib/extension_helper.rb +9 -0
 - metadata +140 -0
 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'concurrent/atomic_reference/concurrent_update_error'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              # Define update methods that delegate to @ref field
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Atomic
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Pass the current value to the given block, replacing it
         
     | 
| 
      
 8 
     | 
    
         
            +
                # with the block's result. May retry if the value changes
         
     | 
| 
      
 9 
     | 
    
         
            +
                # during the block's execution.
         
     | 
| 
      
 10 
     | 
    
         
            +
                def update
         
     | 
| 
      
 11 
     | 
    
         
            +
                  true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value))
         
     | 
| 
      
 12 
     | 
    
         
            +
                  new_value
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def try_update
         
     | 
| 
      
 16 
     | 
    
         
            +
                  old_value = @ref.get
         
     | 
| 
      
 17 
     | 
    
         
            +
                  new_value = yield old_value
         
     | 
| 
      
 18 
     | 
    
         
            +
                  unless @ref.compare_and_set(old_value, new_value)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    if $VERBOSE
         
     | 
| 
      
 20 
     | 
    
         
            +
                      raise ConcurrentUpdateError, "Update failed"
         
     | 
| 
      
 21 
     | 
    
         
            +
                    else
         
     | 
| 
      
 22 
     | 
    
         
            +
                      raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  new_value
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'concurrent/atomic_reference/concurrent_update_error'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              # Define update methods that use direct paths
         
     | 
| 
      
 6 
     | 
    
         
            +
              module AtomicDirectUpdate
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Pass the current value to the given block, replacing it
         
     | 
| 
      
 8 
     | 
    
         
            +
                # with the block's result. May retry if the value changes
         
     | 
| 
      
 9 
     | 
    
         
            +
                # during the block's execution.
         
     | 
| 
      
 10 
     | 
    
         
            +
                def update
         
     | 
| 
      
 11 
     | 
    
         
            +
                  true until compare_and_set(old_value = get, new_value = yield(old_value))
         
     | 
| 
      
 12 
     | 
    
         
            +
                  new_value
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def try_update
         
     | 
| 
      
 16 
     | 
    
         
            +
                  old_value = get
         
     | 
| 
      
 17 
     | 
    
         
            +
                  new_value = yield old_value
         
     | 
| 
      
 18 
     | 
    
         
            +
                  unless compare_and_set(old_value, new_value)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    if $VERBOSE
         
     | 
| 
      
 20 
     | 
    
         
            +
                      raise ConcurrentUpdateError, "Update failed"
         
     | 
| 
      
 21 
     | 
    
         
            +
                    else
         
     | 
| 
      
 22 
     | 
    
         
            +
                      raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  new_value
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,47 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'thread'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'concurrent/atomic_reference/direct_update'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'concurrent/atomic_reference/numeric_cas_wrapper'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              # Portable/generic (but not very memory or scheduling-efficient) fallback
         
     | 
| 
      
 8 
     | 
    
         
            +
              class MutexAtomic #:nodoc: all
         
     | 
| 
      
 9 
     | 
    
         
            +
                include Concurrent::AtomicDirectUpdate
         
     | 
| 
      
 10 
     | 
    
         
            +
                include Concurrent::AtomicNumericCompareAndSetWrapper
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def initialize(value = nil)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @mutex = Mutex.new
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @value = value
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def get
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @mutex.synchronize { @value }
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
                alias value get
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def set(new_value)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @mutex.synchronize { @value = new_value }
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
                alias value= set
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def get_and_set(new_value)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 29 
     | 
    
         
            +
                    old_value = @value
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @value = new_value
         
     | 
| 
      
 31 
     | 
    
         
            +
                    old_value
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
                alias swap get_and_set
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def _compare_and_set(old_value, new_value)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  return false unless @mutex.try_lock
         
     | 
| 
      
 38 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 39 
     | 
    
         
            +
                    return false unless @value.equal? old_value
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @value = new_value
         
     | 
| 
      
 41 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 42 
     | 
    
         
            +
                    @mutex.unlock
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                  true
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              module AtomicNumericCompareAndSetWrapper
         
     | 
| 
      
 4 
     | 
    
         
            +
                #alias _compare_and_set compare_and_set
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def compare_and_set(expected, new)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  if expected.kind_of? Numeric
         
     | 
| 
      
 8 
     | 
    
         
            +
                    while true
         
     | 
| 
      
 9 
     | 
    
         
            +
                      old = get
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                      return false unless old.kind_of? Numeric
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                      return false unless old == expected
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                      result = _compare_and_set(old, new)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      return result if result
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  else
         
     | 
| 
      
 19 
     | 
    
         
            +
                    _compare_and_set(expected, new)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
                alias compare_and_swap compare_and_set
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'concurrent/atomic_reference/direct_update'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'concurrent/atomic_reference/numeric_cas_wrapper'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              # extend Rubinius's version adding aliases and numeric logic
         
     | 
| 
      
 7 
     | 
    
         
            +
              class RbxAtomic < Rubinius::AtomicReference
         
     | 
| 
      
 8 
     | 
    
         
            +
                alias _compare_and_set compare_and_set
         
     | 
| 
      
 9 
     | 
    
         
            +
                include Concurrent::AtomicDirectUpdate
         
     | 
| 
      
 10 
     | 
    
         
            +
                include Concurrent::AtomicNumericCompareAndSetWrapper
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                alias value get
         
     | 
| 
      
 13 
     | 
    
         
            +
                alias value= set
         
     | 
| 
      
 14 
     | 
    
         
            +
                alias swap get_and_set
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            begin
         
     | 
| 
      
 2 
     | 
    
         
            +
              require 'concurrent_ruby_ext'
         
     | 
| 
      
 3 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 4 
     | 
    
         
            +
              # may be a Windows cross-compiled native gem
         
     | 
| 
      
 5 
     | 
    
         
            +
              require "#{RUBY_VERSION[0..2]}/concurrent_ruby_ext"
         
     | 
| 
      
 6 
     | 
    
         
            +
            end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            require 'concurrent/atomic_reference/direct_update'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'concurrent/atomic_reference/numeric_cas_wrapper'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 12 
     | 
    
         
            +
              class CAtomic
         
     | 
| 
      
 13 
     | 
    
         
            +
                include Concurrent::AtomicDirectUpdate
         
     | 
| 
      
 14 
     | 
    
         
            +
                include Concurrent::AtomicNumericCompareAndSetWrapper
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'concurrent/atomic'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'concurrent/atomic/atomic_boolean'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'concurrent/atomic/atomic_fixnum'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'concurrent/atomic/condition'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'concurrent/atomic/copy_on_notify_observer_set'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'concurrent/atomic/copy_on_write_observer_set'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'concurrent/atomic/cyclic_barrier'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'concurrent/atomic/count_down_latch'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'concurrent/atomic/event'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'concurrent/atomic/thread_local_var'
         
     | 
| 
         @@ -0,0 +1,85 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'concurrent/atomic/condition'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'waitable_list'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 6 
     | 
    
         
            +
              class BufferedChannel
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize(size)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @mutex = Mutex.new
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @condition = Condition.new
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @buffer_condition = Condition.new
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  @probe_set = WaitableList.new
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @buffer = RingBuffer.new(size)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def probe_set_size
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @probe_set.size
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def buffer_queue_size
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @mutex.synchronize { @buffer.count }
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def push(value)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  until set_probe_or_push_into_buffer(value)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def pop
         
     | 
| 
      
 31 
     | 
    
         
            +
                  probe = Channel::Probe.new
         
     | 
| 
      
 32 
     | 
    
         
            +
                  select(probe)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  probe.value
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def select(probe)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    if @buffer.empty?
         
     | 
| 
      
 40 
     | 
    
         
            +
                      @probe_set.put(probe)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      true
         
     | 
| 
      
 42 
     | 
    
         
            +
                    else
         
     | 
| 
      
 43 
     | 
    
         
            +
                      shift_buffer if probe.set_unless_assigned(peek_buffer, self)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                def remove_probe(probe)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  @probe_set.delete(probe)
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                private
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def push_into_buffer(value)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  @buffer_condition.wait(@mutex) while @buffer.full?
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @buffer.offer value
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @buffer_condition.broadcast
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def peek_buffer
         
     | 
| 
      
 62 
     | 
    
         
            +
                  @buffer_condition.wait(@mutex) while @buffer.empty?
         
     | 
| 
      
 63 
     | 
    
         
            +
                  @buffer.peek
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                def shift_buffer
         
     | 
| 
      
 67 
     | 
    
         
            +
                  @buffer_condition.wait(@mutex) while @buffer.empty?
         
     | 
| 
      
 68 
     | 
    
         
            +
                  result = @buffer.poll
         
     | 
| 
      
 69 
     | 
    
         
            +
                  @buffer_condition.broadcast
         
     | 
| 
      
 70 
     | 
    
         
            +
                  result
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                def set_probe_or_push_into_buffer(value)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 75 
     | 
    
         
            +
                    if @probe_set.empty?
         
     | 
| 
      
 76 
     | 
    
         
            +
                      push_into_buffer(value)
         
     | 
| 
      
 77 
     | 
    
         
            +
                      true
         
     | 
| 
      
 78 
     | 
    
         
            +
                    else
         
     | 
| 
      
 79 
     | 
    
         
            +
                      @probe_set.take.set_unless_assigned(value, self)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
              end
         
     | 
| 
      
 85 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,41 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'concurrent/ivar'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Channel
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                class Probe < Concurrent::IVar
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize(value = NO_VALUE, opts = {})
         
     | 
| 
      
 9 
     | 
    
         
            +
                    super(value, opts)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def set_unless_assigned(value, channel)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    mutex.synchronize do
         
     | 
| 
      
 14 
     | 
    
         
            +
                      return false if [:fulfilled, :rejected].include? @state
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                      set_state(true, [value, channel], nil)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      event.set
         
     | 
| 
      
 18 
     | 
    
         
            +
                      true
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  alias_method :composite_value, :value
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def value
         
     | 
| 
      
 25 
     | 
    
         
            +
                    composite_value.nil? ? nil : composite_value[0]
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  def channel
         
     | 
| 
      
 29 
     | 
    
         
            +
                    composite_value.nil? ? nil : composite_value[1]
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def self.select(*channels)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  probe = Probe.new
         
     | 
| 
      
 35 
     | 
    
         
            +
                  channels.each { |channel| channel.select(probe) }
         
     | 
| 
      
 36 
     | 
    
         
            +
                  result = probe.composite_value
         
     | 
| 
      
 37 
     | 
    
         
            +
                  channels.each { |channel| channel.remove_probe(probe) }
         
     | 
| 
      
 38 
     | 
    
         
            +
                  result
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'waitable_list'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 4 
     | 
    
         
            +
              class UnbufferedChannel
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @probe_set = WaitableList.new
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def probe_set_size
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @probe_set.size
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def push(value)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  until @probe_set.take.set_unless_assigned(value, self)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def pop
         
     | 
| 
      
 20 
     | 
    
         
            +
                  probe = Channel::Probe.new
         
     | 
| 
      
 21 
     | 
    
         
            +
                  select(probe)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  probe.value
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def select(probe)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @probe_set.put(probe)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def remove_probe(probe)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @probe_set.delete(probe)
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'concurrent/atomic/condition'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 4 
     | 
    
         
            +
              class WaitableList
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @mutex = Mutex.new
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @condition = Condition.new
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  @list = []
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def size
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @mutex.synchronize { @list.size }
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def empty?
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @mutex.synchronize { @list.empty? }
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def put(value)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @list << value
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @condition.signal
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def delete(value)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @mutex.synchronize { @list.delete(value) }
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                def take
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 34 
     | 
    
         
            +
                    @condition.wait(@mutex) while @list.empty?
         
     | 
| 
      
 35 
     | 
    
         
            +
                    @list.shift
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,71 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'concurrent/atomic/condition'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Concurrent
         
     | 
| 
      
 4 
     | 
    
         
            +
              class BlockingRingBuffer
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize(capacity)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @buffer = RingBuffer.new(capacity)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @first = @last = 0
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @count = 0
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @mutex = Mutex.new
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @condition = Condition.new
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                # @return [Integer] the capacity of the buffer
         
     | 
| 
      
 15 
     | 
    
         
            +
                def capacity
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @mutex.synchronize { @buffer.capacity }
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                # @return [Integer] the number of elements currently in the buffer
         
     | 
| 
      
 20 
     | 
    
         
            +
                def count
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @mutex.synchronize { @buffer.count }
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                # @return [Boolean] true if buffer is empty, false otherwise
         
     | 
| 
      
 25 
     | 
    
         
            +
                def empty?
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @mutex.synchronize { @buffer.empty? }
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                # @return [Boolean] true if buffer is full, false otherwise
         
     | 
| 
      
 30 
     | 
    
         
            +
                def full?
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @mutex.synchronize { @buffer.full? }
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                # @param [Object] value the value to be inserted
         
     | 
| 
      
 35 
     | 
    
         
            +
                # @return [Boolean] true if value has been inserted, false otherwise
         
     | 
| 
      
 36 
     | 
    
         
            +
                def put(value)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 38 
     | 
    
         
            +
                    wait_while_full
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @buffer.offer(value)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @condition.signal
         
     | 
| 
      
 41 
     | 
    
         
            +
                    true
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                # @return [Object] the first available value and removes it from the buffer. If buffer is empty it blocks until an element is available
         
     | 
| 
      
 46 
     | 
    
         
            +
                def take
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @mutex.synchronize do
         
     | 
| 
      
 48 
     | 
    
         
            +
                    wait_while_empty
         
     | 
| 
      
 49 
     | 
    
         
            +
                    result = @buffer.poll
         
     | 
| 
      
 50 
     | 
    
         
            +
                    @condition.signal
         
     | 
| 
      
 51 
     | 
    
         
            +
                    result
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                # @return [Object] the first available value and without removing it from the buffer. If buffer is empty returns nil
         
     | 
| 
      
 56 
     | 
    
         
            +
                def peek
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @mutex.synchronize { @buffer.peek }
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                private
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                def wait_while_full
         
     | 
| 
      
 63 
     | 
    
         
            +
                  @condition.wait(@mutex) while @buffer.full?
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                def wait_while_empty
         
     | 
| 
      
 67 
     | 
    
         
            +
                  @condition.wait(@mutex) while @buffer.empty?
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
            end
         
     |