celluloid 0.16.0.pre2 → 0.16.0.pre3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9c58eede0a8ebeb315bf6f2fa925e19173dd5e9
4
- data.tar.gz: 525f0ae4823a55ca1e23bf1ff5b6c8493592551f
3
+ metadata.gz: 4f7aa9e5aa8ef9c2cd0aaabdde975d786214410b
4
+ data.tar.gz: 993cfb53e3ec7f1c24308bf2339e2e60b63f21df
5
5
  SHA512:
6
- metadata.gz: 2ac75588d4accd17305ea04b6329563783db6972262584898e3143bdf6086ba47dc8bcf8c93ad6c7a8b44115c2c718fbcc615219da968ffdfa8a7a5f17b5f908
7
- data.tar.gz: e1185014388060dcd75a41b583a6df01f7bcbb37e21e1619091e364374cb861a31df7c7110b371887540c2482ff54cfae0cf7a3df534fc188157e220d5f8cd12
6
+ metadata.gz: 50e59017b92d0f00ff20d1f6a9e8ec436ca751e126df040d3f232d6e96bce43b532e666288f664b5cf2fc19c9bc12ccb45abcac0a6c09c72f0fc33eeb813ccbc
7
+ data.tar.gz: 95ec24381ebc52700045ecd4aeca559b7f2e4a304526d06198222eb357082dae0c1615afc9612741ca86b2308ff2f3dd0e2f77fae39078387eb3ae2901ba424c
@@ -7,7 +7,7 @@ module Celluloid
7
7
  # Expose all instance methods as singleton methods
8
8
  extend self
9
9
 
10
- VERSION = '0.16.0.pre2'
10
+ VERSION = '0.16.0.pre3'
11
11
 
12
12
  # Linking times out after 5 seconds
13
13
  LINKING_TIMEOUT = 5
@@ -112,8 +112,8 @@ module Celluloid
112
112
  @tasks = TaskSet.new
113
113
  @links = Links.new
114
114
  @signals = Signals.new
115
- @receivers = Receivers.new
116
115
  @timers = Timers::Group.new
116
+ @receivers = Receivers.new(@timers)
117
117
  @handlers = Handlers.new
118
118
  @running = false
119
119
  @name = nil
@@ -147,11 +147,15 @@ module Celluloid
147
147
  def run
148
148
  while @running
149
149
  begin
150
- message = @mailbox.receive(timeout_interval)
151
- handle_message message
152
- rescue TimeoutError
153
- @timers.fire
154
- @receivers.fire_timers
150
+ @timers.wait do |interval|
151
+ interval = 0 if interval and interval < 0
152
+
153
+ if message = @mailbox.check(interval)
154
+ handle_message(message)
155
+
156
+ break unless @running
157
+ end
158
+ end
155
159
  rescue MailboxShutdown
156
160
  @running = false
157
161
  end
@@ -171,12 +175,10 @@ module Celluloid
171
175
  # Perform a linking request with another actor
172
176
  def linking_request(receiver, type)
173
177
  Celluloid.exclusive do
174
- linking_timeout = Timers::Timeout.new(LINKING_TIMEOUT)
175
-
176
178
  receiver.mailbox << LinkingRequest.new(Actor.current, type)
177
179
  system_events = []
178
180
 
179
- linking_timeout.while_time_remaining do |remaining|
181
+ Timers::Wait.for(LINKING_TIMEOUT) do |remaining|
180
182
  begin
181
183
  message = @mailbox.receive(remaining) do |msg|
182
184
  msg.is_a?(LinkingResponse) &&
@@ -229,20 +231,6 @@ module Celluloid
229
231
  end
230
232
  end
231
233
 
232
- # How long to wait until the next timer fires
233
- def timeout_interval
234
- i1 = @timers.wait_interval
235
- i2 = @receivers.wait_interval
236
-
237
- if i1 and i2
238
- i1 < i2 ? i1 : i2
239
- elsif i1
240
- i1
241
- else
242
- i2
243
- end
244
- end
245
-
246
234
  # Schedule a block to run at the given time
247
235
  def after(interval, &block)
248
236
  @timers.after(interval) { task(:timer, &block) }
@@ -37,17 +37,18 @@ module Celluloid
37
37
  end
38
38
 
39
39
  # Receive a message from the Mailbox
40
- def receive(timeout = nil, &block)
40
+ def check(timeout = nil, &block)
41
41
  # Get a message if it is available and process it immediately if possible:
