concurrent-ruby 0.1.1.pre.2 → 0.1.1.pre.3

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.
@@ -11,16 +11,17 @@ require 'concurrent/future'
11
11
  require 'concurrent/goroutine'
12
12
  require 'concurrent/promise'
13
13
  require 'concurrent/obligation'
14
- require 'concurrent/reactor'
15
14
  require 'concurrent/smart_mutex'
16
15
  require 'concurrent/utilities'
17
16
 
18
- require 'concurrent/drb_async_demux'
19
- require 'concurrent/tcp_sync_demux'
17
+ require 'concurrent/reactor'
18
+ require 'concurrent/reactor/drb_async_demux'
19
+ require 'concurrent/reactor/tcp_sync_demux'
20
20
 
21
21
  require 'concurrent/thread_pool'
22
22
  require 'concurrent/cached_thread_pool'
23
23
  require 'concurrent/fixed_thread_pool'
24
+ require 'concurrent/null_thread_pool'
24
25
 
25
26
  require 'concurrent/global_thread_pool'
26
27
 
@@ -1,6 +1,7 @@
1
1
  require 'observer'
2
2
  require 'thread'
3
3
 
4
+ require 'concurrent/global_thread_pool'
4
5
  require 'concurrent/utilities'
5
6
 
6
7
  module Concurrent
@@ -13,6 +14,7 @@ module Concurrent
13
14
  # A good example of an agent is a shared incrementing counter, such as the score in a video game.
14
15
  class Agent
15
16
  include Observable
17
+ include UsesGlobalThreadPool
16
18
 
17
19
  TIMEOUT = 5
18
20
 
@@ -26,7 +28,7 @@ module Concurrent
26
28
  @validator = nil
27
29
  @queue = Queue.new
28
30
 
29
- @thread = Thread.new{ work }
31
+ Agent.thread_pool.post{ work }
30
32
  end
31
33
 
32
34
  def value(timeout = 0) return @value; end
@@ -7,6 +7,7 @@ module Concurrent
7
7
  IllegalMethodCallError = Class.new(StandardError)
8
8
 
9
9
  class Defer
10
+ include UsesGlobalThreadPool
10
11
 
11
12
  def initialize(opts = {}, &block)
12
13
  operation = opts[:op] || opts[:operation]
@@ -22,7 +23,7 @@ module Concurrent
22
23
  if operation.nil?
23
24
  @running = false
24
25
  else
25
- self.go(thread_pool)
26
+ self.go
26
27
  end
27
28
  end
28
29
 
@@ -44,12 +45,11 @@ module Concurrent
44
45
  alias_method :catch, :rescue
45
46
  alias_method :on_error, :rescue
46
47
 
47
- def go(thread_pool = nil)
48
+ def go
48
49
  return nil if @running
49
50
  atomic {
50
- thread_pool ||= $GLOBAL_THREAD_POOL
51
51
  @running = true
52
- thread_pool.post { Thread.pass; fulfill }
52
+ Defer.thread_pool.post { Thread.pass; fulfill }
53
53
  }
54
54
  return nil
55
55
  end
@@ -10,6 +10,8 @@ module Concurrent
10
10
  attr_reader :execution_interval
11
11
  attr_reader :timeout_interval
12
12
 
13
+ protected
14
+
13
15
  def initialize(name, execution_interval, timeout_interval, thread)
14
16
  @name = name
15
17
  @execution_interval = execution_interval
@@ -18,6 +20,8 @@ module Concurrent
18
20
  @thread[:stop] = false
19
21
  end
20
22
 
23
+ public
24
+
21
25
  def status
22
26
  return @thread.status unless @thread.nil?
23
27
  end
@@ -12,11 +12,11 @@ module Kernel
12
12
  end
13
13
  module_function :agent
14
14
 
15
- def post(agent, &block)
16
- if agent.respond_to?(:post)
17
- return agent.post(&block)
15
+ def post(object, &block)
16
+ if object.respond_to?(:post)
17
+ return object.post(&block)
18
18
  else
19
- return nil
19
+ raise ArgumentError.new('object does not support #post')
20
20
  end
21
21
  end
22
22
  module_function :post
@@ -44,53 +44,53 @@ module Kernel
44
44
 
45
45
  ## obligation
46
46
 
47
- def deref(obligation, timeout = nil)
48
- if obligation.respond_to?(:deref)
49
- return obligation.deref(timeout)
50
- elsif obligation.respond_to?(:value)
51
- return obligation.deref(timeout)
47
+ def deref(object, timeout = nil)
48
+ if object.respond_to?(:deref)
49
+ return object.deref(timeout)
50
+ elsif object.respond_to?(:value)
51
+ return object.value(timeout)
52
52
  else
53
- return nil
53
+ raise ArgumentError.new('object does not support #deref')
54
54
  end
55
55
  end
56
56
  module_function :deref
57
57
 
58
- def pending?(obligation)
59
- if obligation.respond_to?(:pending?)
60
- return obligation.pending?
58
+ def pending?(object)
59
+ if object.respond_to?(:pending?)
60
+ return object.pending?
61
61
  else
