concurrent-ruby 0.7.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/LICENSE.txt +21 -0
  2. data/README.md +217 -0
  3. data/lib/concurrent.rb +45 -0
  4. data/lib/concurrent/actor.rb +104 -0
  5. data/lib/concurrent/actor/behaviour.rb +70 -0
  6. data/lib/concurrent/actor/behaviour/abstract.rb +48 -0
  7. data/lib/concurrent/actor/behaviour/awaits.rb +21 -0
  8. data/lib/concurrent/actor/behaviour/buffer.rb +54 -0
  9. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +12 -0
  10. data/lib/concurrent/actor/behaviour/executes_context.rb +18 -0
  11. data/lib/concurrent/actor/behaviour/linking.rb +42 -0
  12. data/lib/concurrent/actor/behaviour/pausing.rb +77 -0
  13. data/lib/concurrent/actor/behaviour/removes_child.rb +16 -0
  14. data/lib/concurrent/actor/behaviour/sets_results.rb +36 -0
  15. data/lib/concurrent/actor/behaviour/supervised.rb +58 -0
  16. data/lib/concurrent/actor/behaviour/supervising.rb +34 -0
  17. data/lib/concurrent/actor/behaviour/terminates_children.rb +13 -0
  18. data/lib/concurrent/actor/behaviour/termination.rb +54 -0
  19. data/lib/concurrent/actor/context.rb +153 -0
  20. data/lib/concurrent/actor/core.rb +213 -0
  21. data/lib/concurrent/actor/default_dead_letter_handler.rb +9 -0
  22. data/lib/concurrent/actor/envelope.rb +41 -0
  23. data/lib/concurrent/actor/errors.rb +27 -0
  24. data/lib/concurrent/actor/internal_delegations.rb +49 -0
  25. data/lib/concurrent/actor/public_delegations.rb +40 -0
  26. data/lib/concurrent/actor/reference.rb +81 -0
  27. data/lib/concurrent/actor/root.rb +37 -0
  28. data/lib/concurrent/actor/type_check.rb +48 -0
  29. data/lib/concurrent/actor/utils.rb +10 -0
  30. data/lib/concurrent/actor/utils/ad_hoc.rb +21 -0
  31. data/lib/concurrent/actor/utils/balancer.rb +40 -0
  32. data/lib/concurrent/actor/utils/broadcast.rb +52 -0
  33. data/lib/concurrent/actor/utils/pool.rb +59 -0
  34. data/lib/concurrent/actress.rb +3 -0
  35. data/lib/concurrent/agent.rb +230 -0
  36. data/lib/concurrent/async.rb +284 -0
  37. data/lib/concurrent/atomic.rb +91 -0
  38. data/lib/concurrent/atomic/atomic_boolean.rb +202 -0
  39. data/lib/concurrent/atomic/atomic_fixnum.rb +203 -0
  40. data/lib/concurrent/atomic/condition.rb +67 -0
  41. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +118 -0
  42. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +117 -0
  43. data/lib/concurrent/atomic/count_down_latch.rb +116 -0
  44. data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
  45. data/lib/concurrent/atomic/event.rb +98 -0
  46. data/lib/concurrent/atomic/synchronization.rb +51 -0
  47. data/lib/concurrent/atomic/thread_local_var.rb +82 -0
  48. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +8 -0
  49. data/lib/concurrent/atomic_reference/direct_update.rb +50 -0
  50. data/lib/concurrent/atomic_reference/jruby.rb +14 -0
  51. data/lib/concurrent/atomic_reference/mutex_atomic.rb +77 -0
  52. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +25 -0
  53. data/lib/concurrent/atomic_reference/rbx.rb +19 -0
  54. data/lib/concurrent/atomic_reference/ruby.rb +37 -0
  55. data/lib/concurrent/atomics.rb +11 -0
  56. data/lib/concurrent/channel/buffered_channel.rb +85 -0
  57. data/lib/concurrent/channel/channel.rb +41 -0
  58. data/lib/concurrent/channel/unbuffered_channel.rb +35 -0
  59. data/lib/concurrent/channel/waitable_list.rb +40 -0
  60. data/lib/concurrent/channels.rb +5 -0
  61. data/lib/concurrent/collection/blocking_ring_buffer.rb +71 -0
  62. data/lib/concurrent/collection/priority_queue.rb +305 -0
  63. data/lib/concurrent/collection/ring_buffer.rb +59 -0
  64. data/lib/concurrent/collections.rb +3 -0
  65. data/lib/concurrent/configuration.rb +161 -0
  66. data/lib/concurrent/dataflow.rb +108 -0
  67. data/lib/concurrent/delay.rb +104 -0
  68. data/lib/concurrent/dereferenceable.rb +101 -0
  69. data/lib/concurrent/errors.rb +30 -0
  70. data/lib/concurrent/exchanger.rb +34 -0
  71. data/lib/concurrent/executor/cached_thread_pool.rb +44 -0
  72. data/lib/concurrent/executor/executor.rb +282 -0
  73. data/lib/concurrent/executor/fixed_thread_pool.rb +33 -0
  74. data/lib/concurrent/executor/immediate_executor.rb +65 -0
  75. data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
  76. data/lib/concurrent/executor/java_fixed_thread_pool.rb +41 -0
  77. data/lib/concurrent/executor/java_single_thread_executor.rb +22 -0
  78. data/lib/concurrent/executor/java_thread_pool_executor.rb +180 -0
  79. data/lib/concurrent/executor/per_thread_executor.rb +100 -0
  80. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
  81. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +32 -0
  82. data/lib/concurrent/executor/ruby_single_thread_executor.rb +74 -0
  83. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +288 -0
  84. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +72 -0
  85. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  86. data/lib/concurrent/executor/serialized_execution.rb +126 -0
  87. data/lib/concurrent/executor/single_thread_executor.rb +35 -0
  88. data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
  89. data/lib/concurrent/executor/timer_set.rb +143 -0
  90. data/lib/concurrent/executors.rb +9 -0
  91. data/lib/concurrent/future.rb +125 -0
  92. data/lib/concurrent/ivar.rb +111 -0
  93. data/lib/concurrent/lazy_register.rb +58 -0
  94. data/lib/concurrent/logging.rb +17 -0
  95. data/lib/concurrent/mvar.rb +200 -0
  96. data/lib/concurrent/obligation.rb +171 -0
  97. data/lib/concurrent/observable.rb +40 -0
  98. data/lib/concurrent/options_parser.rb +48 -0
  99. data/lib/concurrent/promise.rb +170 -0
  100. data/lib/concurrent/scheduled_task.rb +79 -0
  101. data/lib/concurrent/timer_task.rb +341 -0
  102. data/lib/concurrent/tvar.rb +248 -0
  103. data/lib/concurrent/utilities.rb +3 -0
  104. data/lib/concurrent/utility/processor_count.rb +152 -0
  105. data/lib/concurrent/utility/timeout.rb +35 -0
  106. data/lib/concurrent/utility/timer.rb +21 -0
  107. data/lib/concurrent/version.rb +3 -0
  108. data/lib/concurrent_ruby.rb +1 -0
  109. data/lib/concurrent_ruby_ext.jar +0 -0
  110. data/lib/concurrent_ruby_ext.so +0 -0
  111. data/lib/extension_helper.rb +28 -0
  112. metadata +163 -0