42
42
  if message = next_message(block)
43
43
  return message
44
44
  end
45
45
 
46
- # ... otherwise, run the reactor once, either blocking or will return after the given timeout.
46
+ # ... otherwise, run the reactor once, either blocking or will return
47
+ # after the given timeout:
47
48
  @reactor.run_once(timeout)
48
49
 
49
- # This is a hack to get the main Actor#run loop to recompute the timeout:
50
- raise TimeoutError
50
+ # No message was received:
51
+ return nil
51
52
  rescue IOError
52
53
  raise MailboxShutdown, "mailbox shutdown called during receive"
53
54
  end
@@ -7,7 +7,10 @@ module Celluloid
7
7
 
8
8
  def initialize
9
9
  @mutex = Mutex.new
10
- @threads = []
10
+ @idle_threads = []
11
+ @all_threads = []
12
+ @busy_size = 0
13
+ @idle_size = 0
11
14
 
12
15
  # TODO: should really adjust this based on usage
13
16
  @max_idle = 16
@@ -15,17 +18,15 @@ module Celluloid
15
18
  end
16
19
 
17
20
  def busy_size
18
- @threads.select(&:busy).size
21
+ @busy_size
19
22
  end
20
23
 
21
24
  def idle_size
22
- @threads.reject(&:busy).size
25
+ @idle_size
23
26
  end
24
27
 
25
28
  def assert_running
26
- unless running?
27
- raise Error, "Thread pool is not running"
28
- end
29
+ raise Error, "Thread pool is not running" unless running?
29
30
  end
30
31
 
31
32
  def assert_inactive
@@ -44,17 +45,15 @@ module Celluloid
44
45
  end
45
46
 
46
47
  def active?
47
- to_a.any?
48
+ busy_size + idle_size > 0
48
49
  end
49
50
 
50
51
  def each
51
- @threads.each do |thread|
52
- yield thread
53
- end
52
+ to_a.each {|thread| yield thread }
54
53
  end
55
54
 
56
55
  def to_a
57
- @threads
56
+ @mutex.synchronize { @all_threads.dup }
58
57
  end
59
58
 
60
59
  # Get a thread from the pool, running the given block
@@ -63,15 +62,16 @@ module Celluloid
63
62
  assert_running
64
63
 
65
64
  begin
66
- idle = @threads.reject(&:busy)
67
- if idle.empty?
65
+ if @idle_threads.empty?
68
66
  thread = create
69
67
  else
70
- thread = idle.first
68
+ thread = @idle_threads.pop
69
+ @idle_size = @idle_threads.length
71
70
  end
72
71
  end until thread.status # handle crashed threads
73
72
 
74
73
  thread.busy = true
74
+ @busy_size += 1
75
75
  thread[:celluloid_queue] << block
76
76
  thread
77
77
  end
@@ -81,15 +81,46 @@ module Celluloid
81
81
  def put(thread)
82
82
  @mutex.synchronize do
83
83
  thread.busy = false
84
- if idle_size >= @max_idle
84
+ if idle_size + 1 >= @max_idle
85
85
  thread[:celluloid_queue] << nil
86
- @threads.delete(thread)
86
+ @busy_size -= 1
87
+ @all_threads.delete(thread)
87
88
  else
89
+ @idle_threads.push thread
90
+ @busy_size -= 1
91
+ @idle_size = @idle_threads.length
88
92
  clean_thread_locals(thread)
89
93
  end
90
94
  end
91
95
  end
92
96
 
97
+ def shutdown
98
+ @mutex.synchronize do
99
+ finalize
100
+ @all_threads.each do |thread|
101
+ thread[:celluloid_queue] << nil
102
+ end
103
+ @all_threads.clear
104
+ @idle_threads.clear
105
+ @busy_size = 0
106
+ @idle_size = 0
107
+ end
108
+ end
109
+
110
+ def kill
111
+ @mutex.synchronize do
112
+ finalize
113
+ @running = false
114
+
115
+ @all_threads.shift.kill until @all_threads.empty?
116
+ @idle_threads.clear
117
+ @busy_size = 0
118
+ @idle_size = 0
119
+ end
120
+ end
121
+
122
+ private
123
+
93
124
  # Create a new thread with an associated queue of procs to run
94
125
  def create
95
126
  queue = Queue.new
