concurrent-ruby 0.7.0.rc1-x86-linux → 0.7.0.rc2-x86-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +3 -2
  3. data/ext/concurrent_ruby_ext/atomic_boolean.c +48 -0
  4. data/ext/concurrent_ruby_ext/atomic_boolean.h +16 -0
  5. data/ext/concurrent_ruby_ext/atomic_fixnum.c +50 -0
  6. data/ext/concurrent_ruby_ext/atomic_fixnum.h +13 -0
  7. data/ext/concurrent_ruby_ext/atomic_reference.c +44 -44
  8. data/ext/concurrent_ruby_ext/atomic_reference.h +8 -0
  9. data/ext/concurrent_ruby_ext/rb_concurrent.c +32 -3
  10. data/ext/concurrent_ruby_ext/ruby_193_compatible.h +28 -0
  11. data/lib/1.9/concurrent_ruby_ext.so +0 -0
  12. data/lib/2.0/concurrent_ruby_ext.so +0 -0
  13. data/lib/concurrent.rb +2 -1
  14. data/lib/concurrent/actor.rb +104 -0
  15. data/lib/concurrent/{actress → actor}/ad_hoc.rb +2 -3
  16. data/lib/concurrent/actor/behaviour.rb +70 -0
  17. data/lib/concurrent/actor/behaviour/abstract.rb +48 -0
  18. data/lib/concurrent/actor/behaviour/awaits.rb +21 -0
  19. data/lib/concurrent/actor/behaviour/buffer.rb +54 -0
  20. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +12 -0
  21. data/lib/concurrent/actor/behaviour/executes_context.rb +18 -0
  22. data/lib/concurrent/actor/behaviour/linking.rb +42 -0
  23. data/lib/concurrent/actor/behaviour/pausing.rb +77 -0
  24. data/lib/concurrent/actor/behaviour/removes_child.rb +16 -0
  25. data/lib/concurrent/actor/behaviour/sets_results.rb +36 -0
  26. data/lib/concurrent/actor/behaviour/supervised.rb +58 -0
  27. data/lib/concurrent/actor/behaviour/supervising.rb +34 -0
  28. data/lib/concurrent/actor/behaviour/terminates_children.rb +13 -0
  29. data/lib/concurrent/actor/behaviour/termination.rb +54 -0
  30. data/lib/concurrent/actor/context.rb +153 -0
  31. data/lib/concurrent/actor/core.rb +213 -0
  32. data/lib/concurrent/actor/default_dead_letter_handler.rb +9 -0
  33. data/lib/concurrent/{actress → actor}/envelope.rb +1 -1
  34. data/lib/concurrent/actor/errors.rb +27 -0
  35. data/lib/concurrent/actor/internal_delegations.rb +49 -0
  36. data/lib/concurrent/{actress/core_delegations.rb → actor/public_delegations.rb} +11 -13
  37. data/lib/concurrent/{actress → actor}/reference.rb +25 -8
  38. data/lib/concurrent/actor/root.rb +37 -0
  39. data/lib/concurrent/{actress → actor}/type_check.rb +1 -1
  40. data/lib/concurrent/actor/utills.rb +7 -0
  41. data/lib/concurrent/actor/utils/broadcast.rb +36 -0
  42. data/lib/concurrent/actress.rb +2 -224
  43. data/lib/concurrent/agent.rb +10 -12
  44. data/lib/concurrent/atomic.rb +32 -1
  45. data/lib/concurrent/atomic/atomic_boolean.rb +55 -13
  46. data/lib/concurrent/atomic/atomic_fixnum.rb +54 -16
  47. data/lib/concurrent/atomic/synchronization.rb +51 -0
  48. data/lib/concurrent/atomic/thread_local_var.rb +15 -50
  49. data/lib/concurrent/atomic_reference/mutex_atomic.rb +1 -1
  50. data/lib/concurrent/atomic_reference/ruby.rb +15 -0
  51. data/lib/concurrent/atomics.rb +1 -0
  52. data/lib/concurrent/channel/unbuffered_channel.rb +2 -1
  53. data/lib/concurrent/configuration.rb +6 -3
  54. data/lib/concurrent/dataflow.rb +20 -3
  55. data/lib/concurrent/delay.rb +23 -31
  56. data/lib/concurrent/executor/executor.rb +7 -2
  57. data/lib/concurrent/executor/timer_set.rb +1 -1
  58. data/lib/concurrent/future.rb +2 -1
  59. data/lib/concurrent/lazy_register.rb +58 -0
  60. data/lib/concurrent/options_parser.rb +4 -2
  61. data/lib/concurrent/promise.rb +2 -1
  62. data/lib/concurrent/scheduled_task.rb +6 -5
  63. data/lib/concurrent/tvar.rb +6 -10
  64. data/lib/concurrent/utility/processor_count.rb +4 -2
  65. data/lib/concurrent/version.rb +1 -1
  66. data/lib/concurrent_ruby_ext.so +0 -0
  67. metadata +39 -10
  68. data/lib/concurrent/actress/context.rb +0 -98
  69. data/lib/concurrent/actress/core.rb +0 -228
  70. data/lib/concurrent/actress/errors.rb +0 -14
@@ -1,13 +1,12 @@
1
1
  module Concurrent
2
- module Actress
2
+ module Actor
3
3
  # Allows quick creation of actors with behaviour defined by blocks.
4
4
  # @example ping
5
5
  # AdHoc.spawn :forward, an_actor do |where|
6
6
  # # this block has to return proc defining #on_message behaviour
7
7
  # -> message { where.tell message }
8
8
  # end
9
- class AdHoc
10
- include Context
9
+ class AdHoc < Context
11
10
  def initialize(*args, &initializer)
12
11
  @on_message = Type! initializer.call(*args), Proc
13
12
  end
@@ -0,0 +1,70 @@
1
+ module Concurrent
2
+ module Actor
3
+
4
+ # Actors have modular architecture, which is achieved by combining a light core with chain of
5
+ # behaviours. Each message or internal event propagates through the chain allowing the
6
+ # behaviours react based on their responsibility. listing few as an example:
7
+ #
8
+ # - {Behaviour::Linking}:
9
+ #
10
+ # > {include:Actor::Behaviour::Linking}
11
+ #
12
+ # - {Behaviour::Awaits}:
13
+ #
14
+ # > {include:Actor::Behaviour::Awaits}
15
+ #
16
+ # See {Behaviour}'s namespace fo other behaviours.
17
+ # If needed new behaviours can be added, or old one removed to get required behaviour.
18
+ module Behaviour
19
+ MESSAGE_PROCESSED = Object.new
20
+
21
+ require 'concurrent/actor/behaviour/abstract'
22
+ require 'concurrent/actor/behaviour/awaits'
23
+ require 'concurrent/actor/behaviour/buffer'
24
+ require 'concurrent/actor/behaviour/errors_on_unknown_message'
25
+ require 'concurrent/actor/behaviour/executes_context'
26
+ require 'concurrent/actor/behaviour/linking'
27
+ require 'concurrent/actor/behaviour/pausing'
28
+ require 'concurrent/actor/behaviour/removes_child'
29
+ require 'concurrent/actor/behaviour/sets_results'
30
+ require 'concurrent/actor/behaviour/supervised'
31
+ require 'concurrent/actor/behaviour/supervising'
32
+ require 'concurrent/actor/behaviour/termination'
33
+ require 'concurrent/actor/behaviour/terminates_children'
34
+
35
+ def self.basic_behaviour_definition
36
+ [*base,
37
+ *user_messages(:terminate!)]
38
+ end
39
+
40
+ def self.restarting_behaviour_definition
41
+ [*base,
42
+ *supervised,
43
+ [Behaviour::Supervising, [:reset!, :one_for_one]],
44
+ *user_messages(:pause!)]
45
+ end
46
+
47
+ def self.base
48
+ [[SetResults, [:terminate!]],
49
+ # has to be before Termination to be able to remove children form terminated actor
50
+ [RemovesChild, []],
51
+ [Termination, []],
52
+ [TerminatesChildren, []],
53
+ [Linking, []]]
54
+ end
55
+
56
+ def self.supervised
57
+ [[Supervised, []],
58
+ [Pausing, []]]
59
+ end
60
+
61
+ def self.user_messages(on_error)
62
+ [[Buffer, []],
63
+ [SetResults, [on_error]],
64
+ [Awaits, []],
65
+ [ExecutesContext, []],
66
+ [ErrorsOnUnknownMessage, []]]
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,48 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+ class Abstract
5
+ include TypeCheck
6
+ include InternalDelegations
7
+
8
+ attr_reader :core, :subsequent
9
+
10
+ def initialize(core, subsequent)
11
+ @core = Type! core, Core
12
+ @subsequent = Type! subsequent, Abstract, NilClass
13
+ end
14
+
15
+ # override to add extra behaviour
16
+ # @note super needs to be called not to break the chain
17
+ def on_envelope(envelope)
18
+ pass envelope
19
+ end
20
+
21
+ # @param [Envelope] envelope to pass to {#subsequent} behaviour
22
+ def pass(envelope)
23
+ subsequent.on_envelope envelope
24
+ end
25
+
26
+ # override to add extra behaviour
27
+ # @note super needs to be called not to break the chain
28
+ def on_event(event)
29
+ subsequent.on_event event if subsequent
30
+ end
31
+
32
+ # broadcasts event to all behaviours and context
33
+ # @see #on_event
34
+ # @see AbstractContext#on_event
35
+ def broadcast(event)
36
+ core.broadcast(event)
37
+ end
38
+
39
+ def reject_envelope(envelope)
40
+ envelope.reject! ActorTerminated.new(reference)
41
+ dead_letter_routing << envelope unless envelope.ivar
42
+ log Logging::DEBUG, "rejected #{envelope.message} from #{envelope.sender_path}"
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
@@ -0,0 +1,21 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+
5
+ # Handles `:await` messages. Which allows to wait on Actor to process all previously send
6
+ # messages.
7
+ # @example
8
+ # actor << :a << :b
9
+ # actor.ask(:await).wait # blocks until :a and :b are processed
10
+ class Awaits < Abstract
11
+ def on_envelope(envelope)
12
+ if envelope.message == :await
13
+ true
14
+ else
15
+ pass envelope
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+
5
+ # Any message reaching this behaviour is buffered. Only one message is is scheduled
6
+ # at any given time. Others are kept in buffer until another one can be scheduled.
7
+ # This effective means that messages handled by behaviours before buffer have higher priority
8
+ # and they can be processed before messages arriving into buffer. This allows to
9
+ # process internal actor messages like (`:link`, `:supervise`) processed first.
10
+ class Buffer < Abstract
11
+ def initialize(core, subsequent)
12
+ super core, subsequent
13
+ @buffer = []
14
+ @receive_envelope_scheduled = false
15
+ end
16
+
17
+ def on_envelope(envelope)
18
+ @buffer.push envelope
19
+ process_envelopes?
20
+ MESSAGE_PROCESSED
21
+ end
22
+
23
+ # Ensures that only one envelope processing is scheduled with #schedule_execution,
24
+ # this allows other scheduled blocks to be executed before next envelope processing.
25
+ # Simply put this ensures that Core is still responsive to internal calls (like add_child)
26
+ # even though the Actor is flooded with messages.
27
+ def process_envelopes?
28
+ unless @buffer.empty? || @receive_envelope_scheduled
29
+ @receive_envelope_scheduled = true
30
+ process_envelope
31
+ end
32
+ end
33
+
34
+ def process_envelope
35
+ envelope = @buffer.shift
36
+ return nil unless envelope
37
+ pass envelope
38
+ ensure
39
+ @receive_envelope_scheduled = false
40
+ core.schedule_execution { process_envelopes? }
41
+ end
42
+
43
+ def on_event(event)
44
+ case event
45
+ when :terminated, :restarted
46
+ @buffer.each { |envelope| reject_envelope envelope }
47
+ @buffer.clear
48
+ end
49
+ super event
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,12 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+ # Simply fails when message arrives here.
5
+ class ErrorsOnUnknownMessage < Abstract
6
+ def on_envelope(envelope)
7
+ raise UnknownMessage, envelope
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+ # Delegates messages nad events to {AbstractContext} instance
5
+ class ExecutesContext < Abstract
6
+ def on_envelope(envelope)
7
+ context.on_envelope envelope
8
+ end
9
+
10
+ def on_event(event)
11
+ context.on_event(event)
12
+ core.log Logging::DEBUG, "event: #{event.inspect}"
13
+ super event
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,42 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+
5
+ # Links the actor to other actors and sends events to them,
6
+ # like: `:terminated`, `:paused`, errors, etc
7
+ class Linking < Abstract
8
+ def initialize(core, subsequent)
9
+ super core, subsequent
10
+ @linked = Set.new
11
+ end
12
+
13
+ def on_envelope(envelope)
14
+ case envelope.message
15
+ when :link
16
+ link envelope.sender
17
+ when :unlink
18
+ unlink envelope.sender
19
+ else
20
+ pass envelope
21
+ end
22
+ end
23
+
24
+ def link(ref)
25
+ @linked.add(ref)
26
+ true
27
+ end
28
+
29
+ def unlink(ref)
30
+ @linked.delete(ref)
31
+ true
32
+ end
33
+
34
+ def on_event(event)
35
+ @linked.each { |a| a << event }
36
+ @linked.clear if event == :terminated
37
+ super event
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,77 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+
5
+ # Allows to pause actors on errors.
6
+ # When paused all arriving messages are collected and processed after the actor
7
+ # is resumed or reset. Resume will simply continue with next message.
8
+ # Reset also reinitialized context. `:reset!` and `:resume!` messages are only accepted
9
+ # form supervisor, see Supervised behaviour.
10
+ class Pausing < Abstract
11
+ def initialize(core, subsequent)
12
+ super core, subsequent
13
+ @paused = false
14
+ @buffer = []
15
+ end
16
+
17
+ def on_envelope(envelope)
18
+ case envelope.message
19
+ when :pause!
20
+ pause!
21
+ when :resume!
22
+ resume!
23
+ when :reset!
24
+ reset!
25
+ when :restart!
26
+ restart!
27
+ else
28
+ if @paused
29
+ @buffer << envelope
30
+ MESSAGE_PROCESSED
31
+ else
32
+ pass envelope
33
+ end
34
+ end
35
+ end
36
+
37
+ def pause!(error = nil)
38
+ @paused = true
39
+ broadcast(error || :paused)
40
+ true
41
+ end
42
+
43
+ def resume!(broadcast = true)
44
+ @paused = false
45
+ broadcast(:resumed) if broadcast
46
+ true
47
+ end
48
+
49
+ def reset!(broadcast = true)
50
+ core.allocate_context
51
+ core.build_context
52
+ resume!(false)
53
+ broadcast(:reset) if broadcast
54
+ true
55
+ end
56
+
57
+ def restart!
58
+ reset! false
59
+ broadcast(:restarted)
60
+ true
61
+ end
62
+
63
+ def on_event(event)
64
+ case event
65
+ when :terminated, :restarted
66
+ @buffer.each { |envelope| reject_envelope envelope }
67
+ @buffer.clear
68
+ when :resumed, :reset
69
+ @buffer.each { |envelope| core.schedule_execution { pass envelope } }
70
+ @buffer.clear
71
+ end
72
+ super event
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,16 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+ # Removes terminated children.
5
+ class RemovesChild < Abstract
6
+ def on_envelope(envelope)
7
+ if envelope.message == :remove_child
8
+ core.remove_child envelope.sender
9
+ else
10
+ pass envelope
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+ # Collects returning value and sets the IVar in the {Envelope} or error on failure.
5
+ class SetResults < Abstract
6
+ attr_reader :error_strategy
7
+
8
+ def initialize(core, subsequent, error_strategy)
9
+ super core, subsequent
10
+ @error_strategy = Match! error_strategy, :just_log, :terminate!, :pause!
11
+ end
12
+
13
+ def on_envelope(envelope)
14
+ result = pass envelope
15
+ if result != MESSAGE_PROCESSED && !envelope.ivar.nil?
16
+ envelope.ivar.set result
17
+ end
18
+ nil
19
+ rescue => error
20
+ log Logging::ERROR, error
21
+ case error_strategy
22
+ when :terminate!
23
+ terminate!
24
+ when :pause!
25
+ behaviour!(Pausing).pause!(error)
26
+ when :just_log
27
+ # nothing
28
+ else
29
+ raise
30
+ end
31
+ envelope.ivar.fail error unless envelope.ivar.nil?
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,58 @@
1
+ module Concurrent
2
+ module Actor
3
+ module Behaviour
4
+
5
+ # Sets nad holds the supervisor of the actor if any. There is only one or none supervisor
6
+ # for each actor. Each supervisor is automatically linked.
7
+ class Supervised < Abstract
8
+ attr_reader :supervisor
9
+
10
+ def initialize(core, subsequent)
11
+ super core, subsequent
12
+ @supervisor = nil
13
+ end
14
+
15
+ def on_envelope(envelope)
16
+ case envelope.message
17
+ when :supervise
18
+ supervise envelope.sender
19
+ when :supervisor
20
+ supervisor
21
+ when :un_supervise
22
+ un_supervise envelope.sender
23
+ when :pause!, :resume!, :reset!, :restart!
24
+ # allow only supervisor to control the actor
25
+ if @supervisor == envelope.sender
26
+ pass envelope
27
+ else
28
+ false
29
+ end
30
+ else
31
+ pass envelope
32
+ end
33
+ end
34
+
35
+ def supervise(ref)
36
+ @supervisor = ref
37
+ behaviour!(Linking).link ref
38
+ true
39
+ end
40
+
41
+ def un_supervise(ref)
42
+ if @supervisor == ref
43
+ behaviour!(Linking).unlink ref
44
+ @supervisor = nil
45
+ true
46
+ else
47
+ false
48
+ end
49
+ end
50
+
51
+ def on_event(event)
52
+ @supervisor = nil if event == :terminated
53
+ super event
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end