concurrent-ruby 0.7.0.rc1-x86-mingw32 → 0.7.0.rc2-x86-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 (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 +37 -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