@@ -106,7 +137,8 @@ module Celluloid
106
137
  end
107
138
 
108
139
  thread[:celluloid_queue] = queue
109
- @threads << thread
140
+ # @idle_threads << thread
141
+ @all_threads << thread
110
142
  thread
111
143
  end
112
144
 
@@ -120,26 +152,6 @@ module Celluloid
120
152
  end
121
153
  end
122
154
 
123
- def shutdown
124
- @mutex.synchronize do
125
- finalize
126
- @threads.each do |thread|
127
- thread[:celluloid_queue] << nil
128
- end
129
- end
130
- end
131
-
132
- def kill
133
- @mutex.synchronize do
134
- finalize
135
- @running = false
136
-
137
- @threads.shift.kill until @threads.empty?
138
- end
139
- end
140
-
141
- private
142
-
143
155
  def finalize
144
156
  @max_idle = 0
145
157
  end
@@ -45,36 +45,39 @@ module Celluloid
45
45
  end
46
46
  end
47
47
 
48
- # Receive a message from the Mailbox
49
- def receive(timeout = nil, &block)
48
+ # Receive a message from the Mailbox. May return nil and may return before
49
+ # the specified timeout.
50
+ def check(timeout = nil, &block)
50
51
  message = nil
51
52
 
52
53
  @mutex.lock
53
54
  begin
54
55
  raise MailboxDead, "attempted to receive from a dead mailbox" if @dead
55
56
 
56
- begin
57
+ Timers::Wait.for(timeout) do |remaining|
57
58
  message = next_message(&block)
58
59
 
59
- unless message
60
- if timeout
61
- # TODO: use hitimes/timers instead of Time.now
62
- now = Time.now
63
- wait_until ||= now + timeout
64
- wait_interval = wait_until - now
65
- raise(TimeoutError, "mailbox timeout exceeded", nil) if wait_interval <= 0
66
- else
67
- wait_interval = nil
68
- end
69
-
70
- @condition.wait(@mutex, wait_interval)
71
- end
72
- end until message
73
-
74
- message
60
+ break message if message
61
+
62
+ @condition.wait(@mutex, remaining)
63
+ end
75
64
  ensure
76
65
  @mutex.unlock rescue nil
77
66
  end
67
+
68
+ return message
69
+ end
70
+
71
+ # Receive a letter from the mailbox. Guaranteed to return a message. If
72
+ # timeout is exceeded, raise a TimeoutError.
73
+ def receive(timeout = nil, &block)
74
+ Timers::Wait.for(timeout) do |remaining|
75
+ if message = check(timeout, &block)
76
+ return message
77
+ end
78
+ end
79
+
80
+ raise TimeoutError.new("receive timeout exceeded")
78
81
  end
79
82
 
80
83
  # Shut down this mailbox and clean up its contents
@@ -5,9 +5,9 @@ require 'timers'
5
5
  module Celluloid
6
6
  # Allow methods to directly interact with the actor protocol
7
7
  class Receivers
8
- def initialize
8
+ def initialize(timers)
9
9
  @receivers = Set.new
10
- @timers = Timers::Group.new
10
+ @timers = timers
11
11
  end
12
12
 
13
13
  # Receive an asynchronous message
@@ -29,23 +29,13 @@ module Celluloid
29
29
  end
30
30
  end
31
31
 
32
- # How long to wait until the next timer fires
33
- def wait_interval
34
- @timers.wait_interval
35
- end
36
-
37
- # Fire any pending timers
38
- def fire_timers
39
- @timers.fire
40
- end
41
-
42
32
  # Handle incoming messages
43
33
  def handle_message(message)
44
34
  receiver = @receivers.find { |r| r.match(message) }
45
35
  return unless receiver
46
36
 
47
37
  @receivers.delete receiver
48
- @timers.cancel receiver.timer if receiver.timer
38
+ receiver.timer.cancel if receiver.timer
49
39
  receiver.resume message
50
40
  message
51
41
  end
@@ -48,6 +48,8 @@ module Celluloid
48
48
  @status = :running
49
49
  actor.setup_thread
50
50
 
51
+ name_current_thread thread_metadata
52
+
51
53
  Thread.current[:celluloid_task] = self
52
54
  CallChain.current_id = @chain_id
53
55
 
@@ -56,6 +58,7 @@ module Celluloid
56
58
  rescue Task::TerminatedError
