concurrent-ruby 0.7.0.rc0-x64-mingw32

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.
Files changed (95) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +166 -0
  4. data/ext/concurrent_ruby_ext/atomic_reference.c +78 -0
  5. data/ext/concurrent_ruby_ext/atomic_reference.h +12 -0
  6. data/ext/concurrent_ruby_ext/extconf.rb +59 -0
  7. data/ext/concurrent_ruby_ext/rb_concurrent.c +28 -0
  8. data/lib/2.0/concurrent_ruby_ext.so +0 -0
  9. data/lib/concurrent.rb +45 -0
  10. data/lib/concurrent/actress.rb +221 -0
  11. data/lib/concurrent/actress/ad_hoc.rb +20 -0
  12. data/lib/concurrent/actress/context.rb +98 -0
  13. data/lib/concurrent/actress/core.rb +228 -0
  14. data/lib/concurrent/actress/core_delegations.rb +42 -0
  15. data/lib/concurrent/actress/envelope.rb +41 -0
  16. data/lib/concurrent/actress/errors.rb +14 -0
  17. data/lib/concurrent/actress/reference.rb +64 -0
  18. data/lib/concurrent/actress/type_check.rb +48 -0
  19. data/lib/concurrent/agent.rb +232 -0
  20. data/lib/concurrent/async.rb +319 -0
  21. data/lib/concurrent/atomic.rb +46 -0
  22. data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
  23. data/lib/concurrent/atomic/atomic_fixnum.rb +162 -0
  24. data/lib/concurrent/atomic/condition.rb +67 -0
  25. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +118 -0
  26. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +117 -0
  27. data/lib/concurrent/atomic/count_down_latch.rb +116 -0
  28. data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
  29. data/lib/concurrent/atomic/event.rb +98 -0
  30. data/lib/concurrent/atomic/thread_local_var.rb +117 -0
  31. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
  32. data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
  33. data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
  34. data/lib/concurrent/atomic_reference/jruby.rb +8 -0
  35. data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
  36. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
  37. data/lib/concurrent/atomic_reference/rbx.rb +16 -0
  38. data/lib/concurrent/atomic_reference/ruby.rb +16 -0
  39. data/lib/concurrent/atomics.rb +10 -0
  40. data/lib/concurrent/channel/buffered_channel.rb +85 -0
  41. data/lib/concurrent/channel/channel.rb +41 -0
  42. data/lib/concurrent/channel/unbuffered_channel.rb +34 -0
  43. data/lib/concurrent/channel/waitable_list.rb +40 -0
  44. data/lib/concurrent/channels.rb +5 -0
  45. data/lib/concurrent/collection/blocking_ring_buffer.rb +71 -0
  46. data/lib/concurrent/collection/priority_queue.rb +305 -0
  47. data/lib/concurrent/collection/ring_buffer.rb +59 -0
  48. data/lib/concurrent/collections.rb +3 -0
  49. data/lib/concurrent/configuration.rb +158 -0
  50. data/lib/concurrent/dataflow.rb +91 -0
  51. data/lib/concurrent/delay.rb +112 -0
  52. data/lib/concurrent/dereferenceable.rb +101 -0
  53. data/lib/concurrent/errors.rb +30 -0
  54. data/lib/concurrent/exchanger.rb +34 -0
  55. data/lib/concurrent/executor/cached_thread_pool.rb +44 -0
  56. data/lib/concurrent/executor/executor.rb +229 -0
  57. data/lib/concurrent/executor/fixed_thread_pool.rb +33 -0
  58. data/lib/concurrent/executor/immediate_executor.rb +16 -0
  59. data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
  60. data/lib/concurrent/executor/java_fixed_thread_pool.rb +33 -0
  61. data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
  62. data/lib/concurrent/executor/java_thread_pool_executor.rb +187 -0
  63. data/lib/concurrent/executor/per_thread_executor.rb +24 -0
  64. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
  65. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +32 -0
  66. data/lib/concurrent/executor/ruby_single_thread_executor.rb +73 -0
  67. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +286 -0
  68. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +72 -0
  69. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  70. data/lib/concurrent/executor/serialized_execution.rb +90 -0
  71. data/lib/concurrent/executor/single_thread_executor.rb +35 -0
  72. data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
  73. data/lib/concurrent/executor/timer_set.rb +143 -0
  74. data/lib/concurrent/executors.rb +9 -0
  75. data/lib/concurrent/future.rb +124 -0
  76. data/lib/concurrent/ivar.rb +111 -0
  77. data/lib/concurrent/logging.rb +17 -0
  78. data/lib/concurrent/mvar.rb +200 -0
  79. data/lib/concurrent/obligation.rb +171 -0
  80. data/lib/concurrent/observable.rb +40 -0
  81. data/lib/concurrent/options_parser.rb +46 -0
  82. data/lib/concurrent/promise.rb +169 -0
  83. data/lib/concurrent/scheduled_task.rb +78 -0
  84. data/lib/concurrent/supervisor.rb +343 -0
  85. data/lib/concurrent/timer_task.rb +341 -0
  86. data/lib/concurrent/tvar.rb +252 -0
  87. data/lib/concurrent/utilities.rb +3 -0
  88. data/lib/concurrent/utility/processor_count.rb +150 -0
  89. data/lib/concurrent/utility/timeout.rb +35 -0
  90. data/lib/concurrent/utility/timer.rb +21 -0
  91. data/lib/concurrent/version.rb +3 -0
  92. data/lib/concurrent_ruby.rb +1 -0
  93. data/lib/concurrent_ruby_ext.so +0 -0
  94. data/lib/extension_helper.rb +9 -0
  95. metadata +141 -0
@@ -0,0 +1,17 @@
1
+ require 'logger'
2
+
3
+ module Concurrent
4
+ # Include where logging is needed
5
+ module Logging
6
+ include Logger::Severity
7
+
8
+ # Logs through {Configuration#logger}, it can be overridden by setting @logger
9
+ # @param [Integer] level one of Logger::Severity constants
10
+ # @param [String] progname e.g. a path of an Actor
11
+ # @param [String, nil] message when nil block is used to generate the message
12
+ # @yieldreturn [String] a message
13
+ def log(level, progname, message = nil, &block)
14
+ (@logger || Concurrent.configuration.logger).call level, progname, message, &block
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,200 @@
1
+ require 'concurrent/dereferenceable'
2
+ require 'concurrent/atomic/condition'
3
+ require 'concurrent/atomic/event'
4
+
5
+ module Concurrent
6
+
7
+ # An `MVar` is a single-element container that blocks on `get` if it is empty,
8
+ # and blocks on `put` if it is full. It is safe to use an `MVar` from
9
+ # multiple threads. `MVar` can be seen as a single-element blocking queue, or
10
+ # a rendezvous variable.
11
+ #
12
+ # An `MVar` is typically used to transfer objects between threads, where the
13
+ # sending thread will block if the previous message hasn't been taken yet by the
14
+ # receiving thread. It can also be used to control access to some global shared
15
+ # state, where threads `take` the value, perform some operation, and then
16
+ # `put` it back.
17
+ class MVar
18
+
19
+ include Dereferenceable
20
+
21
+ # Unique value that represents that an `MVar` was empty
22
+ EMPTY = Object.new
23
+
24
+ # Unique value that represents that an `MVar` timed out before it was able
25
+ # to produce a value.
26
+ TIMEOUT = Object.new
27
+
28
+ # Create a new `MVar`, either empty or with an initial value.
29
+ #
30
+ # @param [Hash] opts the options controlling how the future will be processed
31
+ # @option opts [Boolean] :operation (false) when `true` will execute the future on the global
32
+ # operation pool (for long-running operations), when `false` will execute the future on the
33
+ # global task pool (for short-running tasks)
34
+ # @option opts [object] :executor when provided will run all operations on
35
+ # this executor rather than the global thread pool (overrides :operation)
36
+ # @option opts [String] :dup_on_deref (false) call `#dup` before returning the data
37
+ # @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data
38
+ # @option opts [String] :copy_on_deref (nil) call the given `Proc` passing the internal value and
39
+ # returning the value returned from the proc
40
+ def initialize(value = EMPTY, opts = {})
41
+ @value = value
42
+ @mutex = Mutex.new
43
+ @empty_condition = Condition.new
44
+ @full_condition = Condition.new
45
+ set_deref_options(opts)
46
+ end
47
+
48
+ # Remove the value from an `MVar`, leaving it empty, and blocking if there
49
+ # isn't a value. A timeout can be set to limit the time spent blocked, in
50
+ # which case it returns `TIMEOUT` if the time is exceeded.
51
+ # @return [Object] the value that was taken, or `TIMEOUT`
52
+ def take(timeout = nil)
53
+ @mutex.synchronize do
54
+ wait_for_full(timeout)
55
+
56
+ # If we timed out we'll still be empty
57
+ if unlocked_full?
58
+ value = @value
59
+ @value = EMPTY
60
+ @empty_condition.signal
61
+ apply_deref_options(value)
62
+ else
63
+ TIMEOUT
64
+ end
65
+ end
66
+ end
67
+
68
+ # Put a value into an `MVar`, blocking if there is already a value until
69
+ # it is empty. A timeout can be set to limit the time spent blocked, in
70
+ # which case it returns `TIMEOUT` if the time is exceeded.
71
+ # @return [Object] the value that was put, or `TIMEOUT`
72
+ def put(value, timeout = nil)
73
+ @mutex.synchronize do
74
+ wait_for_empty(timeout)
75
+
76
+ # If we timed out we won't be empty
77
+ if unlocked_empty?
78
+ @value = value
79
+ @full_condition.signal
80
+ apply_deref_options(value)
81
+ else
82
+ TIMEOUT
83
+ end
84
+ end
85
+ end
86
+
87
+ # Atomically `take`, yield the value to a block for transformation, and then
88
+ # `put` the transformed value. Returns the transformed value. A timeout can
89
+ # be set to limit the time spent blocked, in which case it returns `TIMEOUT`
90
+ # if the time is exceeded.
91
+ # @return [Object] the transformed value, or `TIMEOUT`
92
+ def modify(timeout = nil)
93
+ raise ArgumentError.new('no block given') unless block_given?
94
+
95
+ @mutex.synchronize do
96
+ wait_for_full(timeout)
97
+
98
+ # If we timed out we'll still be empty
99
+ if unlocked_full?
100
+ value = @value
101
+ @value = yield value
102
+ @full_condition.signal
103
+ apply_deref_options(value)
104
+ else
105
+ TIMEOUT
106
+ end
107
+ end
108
+ end
109
+
110
+ # Non-blocking version of `take`, that returns `EMPTY` instead of blocking.
111
+ def try_take!
112
+ @mutex.synchronize do
113
+ if unlocked_full?
114
+ value = @value
115
+ @value = EMPTY
116
+ @empty_condition.signal
117
+ apply_deref_options(value)
118
+ else
119
+ EMPTY
120
+ end
121
+ end
122
+ end
123
+
124
+ # Non-blocking version of `put`, that returns whether or not it was successful.
125
+ def try_put!(value)
126
+ @mutex.synchronize do
127
+ if unlocked_empty?
128
+ @value = value
129
+ @full_condition.signal
130
+ true
131
+ else
132
+ false
133
+ end
134
+ end
135
+ end
136
+
137
+ # Non-blocking version of `put` that will overwrite an existing value.
138
+ def set!(value)
139
+ @mutex.synchronize do
140
+ old_value = @value
141
+ @value = value
142
+ @full_condition.signal
143
+ apply_deref_options(old_value)
144
+ end
145
+ end
146
+
147
+ # Non-blocking version of `modify` that will yield with `EMPTY` if there is no value yet.
148
+ def modify!
149
+ raise ArgumentError.new('no block given') unless block_given?
150
+
151
+ @mutex.synchronize do
152
+ value = @value
153
+ @value = yield value
154
+ if unlocked_empty?
155
+ @empty_condition.signal
156
+ else
157
+ @full_condition.signal
158
+ end
159
+ apply_deref_options(value)
160
+ end
161
+ end
162
+
163
+ # Returns if the `MVar` is currently empty.
164
+ def empty?
165
+ @mutex.synchronize { @value == EMPTY }
166
+ end
167
+
168
+ # Returns if the `MVar` currently contains a value.
169
+ def full?
170
+ not empty?
171
+ end
172
+
173
+ private
174
+
175
+ def unlocked_empty?
176
+ @value == EMPTY
177
+ end
178
+
179
+ def unlocked_full?
180
+ ! unlocked_empty?
181
+ end
182
+
183
+ def wait_for_full(timeout)
184
+ wait_while(@full_condition, timeout) { unlocked_empty? }
185
+ end
186
+
187
+ def wait_for_empty(timeout)
188
+ wait_while(@empty_condition, timeout) { unlocked_full? }
189
+ end
190
+
191
+ def wait_while(condition, timeout)
192
+ remaining = Condition::Result.new(timeout)
193
+ while yield && remaining.can_wait?
194
+ remaining = condition.wait(@mutex, remaining.remaining_time)
195
+ end
196
+ end
197
+
198
+ end
199
+
200
+ end
@@ -0,0 +1,171 @@
1
+ require 'thread'
2
+ require 'timeout'
3
+
4
+ require 'concurrent/dereferenceable'
5
+ require 'concurrent/atomic/event'
6
+
7
+ module Concurrent
8
+
9
+ module Obligation
10
+ include Dereferenceable
11
+
12
+ # Has the obligation been fulfilled?
13
+ # @return [Boolean]
14
+ def fulfilled?
15
+ state == :fulfilled
16
+ end
17
+ alias_method :realized?, :fulfilled?
18
+
19
+ # Has the obligation been rejected?
20
+ # @return [Boolean]
21
+ def rejected?
22
+ state == :rejected
23
+ end
24
+
25
+ # Is obligation completion still pending?
26
+ # @return [Boolean]
27
+ def pending?
28
+ state == :pending
29
+ end
30
+
31
+ # Is the obligation still unscheduled?
32
+ # @return [Boolean]
33
+ def unscheduled?
34
+ state == :unscheduled
35
+ end
36
+
37
+ def completed?
38
+ [:fulfilled, :rejected].include? state
39
+ end
40
+
41
+ def incomplete?
42
+ [:unscheduled, :pending].include? state
43
+ end
44
+
45
+ # @return [Object] see Dereferenceable#deref
46
+ def value(timeout = nil)
47
+ wait timeout
48
+ deref
49
+ end
50
+
51
+ # wait until Obligation is #complete?
52
+ # @param [Numeric] timeout the maximum time in second to wait.
53
+ # @return [Obligation] self
54
+ def wait(timeout = nil)
55
+ event.wait(timeout) if timeout != 0 && incomplete?
56
+ self
57
+ end
58
+
59
+ # wait until Obligation is #complete?
60
+ # @param [Numeric] timeout the maximum time in second to wait.
61
+ # @return [Obligation] self
62
+ # @raise [Exception] when #rejected? it raises #reason
63
+ def no_error!(timeout = nil)
64
+ wait(timeout).tap { raise self if rejected? }
65
+ end
66
+
67
+ # @raise [Exception] when #rejected? it raises #reason
68
+ # @return [Object] see Dereferenceable#deref
69
+ def value!(timeout = nil)
70
+ wait(timeout)
71
+ if rejected?
72
+ raise self
73
+ else
74
+ deref
75
+ end
76
+ end
77
+
78
+ def state
79
+ mutex.lock
80
+ @state
81
+ ensure
82
+ mutex.unlock
83
+ end
84
+
85
+ def reason
86
+ mutex.lock
87
+ @reason
88
+ ensure
89
+ mutex.unlock
90
+ end
91
+
92
+ # @example allows Obligation to be risen
93
+ # rejected_ivar = Ivar.new.fail
94
+ # raise rejected_ivar
95
+ def exception(*args)
96
+ raise 'obligation is not rejected' unless rejected?
97
+ reason.exception(*args)
98
+ end
99
+
100
+ protected
101
+
102
+ # @!visibility private
103
+ def init_obligation # :nodoc:
104
+ init_mutex
105
+ @event = Event.new
106
+ end
107
+
108
+ # @!visibility private
109
+ def event # :nodoc:
110
+ @event
111
+ end
112
+
113
+ # @!visibility private
114
+ def set_state(success, value, reason) # :nodoc:
115
+ if success
116
+ @value = value
117
+ @state = :fulfilled
118
+ else
119
+ @reason = reason
120
+ @state = :rejected
121
+ end
122
+ end
123
+
124
+ # @!visibility private
125
+ def state=(value) # :nodoc:
126
+ mutex.lock
127
+ @state = value
128
+ ensure
129
+ mutex.unlock
130
+ end
131
+
132
+ # atomic compare and set operation
133
+ # state is set to next_state only if current state is == expected_current
134
+ #
135
+ # @param [Symbol] next_state
136
+ # @param [Symbol] expected_current
137
+ #
138
+ # @return [Boolean] true is state is changed, false otherwise
139
+ #
140
+ # @!visibility private
141
+ def compare_and_set_state(next_state, expected_current) # :nodoc:
142
+ mutex.lock
143
+ if @state == expected_current
144
+ @state = next_state
145
+ true
146
+ else
147
+ false
148
+ end
149
+ ensure
150
+ mutex.unlock
151
+ end
152
+
153
+ # executes the block within mutex if current state is included in expected_states
154
+ #
155
+ # @return block value if executed, false otherwise
156
+ #
157
+ # @!visibility private
158
+ def if_state(*expected_states) # :nodoc:
159
+ mutex.lock
160
+ raise ArgumentError.new('no block given') unless block_given?
161
+
162
+ if expected_states.include? @state
163
+ yield
164
+ else
165
+ false
166
+ end
167
+ ensure
168
+ mutex.unlock
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,40 @@
1
+ require 'concurrent/atomic/copy_on_notify_observer_set'
2
+ require 'concurrent/atomic/copy_on_write_observer_set'
3
+
4
+ module Concurrent
5
+
6
+ module Observable
7
+
8
+ # @return [Object] the added observer
9
+ def add_observer(*args, &block)
10
+ observers.add_observer(*args, &block)
11
+ end
12
+
13
+ # as #add_observer but it can be used for chaining
14
+ # @return [Observable] self
15
+ def with_observer(*args, &block)
16
+ add_observer *args, &block
17
+ self
18
+ end
19
+
20
+ # @return [Object] the deleted observer
21
+ def delete_observer(*args)
22
+ observers.delete_observer(*args)
23
+ end
24
+
25
+ # @return [Observable] self
26
+ def delete_observers
27
+ observers.delete_observers
28
+ self
29
+ end
30
+
31
+ # @return [Integer] the observers count
32
+ def count_observers
33
+ observers.count_observers
34
+ end
35
+
36
+ protected
37
+
38
+ attr_accessor :observers
39
+ end
40
+ end
@@ -0,0 +1,46 @@
1
+ module Concurrent
2
+
3
+ # A mixin module for parsing options hashes related to gem-level configuration.
4
+ module OptionsParser
5
+
6
+ # Get the requested `Executor` based on the values set in the options hash.
7
+ #
8
+ # @param [Hash] opts the options defining the requested executor
9
+ # @option opts [Executor] :executor (`nil`) when set use the given `Executor` instance
10
+ # @option opts [Boolean] :operation (`false`) when true use the global operation pool
11
+ # @option opts [Boolean] :task (`true`) when true use the global task pool
12
+ #
13
+ # @return [Executor] the requested thread pool (default: global task pool)
14
+ def get_executor_from(opts = {})
15
+ if opts[:executor]
16
+ opts[:executor]
17
+ elsif opts[:operation] == true || opts[:task] == false
18
+ Concurrent.configuration.global_operation_pool
19
+ else
20
+ Concurrent.configuration.global_task_pool
21
+ end
22
+ end
23
+
24
+ # Get the requested `Executor` based on the values set in the options hash.
25
+ #
26
+ # @param [Hash] opts the options defining the requested executor
27
+ # @option opts [Executor] :task_executor (`nil`) when set use the given `Executor` instance
28
+ #
29
+ # @return [Executor] the requested thread pool (default: global task pool)
30
+ def get_task_executor_from(opts = {})
31
+ opts[:task_executor] || opts[:executor] || Concurrent.configuration.global_task_pool
32
+ end
33
+
34
+ # Get the requested `Executor` based on the values set in the options hash.
35
+ #
36
+ # @param [Hash] opts the options defining the requested executor
37
+ # @option opts [Executor] :task_executor (`nil`) when set use the given `Executor` instance
38
+ #
39
+ # @return [Executor] the requested thread pool (default: global operation pool)
40
+ def get_operation_executor_from(opts = {})
41
+ opts[:operation_executor] || opts[:executor] || Concurrent.configuration.global_operation_pool
42
+ end
43
+
44
+ extend self
45
+ end
46
+ end