62
- return false
62
+ raise ArgumentError.new('object does not support #pending?')
63
63
  end
64
64
  end
65
65
  module_function :pending?
66
66
 
67
- def fulfilled?(obligation)
68
- if obligation.respond_to?(:fulfilled?)
69
- return obligation.fulfilled?
70
- elsif obligation.respond_to?(:realized?)
71
- return obligation.realized?
67
+ def fulfilled?(object)
68
+ if object.respond_to?(:fulfilled?)
69
+ return object.fulfilled?
70
+ elsif object.respond_to?(:realized?)
71
+ return object.realized?
72
72
  else
73
- return false
73
+ raise ArgumentError.new('object does not support #fulfilled?')
74
74
  end
75
75
  end
76
76
  module_function :fulfilled?
77
77
 
78
- def realized?(obligation)
79
- if obligation.respond_to?(:realized?)
80
- return obligation.realized?
81
- elsif obligation.respond_to?(:fulfilled?)
82
- return obligation.fulfilled?
78
+ def realized?(object)
79
+ if object.respond_to?(:realized?)
80
+ return object.realized?
81
+ elsif object.respond_to?(:fulfilled?)
82
+ return object.fulfilled?
83
83
  else
84
- return false
84
+ raise ArgumentError.new('object does not support #realized?')
85
85
  end
86
86
  end
87
87
  module_function :realized?
88
88
 
89
- def rejected?(obligation)
90
- if obligation.respond_to?(:rejected?)
91
- return obligation.rejected?
89
+ def rejected?(object)
90
+ if object.respond_to?(:rejected?)
91
+ return object.rejected?
92
92
  else
93
- return false
93
+ raise ArgumentError.new('object does not support #rejected?')
94
94
  end
95
95
  end
96
96
  module_function :rejected?
@@ -8,22 +8,17 @@ module Concurrent
8
8
 
9
9
  class Future
10
10
  include Obligation
11
+ include UsesGlobalThreadPool
12
+
11
13
  behavior(:future)
12
14
 
13
15
  def initialize(*args, &block)
14
- if args.first.behaves_as?(:global_thread_pool)
15
- thread_pool = args.first
16
- args = args.slice(1, args.length)
17
- else
18
- thread_pool = $GLOBAL_THREAD_POOL
19
- end
20
-
21
16
  unless block_given?
22
17
  @state = :fulfilled
23
18
  else
24
19
  @value = nil
25
20
  @state = :pending
26
- thread_pool.post do
21
+ Future.thread_pool.post(*args) do
27
22
  Thread.pass
28
23
  work(*args, &block)
29
24
  end
@@ -1,3 +1,16 @@
1
1
  require 'concurrent/cached_thread_pool'
2
2
 
3
3
  $GLOBAL_THREAD_POOL ||= Concurrent::CachedThreadPool.new
4
+
5
+ module Concurrent
6
+
7
+ module UsesGlobalThreadPool
8
+
9
+ def self.included(base)
10
+ class << base
11
+ attr_accessor :thread_pool
12
+ end
13
+ base.thread_pool = $GLOBAL_THREAD_POOL
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ require 'concurrent/global_thread_pool'
2
+
3
+ module Concurrent
4
+
5
+ class NullThreadPool
6
+ behavior(:global_thread_pool)
7
+
8
+ def self.post(*args, &block)
9
+ Thread.new(*args, &block)
10
+ return true
11
+ end
12
+
13
+ def post(*args, &block)
14
+ return NullThreadPool.post(*args, &block)
15
+ end
16
+
17
+ def <<(block)
18
+ NullThreadPool.post(&block)
19
+ return self
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,6 @@
1
1
  require 'thread'
2
2
 
3
+ require 'concurrent/global_thread_pool'
3
4
  require 'concurrent/obligation'
4
5
  require 'concurrent/utilities'
5
6
 
@@ -7,6 +8,8 @@ module Concurrent
7
8
 
8
9
  class Promise
9
10
  include Obligation
11
+ include UsesGlobalThreadPool
12
+
10
13
  behavior(:future)
11
14
  behavior(:promise)
12
15
 
@@ -90,15 +93,6 @@ module Concurrent
90
93
  # @private
91
94
  Rescuer = Struct.new(:clazz, :block)
92
95
 
93
- # @private
94
- def root # :nodoc:
95
- return atomic {
96
- current = self
97
- current = current.parent until current.root?
98
- current
99
- }
100
- end
101
-
102
96
  # @private
103
97
  def root? # :nodoc:
104
98
  @parent.nil?
@@ -148,7 +142,7 @@ module Concurrent
148
142
 
149
143
  # @private
150
144
  def realize(*args) # :nodoc:
151
- Thread.new(@chain, @mutex, args) do |chain, mutex, args|
145
+ Promise.thread_pool.post(@chain, @mutex, args) do |chain, mutex, args|
152
146
  result = args.length == 1 ? args.first : args
153
147
  index = 0
154
148
  loop do