57
59
  # Task was explicitly terminated
58
60
  ensure
61
+ name_current_thread nil
59
62
  @status = :dead
60
63
  actor.tasks.delete self
61
64
  end
@@ -147,6 +150,25 @@ module Celluloid
147
150
  raise message if $CELLULOID_DEBUG
148
151
  end
149
152
  end
153
+
154
+ private
155
+
156
+ def name_current_thread(new_name)
157
+ return unless RUBY_PLATFORM == "java"
158
+ if new_name.nil?
159
+ new_name = Thread.current[:celluloid_original_thread_name]
160
+ Thread.current[:celluloid_original_thread_name] = nil
161
+ else
162
+ Thread.current[:celluloid_original_thread_name] = Thread.current.to_java.getNativeThread.get_name
163
+ end
164
+ Thread.current.to_java.getNativeThread.set_name(new_name)
165
+ end
166
+
167
+ def thread_metadata
168
+ method = @meta && @meta[:method_name] || "<no method>"
169
+ klass = Thread.current[:celluloid_actor] && Thread.current[:celluloid_actor].behavior.subject.bare_object.class || "<no actor>"
170
+ format("[Celluloid] %s#%s", klass, method)
171
+ end
150
172
  end
151
173
  end
152
174
 
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ class EveryActor
4
+ include Celluloid
5
+
6
+ def initialize
7
+ @trace = []
8
+ @times = []
9
+ @start = Time.now
10
+
11
+ every(1) { log(1) }
12
+ every(2) { log(2) }
13
+ every(1) { log(11) }
14
+ every(2) { log(22) }
15
+ end
16
+
17
+ def log(t)
18
+ @trace << t
19
+
20
+ offset = Time.now - @start
21
+ @times << offset
22
+
23
+ # puts "log(#{t}) @ #{offset}"
24
+ end
25
+
26
+ attr :trace
27
+ attr :times
28
+ end
29
+
30
+ describe Celluloid::Actor do
31
+ it "run every(t) task several times" do
32
+ Celluloid.boot
33
+
34
+ every_actor = EveryActor.new
35
+
36
+ sleep 5.5
37
+
38
+ times = every_actor.times
39
+ trace = every_actor.trace
40
+
41
+ Celluloid.shutdown
42
+
43
+ expect(trace.count(1)).to be == 5
44
+ expect(trace.count(11)).to be == 5
45
+ expect(trace.count(2)).to be == 2
46
+ expect(trace.count(22)).to be == 2
47
+ end
48
+ end
@@ -285,6 +285,31 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
285
285
  actor.send('foo').should eq('oof')
286
286
  end
287
287
 
288
+ context "when executing under JRuby" do
289
+ let(:klass) {
290
+ Class.new do
291
+ include included_module
292
+ task_class task_klass
293
+
294
+ def current_thread_name
295
+ java_thread.get_name
296
+ end
297
+
298
+ def java_thread
299
+ Thread.current.to_java.getNativeThread
300
+ end
301
+ end
302
+ }
303
+
304
+ it "sets execution info" do
305
+ klass.new.current_thread_name.should == "Class#current_thread_name"
306
+ end
307
+
308
+ it "unsets execution info after task completion" do
309
+ klass.new.java_thread.get_name.should == "<unused>"
310
+ end
311
+ end if RUBY_PLATFORM == "java"
312
+
288
313
  context "mocking methods" do
289
314
  let(:actor) { actor_class.new "Troy McClure" }
290
315
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: celluloid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0.pre2
4
+ version: 0.16.0.pre3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Arcieri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-23 00:00:00.000000000 Z
11
+ date: 2014-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: timers
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 3.0.0
19
+ version: 4.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 3.0.0
26
+ version: 4.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -184,6 +184,7 @@ files:
184
184
  - spec/celluloid/tasks/task_fiber_spec.rb
185
185
  - spec/celluloid/tasks/task_thread_spec.rb
186
186
  - spec/celluloid/thread_handle_spec.rb
187
+ - spec/celluloid/timer_spec.rb
187
188
  - spec/celluloid/uuid_spec.rb
188
189
  - spec/spec_helper.rb
189
190
  - spec/support/actor_examples.rb
@@ -215,3 +216,4 @@ signing_key:
215
216
  specification_version: 4
216
217
  summary: Actor-based concurrent object framework for Ruby
217
218
  test_files: []
219
+ has_rdoc: