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,54 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+
5
+ # Handles actor termination.
6
+ # @note Actor rejects envelopes when terminated.
7
+ class Termination < Abstract
8
+
9
+ # @!attribute [r] terminated
10
+ # @return [Event] event which will become set when actor is terminated.
11
+ attr_reader :terminated
12
+
13
+ def initialize(core, subsequent)
14
+ super core, subsequent
15
+ @terminated = Event.new
16
+ end
17
+
18
+ # @note Actor rejects envelopes when terminated.
19
+ # @return [true, false] if actor is terminated
20
+ def terminated?
21
+ @terminated.set?
22
+ end
23
+
24
+ def on_envelope(envelope)
25
+ case envelope.message
26
+ when :terminated?
27
+ terminated?
28
+ when :terminate!
29
+ terminate!
30
+ when :terminated_event
31
+ terminated
32
+ else
33
+ if terminated?
34
+ reject_envelope envelope
35
+ MESSAGE_PROCESSED
36
+ else
37
+ pass envelope
38
+ end
39
+ end
40
+ end
41
+
42
+ # Terminates the actor. Any Envelope received after termination is rejected.
43
+ # Terminates all its children, does not wait until they are terminated.
44
+ def terminate!
45
+ return true if terminated?
46
+ terminated.set
47
+ broadcast(:terminated)
48
+ parent << :remove_child if parent
49
+ true
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,153 @@
1
+ module Concurrent
2
+ module Actor
3
+
4
+ # Abstract implementation of Actor context. Children has to implement
5
+ # {AbstractContext#on_message} and {AbstractContext#behaviour_definition} methods.
6
+ # There are two implementations:
7
+ #
8
+ # - {Context}
9
+ #
10
+ # > {include:Actor::Context}
11
+ #
12
+ # - {RestartingContext}.
13
+ #
14
+ # > {include:Actor::RestartingContext}
15
+ class AbstractContext
16
+ include TypeCheck
17
+ include InternalDelegations
18
+
19
+ attr_reader :core
20
+
21
+ # @abstract override to define Actor's behaviour
22
+ # @param [Object] message
23
+ # @return [Object] a result which will be used to set the IVar supplied to Reference#ask
24
+ # @note self should not be returned (or sent to other actors), {#reference} should be used
25
+ # instead
26
+ def on_message(message)
27
+ raise NotImplementedError
28
+ end
29
+
30
+ # override to add custom code invocation on events like `:terminated`, `:resumed`, `anError`.
31
+ def on_event(event)
32
+ end
33
+
34
+ # @api private
35
+ def on_envelope(envelope)
36
+ @envelope = envelope
37
+ on_message envelope.message
38
+ ensure
39
+ @envelope = nil
40
+ end
41
+
42
+ # if you want to pass the message to next behaviour, usually {Behaviour::ErrorsOnUnknownMessage}
43
+ def pass
44
+ core.behaviour!(Behaviour::ExecutesContext).pass envelope
45
+ end
46
+
47
+ # Defines an actor responsible for dead letters. Any rejected message send with
48
+ # {Reference#tell} is sent there, a message with ivar is considered already monitored for
49
+ # failures. Default behaviour is to use {AbstractContext#dead_letter_routing} of the parent,
50
+ # so if no {AbstractContext#dead_letter_routing} method is overridden in parent-chain the message ends up in
51
+ # `Actor.root.dead_letter_routing` agent which will log warning.
52
+ # @return [Reference]
53
+ def dead_letter_routing
54
+ parent.dead_letter_routing
55
+ end
56
+
57
+ # @return [Array<Array(Behavior::Abstract, Array<Object>)>]
58
+ def behaviour_definition
59
+ raise NotImplementedError
60
+ end
61
+
62
+ # @return [Envelope] current envelope, accessible inside #on_message processing
63
+ def envelope
64
+ @envelope or raise 'envelope not set'
65
+ end
66
+
67
+ # override if different class for reference is needed
68
+ # @return [CLass] descendant of {Reference}
69
+ def default_reference_class
70
+ Reference
71
+ end
72
+
73
+ def tell(message)
74
+ reference.tell message
75
+ end
76
+
77
+ def ask(message)
78
+ raise 'actor cannot ask itself'
79
+ end
80
+
81
+ alias_method :<<, :tell
82
+ alias_method :ask!, :ask
83
+
84
+ private
85
+
86
+ def initialize_core(core)
87
+ @core = Type! core, Core
88
+ end
89
+
90
+ # behaves as {Concurrent::Actor.spawn} but :class is auto-inserted based on receiver
91
+ def self.spawn(name_or_opts, *args, &block)
92
+ Actor.spawn spawn_optionify(name_or_opts, *args), &block
93
+ end
94
+
95
+ # behaves as {Concurrent::Actor.spawn!} but :class is auto-inserted based on receiver
96
+ def self.spawn!(name_or_opts, *args, &block)
97
+ Actor.spawn! spawn_optionify(name_or_opts, *args), &block
98
+ end
99
+
100
+ private
101
+
102
+ def self.spawn_optionify(name_or_opts, *args)
103
+ if name_or_opts.is_a? Hash
104
+ if name_or_opts.key?(:class) && name_or_opts[:class] != self
105
+ raise ArgumentError,
106
+ ':class option is ignored when calling on context class, use Actor.spawn instead'
107
+ end
108
+ name_or_opts.merge class: self
109
+ else
110
+ { class: self, name: name_or_opts, args: args }
111
+ end
112
+ end
113
+
114
+ # to avoid confusion with Kernel.spawn
115
+ undef_method :spawn
116
+ end
117
+
118
+ # Basic Context of an Actor.
119
+ #
120
+ # - linking
121
+ # - terminates on error
122
+ #
123
+ # TODO describe behaviour
124
+ # TODO usage
125
+ # @example ping
126
+ # class Ping < Context
127
+ # def on_message(message)
128
+ # message
129
+ # end
130
+ # end
131
+ #
132
+ # Ping.spawn(:ping1).ask(:m).value #=> :m
133
+ class Context < AbstractContext
134
+ def behaviour_definition
135
+ Behaviour.basic_behaviour_definition
136
+ end
137
+ end
138
+
139
+ # Context of an Actor for complex robust systems.
140
+ #
141
+ # - linking
142
+ # - supervising
143
+ # - pauses on error
144
+ #
145
+ # TODO describe behaviour
146
+ # TODO usage
147
+ class RestartingContext < AbstractContext
148
+ def behaviour_definition
149
+ Behaviour.restarting_behaviour_definition
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,213 @@
1
+ module Concurrent
2
+ module Actor
3
+
4
+ require 'set'
5
+
6
+ # Core of the actor
7
+ # @note Whole class should be considered private. An user should use {Context}s and {Reference}s only.
8
+ # @note devel: core should not block on anything, e.g. it cannot wait on children to terminate
9
+ # that would eat up all threads in task pool and deadlock
10
+ class Core
11
+ include TypeCheck
12
+ include Concurrent::Logging
13
+ include Synchronization
14
+
15
+ # @!attribute [r] reference
16
+ # @return [Reference] reference to this actor which can be safely passed around
17
+ # @!attribute [r] name
18
+ # @return [String] the name of this instance, it should be uniq (not enforced right now)
19
+ # @!attribute [r] path
20
+ # @return [String] a path of this actor. It is used for easier orientation and logging.
21
+ # Path is constructed recursively with: `parent.path + self.name` up to a {Actor.root},
22
+ # e.g. `/an_actor/its_child`.
23
+ # (It will also probably form a supervision path (failures will be reported up to parents)
24
+ # in future versions.)
25
+ # @!attribute [r] executor
26
+ # @return [Executor] which is used to process messages
27
+ # @!attribute [r] actor_class
28
+ # @return [Context] a class including {Context} representing Actor's behaviour
29
+ attr_reader :reference, :name, :path, :executor, :context_class, :context, :behaviour_definition
30
+
31
+ # @option opts [String] name
32
+ # @option opts [Reference, nil] parent of an actor spawning this one
33
+ # @option opts [Class] reference a custom descendant of {Reference} to use
34
+ # @option opts [Context] actor_class a class to be instantiated defining Actor's behaviour
35
+ # @option opts [Array<Object>] args arguments for actor_class instantiation
36
+ # @option opts [Executor] executor, default is `Concurrent.configuration.global_task_pool`
37
+ # @option opts [true, false] link, atomically link the actor to its parent
38
+ # @option opts [true, false] supervise, atomically supervise the actor by its parent
39
+ # @option opts [Array<Array(Behavior::Abstract, Array<Object>)>] behaviour_definition, array of pairs
40
+ # where each pair is behaviour class and its args, see {Behaviour.basic_behaviour_definition}
41
+ # @option opts [IVar, nil] initialized, if present it'll be set or failed after {Context} initialization
42
+ # @option opts [Proc, nil] logger a proc accepting (level, progname, message = nil, &block) params,
43
+ # can be used to hook actor instance to any logging system
44
+ # @param [Proc] block for class instantiation
45
+ def initialize(opts = {}, &block)
46
+ synchronize do
47
+ @mailbox = Array.new
48
+ @serialized_execution = SerializedExecution.new
49
+ @executor = Type! opts.fetch(:executor, Concurrent.configuration.global_task_pool), Executor
50
+ @children = Set.new
51
+ @context_class = Child! opts.fetch(:class), AbstractContext
52
+ allocate_context
53
+ @reference = (Child! opts[:reference_class] || @context.default_reference_class, Reference).new self
54
+ @name = (Type! opts.fetch(:name), String, Symbol).to_s
55
+
56
+ parent = opts[:parent]
57
+ @parent_core = (Type! parent, Reference, NilClass) && parent.send(:core)
58
+ if @parent_core.nil? && @name != '/'
59
+ raise 'only root has no parent'
60
+ end
61
+
62
+ @path = @parent_core ? File.join(@parent_core.path, @name) : @name
63
+ @logger = opts[:logger]
64
+
65
+ @parent_core.add_child reference if @parent_core
66
+
67
+ initialize_behaviours opts
68
+
69
+ @args = opts.fetch(:args, [])
70
+ @block = block
71
+ initialized = Type! opts[:initialized], IVar, NilClass
72
+
73
+ messages = []
74
+ messages << :link if opts[:link]
75
+ messages << :supervise if opts[:supervise]
76
+
77
+ schedule_execution do
78
+ begin
79
+ build_context
80
+
81
+ messages.each do |message|
82
+ handle_envelope Envelope.new(message, nil, parent, reference)
83
+ end
84
+
85
+ initialized.set true if initialized
86
+ rescue => ex
87
+ log ERROR, ex
88
+ @first_behaviour.terminate!
89
+ initialized.fail ex if initialized
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ # @return [Reference, nil] of parent actor
96
+ def parent
97
+ @parent_core && @parent_core.reference
98
+ end
99
+
100
+ # @see AbstractContext#dead_letter_routing
101
+ def dead_letter_routing
102
+ @context.dead_letter_routing
103
+ end
104
+
105
+ # @return [Array<Reference>] of children actors
106
+ def children
107
+ guard!
108
+ @children.to_a
109
+ end
110
+
111
+ # @api private
112
+ def add_child(child)
113
+ guard!
114
+ Type! child, Reference
115
+ @children.add child
116
+ nil
117
+ end
118
+
119
+ # @api private
120
+ def remove_child(child)
121
+ guard!
122
+ Type! child, Reference
123
+ @children.delete child
124
+ nil
125
+ end
126
+
127
+ # is executed by Reference scheduling processing of new messages
128
+ # can be called from other alternative Reference implementations
129
+ # @param [Envelope] envelope
130
+ def on_envelope(envelope)
131
+ schedule_execution { handle_envelope envelope }
132
+ nil
133
+ end
134
+
135
+ # ensures that we are inside of the executor
136
+ def guard!
137
+ unless Actor.current == reference
138
+ raise "can be called only inside actor #{reference} but was #{Actor.current}"
139
+ end
140
+ end
141
+
142
+ def log(level, message = nil, &block)
143
+ super level, @path, message, &block
144
+ end
145
+
146
+ # Schedules blocks to be executed on executor sequentially,
147
+ # sets Actress.current
148
+ def schedule_execution
149
+ @serialized_execution.post(@executor) do
150
+ synchronize do
151
+ begin
152
+ Thread.current[:__current_actor__] = reference
153
+ yield
154
+ rescue => e
155
+ log FATAL, e
156
+ ensure
157
+ Thread.current[:__current_actor__] = nil
158
+ end
159
+ end
160
+ end
161
+
162
+ nil
163
+ end
164
+
165
+ def broadcast(event)
166
+ @first_behaviour.on_event(event)
167
+ end
168
+
169
+ # @param [Class] behaviour_class
170
+ # @return [Behaviour::Abstract, nil] based on behaviour_class
171
+ def behaviour(behaviour_class)
172
+ @behaviours[behaviour_class]
173
+ end
174
+
175
+ # @param [Class] behaviour_class
176
+ # @return [Behaviour::Abstract] based on behaviour_class
177
+ # @raise [KeyError] when no behaviour
178
+ def behaviour!(behaviour_class)
179
+ @behaviours.fetch behaviour_class
180
+ end
181
+
182
+ # @api private
183
+ def allocate_context
184
+ @context = @context_class.allocate
185
+ end
186
+
187
+ # @api private
188
+ def build_context
189
+ @context.send :initialize_core, self
190
+ @context.send :initialize, *@args, &@block
191
+ end
192
+
193
+ private
194
+
195
+ def handle_envelope(envelope)
196
+ log DEBUG, "received #{envelope.message.inspect} from #{envelope.sender}"
197
+ @first_behaviour.on_envelope envelope
198
+ end
199
+
200
+ def initialize_behaviours(opts)
201
+ @behaviour_definition = (Type! opts[:behaviour_definition] || @context.behaviour_definition, Array).each do |v|
202
+ Type! v, Array
203
+ Match! v.size, 2
204
+ Child! v[0], Behaviour::Abstract
205
+ Type! v[1], Array
206
+ end
207
+ @behaviours = {}
208
+ @first_behaviour = @behaviour_definition.reverse.
209
+ reduce(nil) { |last, (behaviour, args)| @behaviours[behaviour] = behaviour.new(self, last, *args) }
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,9 @@
1
+ module Concurrent
2
+ module Actor
3
+ class DefaultDeadLetterHandler < RestartingContext
4
+ def on_message(dead_letter)
5
+ log Logging::INFO, "got dead letter #{dead_letter.inspect}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,41 @@
1
+ module Concurrent
2
+ module Actor
3
+ class Envelope
4
+ include TypeCheck
5
+
6
+ # @!attribute [r] message
7
+ # @return [Object] a message
8
+ # @!attribute [r] ivar
9
+ # @return [IVar] an ivar which becomes resolved after message is processed
10
+ # @!attribute [r] sender
11
+ # @return [Reference, Thread] an actor or thread sending the message
12
+ # @!attribute [r] address
13
+ # @return [Reference] where this message will be delivered
14
+
15
+ attr_reader :message, :ivar, :sender, :address
16
+
17
+ def initialize(message, ivar, sender, address)
18
+ @message = message
19
+ @ivar = Type! ivar, IVar, NilClass
20
+ @sender = Type! sender, Reference, Thread
21
+ @address = Type! address, Reference
22
+ end
23
+
24
+ def sender_path
25
+ if sender.is_a? Reference
26
+ sender.path
27
+ else
28
+ sender.to_s
29
+ end
30
+ end
31
+
32
+ def address_path
33
+ address.path
34
+ end
35
+
36
+ def reject!(error)
37
+ ivar.fail error unless ivar.nil?
38
+ end
39
+ end
40
+ end
41
+ end