@@ -0,0 +1,74 @@
1
+ require 'drb/drb'
2
+ require 'drb/acl'
3
+ require 'functional'
4
+ require 'concurrent/reactor'
5
+
6
+ module Concurrent
7
+ class Reactor
8
+
9
+ class DRbAsyncDemux
10
+
11
+ behavior(:async_event_demux)
12
+
13
+ DEFAULT_URI = 'druby://localhost:12345'
14
+ DEFAULT_ACL = %[allow all]
15
+
16
+ def initialize(opts = {})
17
+ @uri = opts[:uri] || DEFAULT_URI
18
+ @acl = ACL.new(opts[:acl] || DEFAULT_ACL)
19
+ end
20
+
21
+ def set_reactor(reactor)
22
+ raise ArgumentError.new('invalid reactor') unless reactor.behaves_as?(:demux_reactor)
23
+ @reactor = reactor
24
+ end
25
+
26
+ def start
27
+ DRb.install_acl(@acl)
28
+ @service = DRb.start_service(@uri, Demultiplexer.new(@reactor))
29
+ end
30
+
31
+ def stop
32
+ @service = DRb.stop_service
33
+ end
34
+
35
+ def stopped?
36
+ return @service.nil?
37
+ end
38
+
39
+ private
40
+
41
+ class Demultiplexer
42
+
43
+ def initialize(reactor)
44
+ @reactor = reactor
45
+ end
46
+
47
+ Concurrent::Reactor::RESERVED_EVENTS.each do |event|
48
+ define_method(event){|*args| false }
49
+ end
50
+
51
+ def method_missing(method, *args, &block)
52
+ (class << self; self; end).class_eval do
53
+ define_method(method) do |*args|
54
+ result = @reactor.handle(method, *args)
55
+ case result.first
56
+ when :ok
57
+ return result.last
58
+ when :ex
59
+ raise result.last
60
+ when :noop
61
+ raise NoMethodError.new("undefined method '#{method}' for #{self}")
62
+ else
63
+ raise DRb::DRbUnknownError.new("unexpected error when calling method '#{method}'")
64
+ end
65
+ end
66
+ end
67
+ self.send(method, *args)
68
+ end
69
+ end
70
+ end
71
+
72
+ DRbAsyncDemultiplexer = DRbAsyncDemux
73
+ end
74
+ end
@@ -0,0 +1,98 @@
1
+ require 'socket'
2
+ require 'drb/acl'
3
+ require 'functional'
4
+ require 'concurrent/reactor'
5
+
6
+ module Concurrent
7
+ class Reactor
8
+
9
+ class TcpSyncDemux
10
+
11
+ behavior(:sync_event_demux)
12
+
13
+ DEFAULT_HOST = '127.0.0.1'
14
+ DEFAULT_PORT = 12345
15
+ DEFAULT_ACL = %[allow all]
16
+
17
+ def initialize(opts = {})
18
+ @host = opts[:host] || DEFAULT_HOST
19
+ @port = opts[:port] || DEFAULT_PORT
20
+ @acl = ACL.new(opts[:acl] || DEFAULT_ACL)
21
+ end
22
+
23
+ def start
24
+ @server = TCPServer.new(@host, @port)
25
+ end
26
+
27
+ def stop
28
+ atomic {
29
+ @socket.close unless @socket.nil?
30
+ @server.close unless @server.nil?
31
+ @server = @socket = nil
32
+ }
33
+ end
34
+
35
+ def stopped?
36
+ return @server.nil?
37
+ end
38
+
39
+ def accept
40
+ @socket = @server.accept if @socket.nil?
41
+ return nil unless @acl.allow_socket?(@socket)
42
+ event, args = get_message(@socket)
43
+ return nil if event.nil?
44
+ return Reactor::EventContext.new(event, args)
45
+ end
46
+
47
+ def respond(result, message)
48
+ return nil if @socket.nil?
49
+ @socket.puts(format_message(result, message))
50
+ end
51
+
52
+ def close
53
+ @socket.close
54
+ @socket = nil
55
+ end
56
+
57
+ def self.format_message(event, *args)
58
+ args = args.reduce('') do |memo, arg|
59
+ memo << "#{arg}\r\n"
60
+ end
61
+ return ":#{event}\r\n#{args}\r\n"
62
+ end
63
+ def format_message(*args) self.class.format_message(*args); end
64
+
65
+ def self.parse_message(message)
66
+ return atomic {
67
+ event = message.first.match /^:?(\w+)/
68
+ event = event[1].to_s.downcase.to_sym unless event.nil?
69
+
70
+ args = message.slice(1, message.length) || []
71
+
72
+ [event, args]
73
+ }
74
+ end
75
+ def parse_message(*args) self.class.parse_message(*args); end
76
+
77
+ def self.get_message(socket)
78
+ message = []
79
+ while line = socket.gets
80
+ if line.nil? || (line = line.strip).empty?
81
+ break
82
+ else
83
+ message << line
84
+ end
85
+ end
86
+
87
+ if message.empty?
88
+ return nil
89
+ else
90
+ return parse_message(message)
91
+ end
92
+ end
93
+ def get_message(*args) self.class.get_message(*args); end
94
+ end
95
+
96
+ TcpSyncDemultiplexer = TcpSyncDemux
97
+ end
98
+ end