@@ -0,0 +1,98 @@
1
+ require 'thread'
2
+ require 'concurrent/atomic/condition'
3
+
4
+ module Concurrent
5
+
6
+ # Old school kernel-style event reminiscent of Win32 programming in C++.
7
+ #
8
+ # When an `Event` is created it is in the `unset` state. Threads can choose to
9
+ # `#wait` on the event, blocking until released by another thread. When one
10
+ # thread wants to alert all blocking threads it calls the `#set` method which
11
+ # will then wake up all listeners. Once an `Event` has been set it remains set.
12
+ # New threads calling `#wait` will return immediately. An `Event` may be
13
+ # `#reset` at any time once it has been set.
14
+ #
15
+ # @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682655.aspx
16
+ class Event
17
+
18
+ # Creates a new `Event` in the unset state. Threads calling `#wait` on the
19
+ # `Event` will block.
20
+ def initialize
21
+ @set = false
22
+ @mutex = Mutex.new
23
+ @condition = Condition.new
24
+ end
25
+
26
+ # Is the object in the set state?
27
+ #
28
+ # @return [Boolean] indicating whether or not the `Event` has been set
29
+ def set?
30
+ @mutex.lock
31
+ @set
32
+ ensure
33
+ @mutex.unlock
34
+ end
35
+
36
+ # Trigger the event, setting the state to `set` and releasing all threads
37
+ # waiting on the event. Has no effect if the `Event` has already been set.
38
+ #
39
+ # @return [Boolean] should always return `true`
40
+ def set
41
+ @mutex.lock
42
+ unless @set
43
+ @set = true
44
+ @condition.broadcast
45
+ end
46
+ true
47
+ ensure
48
+ @mutex.unlock
49
+ end
50
+
51
+ def try?
52
+ @mutex.lock
53
+
54
+ if @set
55
+ false
56
+ else
57
+ @set = true
58
+ @condition.broadcast
59
+ true
60
+ end
61
+
62
+ ensure
63
+ @mutex.unlock
64
+ end
65
+
66
+ # Reset a previously set event back to the `unset` state.
67
+ # Has no effect if the `Event` has not yet been set.
68
+ #
69
+ # @return [Boolean] should always return `true`
70
+ def reset
71
+ @mutex.lock
72
+ @set = false
73
+ true
74
+ ensure
75
+ @mutex.unlock
76
+ end
77
+
78
+ # Wait a given number of seconds for the `Event` to be set by another
79
+ # thread. Will wait forever when no `timeout` value is given. Returns
80
+ # immediately if the `Event` has already been set.
81
+ #
82
+ # @return [Boolean] true if the `Event` was set before timeout else false
83
+ def wait(timeout = nil)
84
+ @mutex.lock
85
+
86
+ unless @set
87
+ remaining = Condition::Result.new(timeout)
88
+ while !@set && remaining.can_wait?
89
+ remaining = @condition.wait(@mutex, remaining.remaining_time)
90
+ end
91
+ end
92
+
93
+ @set
94
+ ensure
95
+ @mutex.unlock
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,51 @@
1
+ module Concurrent
2
+
3
+ # Safe synchronization under JRuby, prevents reading uninitialized @mutex variable.
4
+ # @note synchronized needs to be called in #initialize for this module to work properly
5
+ # @example usage
6
+ # class AClass
7
+ # include Synchronized
8
+ #
9
+ # def initialize
10
+ # synchronize do
11
+ # # body of the constructor ...
12
+ # end
13
+ # end
14
+ #
15
+ # def a_method
16
+ # synchronize do
17
+ # # body of a_method ...
18
+ # end
19
+ # end
20
+ # end
21
+ module Synchronization
22
+
23
+ engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
24
+
25
+ case engine
26
+ when 'jruby'
27
+ require 'jruby'
28
+
29
+ def synchronize
30
+ JRuby.reference0(self).synchronized { yield }
31
+ end
32
+
33
+ when 'rbx'
34
+
35
+ def synchronize
36
+ Rubinius.lock(self)
37
+ yield
38
+ ensure
39
+ Rubinius.unlock(self)
40
+ end
41
+
42
+ else
43
+
44
+ def synchronize
45
+ @mutex ||= Mutex.new
46
+ @mutex.synchronize { yield }
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,82 @@
1
+ require 'concurrent/atomic'
2
+
3
+ module Concurrent
4
+
5
+ module ThreadLocalRubyStorage
6
+
7
+ def allocate_storage
8
+ @storage = Atomic.new Hash.new
9
+ end
10
+
11
+ def get
12
+ @storage.get[Thread.current]
13
+ end
14
+
15
+ def set(value)
16
+ @storage.update { |s| s.merge Thread.current => value }
17
+ end
18
+
19
+ end
20
+
21
+ module ThreadLocalJavaStorage
22
+
23
+ protected
24
+
25
+ def allocate_storage
26
+ @var = java.lang.ThreadLocal.new
27
+ end
28
+
29
+ def get
30
+ @var.get
31
+ end
32
+
33
+ def set(value)
34
+ @var.set(value)
35
+ end
36
+
37
+ end
38
+
39
+ class AbstractThreadLocalVar
40
+
41
+ NIL_SENTINEL = Object.new
42
+
43
+ def initialize(default = nil)
44
+ @default = default
45
+ allocate_storage
46
+ end
47
+
48
+ def value
49
+ value = get
50
+
51
+ if value.nil?
52
+ @default
53
+ elsif value == NIL_SENTINEL
54
+ nil
55
+ else
56
+ value
57
+ end
58
+ end
59
+
60
+ def value=(value)
61
+ if value.nil?
62
+ stored_value = NIL_SENTINEL
63
+ else
64
+ stored_value = value
65
+ end
66
+
67
+ set stored_value
68
+
69
+ value
70
+ end
71
+
72
+ end
73
+
74
+ class ThreadLocalVar < AbstractThreadLocalVar
75
+ if RUBY_PLATFORM == 'java'
76
+ include ThreadLocalJavaStorage
77
+ else
78
+ include ThreadLocalRubyStorage
79
+ end
80
+ end
81
+
82
+ end
@@ -0,0 +1,8 @@
1
+ module Concurrent
2
+
3
+ # @!macro atomic_reference
4
+ class ConcurrentUpdateError < ThreadError
5
+ # frozen pre-allocated backtrace to speed ConcurrentUpdateError
6
+ CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
7
+ end
8
+ end
@@ -0,0 +1,50 @@
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
+
8
+ # @!macro [attach] atomic_reference_method_update
9
+ #
10
+ # Pass the current value to the given block, replacing it
11
+ # with the block's result. May retry if the value changes
12
+ # during the block's execution.
13
+ #
14
+ # @yield [Object] Calculate a new value for the atomic reference using
15
+ # given (old) value
16
+ # @yieldparam [Object] old_value the starting value of the atomic reference
17
+ #
18
+ # @return [Object] the new value
19
+ def update
20
+ true until compare_and_set(old_value = get, new_value = yield(old_value))
21
+ new_value
22
+ end
23
+
24
+ # @!macro [attach] atomic_reference_method_try_update
25
+ #
26
+ # Pass the current value to the given block, replacing it
27
+ # with the block's result. Raise an exception if the update
28
+ # fails.
29
+ #
30
+ # @yield [Object] Calculate a new value for the atomic reference using
31
+ # given (old) value
32
+ # @yieldparam [Object] old_value the starting value of the atomic reference
33
+ #
34
+ # @return [Object] the new value
35
+ #
36
+ # @raise [Concurrent::ConcurrentUpdateError] if the update fails
37
+ def try_update
38
+ old_value = get
39
+ new_value = yield old_value
40
+ unless compare_and_set(old_value, new_value)
41
+ if $VERBOSE
42
+ raise ConcurrentUpdateError, "Update failed"
43
+ else
44
+ raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE
45
+ end
46
+ end
47
+ new_value
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,14 @@
1
+ require_relative '../../extension_helper'
2
+ Concurrent.safe_require_java_extensions
3
+
4
+ if defined?(Concurrent::JavaAtomic)
5
+ require 'concurrent/atomic_reference/direct_update'
6
+
7
+ module Concurrent
8
+
9
+ # @!macro atomic_reference
10
+ class JavaAtomic
11
+ include Concurrent::AtomicDirectUpdate
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,77 @@
1
+ require 'thread'
2
+ require 'concurrent/atomic_reference/direct_update'
3
+ require 'concurrent/atomic_reference/numeric_cas_wrapper'
4
+
5
+ module Concurrent
6
+
7
+ # @!macro atomic_reference
8
+ class MutexAtomic
9
+ include Concurrent::AtomicDirectUpdate
10
+ include Concurrent::AtomicNumericCompareAndSetWrapper
11
+
12
+ # @!macro [attach] atomic_reference_method_initialize
13
+ def initialize(value = nil)
14
+ @mutex = Mutex.new
15
+ @value = value
16
+ end
17
+
18
+ # @!macro [attach] atomic_reference_method_get
19
+ #
20
+ # Gets the current value.
21
+ #
22
+ # @return [Object] the current value
23
+ def get
24
+ @mutex.synchronize { @value }
25
+ end
26
+ alias_method :value, :get
27
+
28
+ # @!macro [attach] atomic_reference_method_set
29
+ #
30
+ # Sets to the given value.
31
+ #
32
+ # @param [Object] new_value the new value
33
+ #
34
+ # @return [Object] the new value
35
+ def set(new_value)
36
+ @mutex.synchronize { @value = new_value }
37
+ end
38
+ alias_method :value=, :set
39
+
40
+ # @!macro [attach] atomic_reference_method_get_and_set
41
+ #
42
+ # Atomically sets to the given value and returns the old value.
43
+ #
44
+ # @param [Object] new_value the new value
45
+ #
46
+ # @return [Object] the old value
47
+ def get_and_set(new_value)
48
+ @mutex.synchronize do
49
+ old_value = @value
50
+ @value = new_value
51
+ old_value
52
+ end
53
+ end
54
+ alias_method :swap, :get_and_set
55
+
56
+ # @!macro [attach] atomic_reference_method_compare_and_set
57
+ #
58
+ # Atomically sets the value to the given updated value if
59
+ # the current value == the expected value.
60
+ #
61
+ # @param [Object] old_value the expected value
62
+ # @param [Object] new_value the new value
63
+ #
64
+ # @return [Boolean] `true` if successful. A `false` return indicates
65
+ # that the actual value was not equal to the expected value.
66
+ def _compare_and_set(old_value, new_value) #:nodoc:
67
+ return false unless @mutex.try_lock
68
+ begin
69
+ return false unless @value.equal? old_value
70
+ @value = new_value
71
+ ensure
72
+ @mutex.unlock
73
+ end
74
+ true
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,25 @@
1
+ module Concurrent
2
+
3
+ # Special "compare and set" handling of numeric values.
4
+ module AtomicNumericCompareAndSetWrapper
5
+
6
+ # @!macro atomic_reference_method_compare_and_set
7
+ def compare_and_set(old_value, new_value)
8
+ if old_value.kind_of? Numeric
9
+ while true
10
+ old = get
11
+
12
+ return false unless old.kind_of? Numeric
13
+
14
+ return false unless old == old_value
15
+
16
+ result = _compare_and_set(old, new_value)
17
+ return result if result
18
+ end
19
+ else
20
+ _compare_and_set(old_value, new_value)
21
+ end
22
+ end
23
+ alias_method :compare_and_swap, :compare_and_set
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ require 'concurrent/atomic_reference/direct_update'
2
+ require 'concurrent/atomic_reference/numeric_cas_wrapper'
3
+
4
+ module Concurrent
5
+
6
+ # @!macro atomic_reference
7
+ #
8
+ # @note Extends `Rubinius::AtomicReference` version adding aliases
9
+ # and numeric logic.
10
+ class RbxAtomic < Rubinius::AtomicReference
11
+ alias _compare_and_set compare_and_set
12
+ include Concurrent::AtomicDirectUpdate
13
+ include Concurrent::AtomicNumericCompareAndSetWrapper
14
+
15
+ alias_method :value, :get
16
+ alias_method :value=, :set
17
+ alias_method :swap, :get_and_set
18
+ end
19
+ end
@@ -0,0 +1,37 @@
1
+ require_relative '../../extension_helper'
2
+
3
+ if Concurrent.allow_c_extensions?
4
+ begin
5
+ require 'concurrent_ruby_ext'
6
+ rescue LoadError
7
+ # may be a Windows cross-compiled native gem
8
+ require "#{RUBY_VERSION[0..2]}/concurrent_ruby_ext"
9
+ end
10
+ end
11
+
12
+ require 'concurrent/atomic_reference/direct_update'
13
+ require 'concurrent/atomic_reference/numeric_cas_wrapper'
14
+
15
+ module Concurrent
16
+
17
+ # @!macro atomic_reference
18
+ class CAtomic
19
+ include Concurrent::AtomicDirectUpdate
20
+ include Concurrent::AtomicNumericCompareAndSetWrapper
21
+
22
+ # @!method initialize
23
+ # @!macro atomic_reference_method_initialize
24
+
25
+ # @!method get
26
+ # @!macro atomic_reference_method_get
27
+
28
+ # @!method set
29
+ # @!macro atomic_reference_method_set
30
+
31
+ # @!method get_and_set
32
+ # @!macro atomic_reference_method_get_and_set
33
+
34
+ # @!method _compare_and_set
35
+ # @!macro atomic_reference_method_compare_and_set
36
+ end
37
+ end