celluloid 0.16.0.pre → 0.16.0
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 +4 -4
- data/README.md +0 -4
- data/lib/celluloid/actor.rb +27 -32
- data/lib/celluloid/call_chain.rb +1 -1
- data/lib/celluloid/cpu_counter.rb +28 -20
- data/lib/celluloid/evented_mailbox.rb +10 -17
- data/lib/celluloid/internal_pool.rb +49 -37
- data/lib/celluloid/mailbox.rb +22 -19
- data/lib/celluloid/pool_manager.rb +18 -1
- data/lib/celluloid/receivers.rb +4 -13
- data/{spec/support → lib/celluloid/rspec}/actor_examples.rb +25 -0
- data/lib/celluloid/rspec.rb +4 -3
- data/lib/celluloid/tasks/task_fiber.rb +1 -1
- data/lib/celluloid/tasks.rb +22 -0
- data/lib/celluloid.rb +1 -1
- data/spec/celluloid/cpu_counter_spec.rb +75 -2
- data/spec/celluloid/pool_spec.rb +33 -0
- data/spec/celluloid/stack_dump_spec.rb +4 -4
- data/spec/celluloid/timer_spec.rb +48 -0
- metadata +24 -9
- /data/{spec/support → lib/celluloid/rspec}/example_actor_class.rb +0 -0
- /data/{spec/support → lib/celluloid/rspec}/mailbox_examples.rb +0 -0
- /data/{spec/support → lib/celluloid/rspec}/task_examples.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6b9e9584ba72b44bbb2ce23372b0b4b86f2f3687
|
|
4
|
+
data.tar.gz: 10ec35b6465a1025defe4a697c3108f1982b5f77
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9394c33b6d7eff1efa0e0f78d24ff5578ce208dac695d0b7b806c999b47a456253c670783599ae448cb9bb3f6bf455be4ac66705fb399d8e53c3adb72a894250
|
|
7
|
+
data.tar.gz: f3e2659328cb38517ec107ad32e7c08d8aaa40fece3d74213273d50f703a6cb0878a43616d933b41fb6d061d928f02ba68850d269be32107062bc5e7b162bcc2
|
data/README.md
CHANGED
|
@@ -170,7 +170,3 @@ License
|
|
|
170
170
|
|
|
171
171
|
Copyright (c) 2011-2014 Tony Arcieri. Distributed under the MIT License. See
|
|
172
172
|
LICENSE.txt for further details.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
[](https://bitdeli.com/free "Bitdeli Badge")
|
|
176
|
-
|
data/lib/celluloid/actor.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
require 'timers'
|
|
2
3
|
|
|
3
4
|
module Celluloid
|
|
@@ -111,8 +112,8 @@ module Celluloid
|
|
|
111
112
|
@tasks = TaskSet.new
|
|
112
113
|
@links = Links.new
|
|
113
114
|
@signals = Signals.new
|
|
114
|
-
@
|
|
115
|
-
@
|
|
115
|
+
@timers = Timers::Group.new
|
|
116
|
+
@receivers = Receivers.new(@timers)
|
|
116
117
|
@handlers = Handlers.new
|
|
117
118
|
@running = false
|
|
118
119
|
@name = nil
|
|
@@ -146,11 +147,15 @@ module Celluloid
|
|
|
146
147
|
def run
|
|
147
148
|
while @running
|
|
148
149
|
begin
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
|
154
159
|
rescue MailboxShutdown
|
|
155
160
|
@running = false
|
|
156
161
|
end
|
|
@@ -170,31 +175,35 @@ module Celluloid
|
|
|
170
175
|
# Perform a linking request with another actor
|
|
171
176
|
def linking_request(receiver, type)
|
|
172
177
|
Celluloid.exclusive do
|
|
173
|
-
start_time = Time.now
|
|
174
178
|
receiver.mailbox << LinkingRequest.new(Actor.current, type)
|
|
175
179
|
system_events = []
|
|
176
180
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
Timers::Wait.for(LINKING_TIMEOUT) do |remaining|
|
|
182
|
+
begin
|
|
183
|
+
message = @mailbox.receive(remaining) do |msg|
|
|
184
|
+
msg.is_a?(LinkingResponse) &&
|
|
185
|
+
msg.actor.mailbox.address == receiver.mailbox.address &&
|
|
186
|
+
msg.type == type
|
|
187
|
+
end
|
|
188
|
+
rescue TimeoutError
|
|
189
|
+
next # IO reactor did something, no message in queue yet.
|
|
183
190
|
end
|
|
184
191
|
|
|
185
192
|
if message.instance_of? LinkingResponse
|
|
186
193
|
Celluloid::Probe.actors_linked(self, receiver) if $CELLULOID_MONITORING
|
|
194
|
+
|
|
187
195
|
# We're done!
|
|
188
196
|
system_events.each { |ev| @mailbox << ev }
|
|
197
|
+
|
|
189
198
|
return
|
|
190
|
-
elsif message.
|
|
191
|
-
raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
|
|
192
|
-
elsif message.instance_of? SystemEvent
|
|
199
|
+
elsif message.is_a? SystemEvent
|
|
193
200
|
# Queue up pending system events to be processed after we've successfully linked
|
|
194
201
|
system_events << message
|
|
195
|
-
else raise
|
|
202
|
+
else raise "Unexpected message type: #{message.class}. Expected LinkingResponse, NilClass, SystemEvent."
|
|
196
203
|
end
|
|
197
204
|
end
|
|
205
|
+
|
|
206
|
+
raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
|
|
198
207
|
end
|
|
199
208
|
end
|
|
200
209
|
|
|
@@ -222,20 +231,6 @@ module Celluloid
|
|
|
222
231
|
end
|
|
223
232
|
end
|
|
224
233
|
|
|
225
|
-
# How long to wait until the next timer fires
|
|
226
|
-
def timeout_interval
|
|
227
|
-
i1 = @timers.wait_interval
|
|
228
|
-
i2 = @receivers.wait_interval
|
|
229
|
-
|
|
230
|
-
if i1 and i2
|
|
231
|
-
i1 < i2 ? i1 : i2
|
|
232
|
-
elsif i1
|
|
233
|
-
i1
|
|
234
|
-
else
|
|
235
|
-
i2
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
|
|
239
234
|
# Schedule a block to run at the given time
|
|
240
235
|
def after(interval, &block)
|
|
241
236
|
@timers.after(interval) { task(:timer, &block) }
|
data/lib/celluloid/call_chain.rb
CHANGED
|
@@ -1,26 +1,34 @@
|
|
|
1
|
-
require 'rbconfig'
|
|
2
|
-
|
|
3
1
|
module Celluloid
|
|
4
2
|
module CPUCounter
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
when 'linux'
|
|
9
|
-
@cores = if File.exists?("/sys/devices/system/cpu/present")
|
|
10
|
-
File.read("/sys/devices/system/cpu/present").split('-').last.to_i+1
|
|
11
|
-
else
|
|
12
|
-
Dir["/sys/devices/system/cpu/cpu*"].select { |n| n=~/cpu\d+/ }.count
|
|
3
|
+
class << self
|
|
4
|
+
def cores
|
|
5
|
+
@cores ||= count_cores
|
|
13
6
|
end
|
|
14
|
-
when 'mingw', 'mswin'
|
|
15
|
-
@cores = Integer(ENV["NUMBER_OF_PROCESSORS"][/\d+/])
|
|
16
|
-
when 'freebsd'
|
|
17
|
-
@cores = Integer(`sysctl hw.ncpu`[/\d+/])
|
|
18
|
-
else
|
|
19
|
-
@cores = nil
|
|
20
|
-
end
|
|
21
7
|
|
|
22
|
-
|
|
23
|
-
end
|
|
24
|
-
end
|
|
8
|
+
private
|
|
25
9
|
|
|
10
|
+
def count_cores
|
|
11
|
+
result = from_env || from_sysdev || from_sysctl
|
|
12
|
+
Integer(result.to_s[/\d+/], 10) if result
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def from_env
|
|
16
|
+
result = ENV['NUMBER_OF_PROCESSORS']
|
|
17
|
+
result if result
|
|
18
|
+
end
|
|
26
19
|
|
|
20
|
+
def from_sysdev
|
|
21
|
+
::IO.read('/sys/devices/system/cpu/present').split('-').last.to_i + 1
|
|
22
|
+
rescue Errno::ENOENT
|
|
23
|
+
result = Dir['/sys/devices/system/cpu/cpu*'].count { |n| n =~ /cpu\d+/ }
|
|
24
|
+
result unless result.zero?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def from_sysctl
|
|
28
|
+
result = `sysctl -n hw.ncpu`
|
|
29
|
+
result if $?.success?
|
|
30
|
+
rescue Errno::ENOENT
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -37,25 +37,18 @@ module Celluloid
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
# Receive a message from the Mailbox
|
|
40
|
-
def
|
|
41
|
-
message
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if timeout
|
|
45
|
-
# TODO: use hitimes/timers instead of Time.now
|
|
46
|
-
now = Time.now
|
|
47
|
-
wait_until ||= now + timeout
|
|
48
|
-
wait_interval = wait_until - now
|
|
49
|
-
raise(TimeoutError, "mailbox timeout exceeded", nil) if wait_interval <= 0
|
|
50
|
-
else
|
|
51
|
-
wait_interval = nil
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
@reactor.run_once(wait_interval)
|
|
55
|
-
message = next_message(block)
|
|
40
|
+
def check(timeout = nil, &block)
|
|
41
|
+
# Get a message if it is available and process it immediately if possible:
|
|
42
|
+
if message = next_message(block)
|
|
43
|
+
return message
|
|
56
44
|
end
|
|
57
45
|
|
|
58
|
-
|
|
46
|
+
# ... otherwise, run the reactor once, either blocking or will return
|
|
47
|
+
# after the given timeout:
|
|
48
|
+
@reactor.run_once(timeout)
|
|
49
|
+
|
|
50
|
+
# No message was received:
|
|
51
|
+
return nil
|
|
59
52
|
rescue IOError
|
|
60
53
|
raise MailboxShutdown, "mailbox shutdown called during receive"
|
|
61
54
|
end
|
|
@@ -7,7 +7,10 @@ module Celluloid
|
|
|
7
7
|
|
|
8
8
|
def initialize
|
|
9
9
|
@mutex = Mutex.new
|
|
10
|
-
@
|
|
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
|
-
@
|
|
21
|
+
@busy_size
|
|
19
22
|
end
|
|
20
23
|
|
|
21
24
|
def idle_size
|
|
22
|
-
@
|
|
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
|
-
|
|
48
|
+
busy_size + idle_size > 0
|
|
48
49
|
end
|
|
49
50
|
|
|
50
51
|
def each
|
|
51
|
-
|
|
52
|
-
yield thread
|
|
53
|
-
end
|
|
52
|
+
to_a.each {|thread| yield thread }
|
|
54
53
|
end
|
|
55
54
|
|
|
56
55
|
def to_a
|
|
57
|
-
@
|
|
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
|
-
|
|
67
|
-
if idle.empty?
|
|
65
|
+
if @idle_threads.empty?
|
|
68
66
|
thread = create
|
|
69
67
|
else
|
|
70
|
-
thread =
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
data/lib/celluloid/mailbox.rb
CHANGED
|
@@ -45,36 +45,39 @@ module Celluloid
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
# Receive a message from the Mailbox
|
|
49
|
-
|
|
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
|
-
|
|
57
|
+
Timers::Wait.for(timeout) do |remaining|
|
|
57
58
|
message = next_message(&block)
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
@@ -24,7 +24,7 @@ module Celluloid
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def __shutdown__
|
|
27
|
-
terminators = (@idle + @busy).
|
|
27
|
+
terminators = (@idle + @busy).map do |actor|
|
|
28
28
|
begin
|
|
29
29
|
actor.future(:terminate)
|
|
30
30
|
rescue DeadActorError
|
|
@@ -81,6 +81,23 @@ module Celluloid
|
|
|
81
81
|
@size
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
def size=(new_size)
|
|
85
|
+
new_size = [0, new_size].max
|
|
86
|
+
|
|
87
|
+
if new_size > size
|
|
88
|
+
delta = new_size - size
|
|
89
|
+
delta.times { @idle << @worker_class.new_link(*@args) }
|
|
90
|
+
else
|
|
91
|
+
(size - new_size).times do
|
|
92
|
+
worker = __provision_worker__
|
|
93
|
+
unlink worker
|
|
94
|
+
@busy.delete worker
|
|
95
|
+
worker.terminate
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
@size = new_size
|
|
99
|
+
end
|
|
100
|
+
|
|
84
101
|
def busy_size
|
|
85
102
|
@busy.length
|
|
86
103
|
end
|
data/lib/celluloid/receivers.rb
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
require 'set'
|
|
2
|
+
|
|
2
3
|
require 'timers'
|
|
3
4
|
|
|
4
5
|
module Celluloid
|
|
5
6
|
# Allow methods to directly interact with the actor protocol
|
|
6
7
|
class Receivers
|
|
7
|
-
def initialize
|
|
8
|
+
def initialize(timers)
|
|
8
9
|
@receivers = Set.new
|
|
9
|
-
@timers =
|
|
10
|
+
@timers = timers
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
# Receive an asynchronous message
|
|
@@ -28,23 +29,13 @@ module Celluloid
|
|
|
28
29
|
end
|
|
29
30
|
end
|
|
30
31
|
|
|
31
|
-
# How long to wait until the next timer fires
|
|
32
|
-
def wait_interval
|
|
33
|
-
@timers.wait_interval
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Fire any pending timers
|
|
37
|
-
def fire_timers
|
|
38
|
-
@timers.fire
|
|
39
|
-
end
|
|
40
|
-
|
|
41
32
|
# Handle incoming messages
|
|
42
33
|
def handle_message(message)
|
|
43
34
|
receiver = @receivers.find { |r| r.match(message) }
|
|
44
35
|
return unless receiver
|
|
45
36
|
|
|
46
37
|
@receivers.delete receiver
|
|
47
|
-
|
|
38
|
+
receiver.timer.cancel if receiver.timer
|
|
48
39
|
receiver.resume message
|
|
49
40
|
message
|
|
50
41
|
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
|
|
data/lib/celluloid/rspec.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
1
|
+
require 'celluloid/rspec/example_actor_class'
|
|
2
|
+
require 'celluloid/rspec/actor_examples'
|
|
3
|
+
require 'celluloid/rspec/mailbox_examples'
|
|
4
|
+
require 'celluloid/rspec/task_examples'
|
|
4
5
|
|
|
5
6
|
module Celluloid
|
|
6
7
|
# Timer accuracy enforced by the tests (50ms)
|
|
@@ -37,7 +37,7 @@ module Celluloid
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def backtrace
|
|
40
|
-
"#{self.class} backtrace unavailable. Please try `Celluloid.task_class = Celluloid::TaskThread` if you need backtraces here."
|
|
40
|
+
["#{self.class} backtrace unavailable. Please try `Celluloid.task_class = Celluloid::TaskThread` if you need backtraces here."]
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
end
|
data/lib/celluloid/tasks.rb
CHANGED
|
@@ -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
|
|
data/lib/celluloid.rb
CHANGED
|
@@ -2,8 +2,81 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Celluloid::CPUCounter do
|
|
4
4
|
describe :cores do
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
subject { described_class.cores }
|
|
6
|
+
|
|
7
|
+
let(:num_cores) { 1024 }
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
described_class.stub(:`) { fail 'backtick stub called' }
|
|
11
|
+
::IO.stub(:open).and_raise('IO.open stub called!')
|
|
12
|
+
described_class.instance_variable_set('@cores', nil)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
after { ENV['NUMBER_OF_PROCESSORS'] = nil }
|
|
16
|
+
|
|
17
|
+
context 'from valid env value' do
|
|
18
|
+
before { ENV['NUMBER_OF_PROCESSORS'] = num_cores.to_s }
|
|
19
|
+
it { should eq num_cores }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context 'from invalid env value' do
|
|
23
|
+
before { ENV['NUMBER_OF_PROCESSORS'] = '' }
|
|
24
|
+
specify { expect { subject }.to raise_error(ArgumentError) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'with no env value' do
|
|
28
|
+
before { ENV['NUMBER_OF_PROCESSORS'] = nil }
|
|
29
|
+
|
|
30
|
+
context 'when /sys/devices/system/cpu/present exists' do
|
|
31
|
+
before do
|
|
32
|
+
::IO.should_receive(:read).with('/sys/devices/system/cpu/present')
|
|
33
|
+
.and_return("dunno-whatever-#{num_cores - 1}")
|
|
34
|
+
end
|
|
35
|
+
it { should eq num_cores }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context 'when /sys/devices/system/cpu/present does NOT exist' do
|
|
39
|
+
before do
|
|
40
|
+
::IO.should_receive(:read).with('/sys/devices/system/cpu/present')
|
|
41
|
+
.and_raise(Errno::ENOENT)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'when /sys/devices/system/cpu/cpu* files exist' do
|
|
45
|
+
before do
|
|
46
|
+
cpu_entries = (1..num_cores).map { |n| "cpu#{n}" }
|
|
47
|
+
cpu_entries << 'non-cpu-entry-to-ignore'
|
|
48
|
+
Dir.should_receive(:[]).with('/sys/devices/system/cpu/cpu*')
|
|
49
|
+
.and_return(cpu_entries)
|
|
50
|
+
end
|
|
51
|
+
it { should eq num_cores }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context 'when /sys/devices/system/cpu/cpu* files DO NOT exist' do
|
|
55
|
+
before do
|
|
56
|
+
Dir.should_receive(:[]).with('/sys/devices/system/cpu/cpu*')
|
|
57
|
+
.and_return([])
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'when sysctl blows up' do
|
|
61
|
+
before { described_class.stub(:`).and_raise(Errno::EINTR) }
|
|
62
|
+
specify { expect { subject }.to raise_error }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context 'when sysctl fails' do
|
|
66
|
+
before { described_class.stub(:`).and_return(`false`) }
|
|
67
|
+
it { should be nil }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context 'when sysctl succeeds' do
|
|
71
|
+
before do
|
|
72
|
+
described_class.should_receive(:`).with('sysctl -n hw.ncpu')
|
|
73
|
+
.and_return(num_cores.to_s)
|
|
74
|
+
`true`
|
|
75
|
+
end
|
|
76
|
+
it { should eq num_cores }
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
7
80
|
end
|
|
8
81
|
end
|
|
9
82
|
end
|
data/spec/celluloid/pool_spec.rb
CHANGED
|
@@ -14,11 +14,23 @@ describe "Celluloid.pool", actor_system: :global do
|
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
def sleepy_work
|
|
18
|
+
t = Time.now.to_f
|
|
19
|
+
sleep 0.25
|
|
20
|
+
t
|
|
21
|
+
end
|
|
22
|
+
|
|
17
23
|
def crash
|
|
18
24
|
raise ExampleError, "zomgcrash"
|
|
19
25
|
end
|
|
20
26
|
end
|
|
21
27
|
|
|
28
|
+
def test_concurrency_of(pool)
|
|
29
|
+
baseline = Time.now.to_f
|
|
30
|
+
values = 10.times.map { pool.future.sleepy_work }.map(&:value)
|
|
31
|
+
values.select {|t| t - baseline < 0.1 }.length
|
|
32
|
+
end
|
|
33
|
+
|
|
22
34
|
subject { MyWorker.pool }
|
|
23
35
|
|
|
24
36
|
it "processes work units synchronously" do
|
|
@@ -56,4 +68,25 @@ describe "Celluloid.pool", actor_system: :global do
|
|
|
56
68
|
end
|
|
57
69
|
futures.map(&:value)
|
|
58
70
|
end
|
|
71
|
+
|
|
72
|
+
context "#size=" do
|
|
73
|
+
subject { MyWorker.pool size: 4 }
|
|
74
|
+
|
|
75
|
+
it "should adjust the pool size up", pending: 'flaky' do
|
|
76
|
+
expect(test_concurrency_of(subject)).to eq(4)
|
|
77
|
+
|
|
78
|
+
subject.size = 6
|
|
79
|
+
subject.size.should == 6
|
|
80
|
+
|
|
81
|
+
test_concurrency_of(subject).should == 6
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "should adjust the pool size down" do
|
|
85
|
+
test_concurrency_of(subject).should == 4
|
|
86
|
+
|
|
87
|
+
subject.size = 2
|
|
88
|
+
subject.size.should == 2
|
|
89
|
+
test_concurrency_of(subject).should == 2
|
|
90
|
+
end
|
|
91
|
+
end
|
|
59
92
|
end
|
|
@@ -45,8 +45,8 @@ describe Celluloid::StackDump do
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
describe '#threads' do
|
|
48
|
-
it 'should include threads that are not actors' do
|
|
49
|
-
subject.threads.size.
|
|
48
|
+
it 'should include threads that are not actors', pending: 'flaky' do
|
|
49
|
+
expect(subject.threads.size).to eq(3)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
it 'should include idle threads' do
|
|
@@ -57,8 +57,8 @@ describe Celluloid::StackDump do
|
|
|
57
57
|
subject.threads.map(&:thread_id).should include(@active_thread.object_id)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
it 'should have the correct roles' do
|
|
61
|
-
subject.threads.map(&:role).
|
|
60
|
+
it 'should have the correct roles', pending: 'flaky' do
|
|
61
|
+
expect(subject.threads.map(&:role)).to include(nil, :other_thing, :task)
|
|
62
62
|
end
|
|
63
63
|
end
|
|
64
64
|
end
|
|
@@ -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
|
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
|
|
4
|
+
version: 0.16.0
|
|
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-
|
|
11
|
+
date: 2014-09-05 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:
|
|
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:
|
|
26
|
+
version: 4.0.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -80,6 +80,20 @@ dependencies:
|
|
|
80
80
|
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rubocop
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
83
97
|
description: Celluloid enables people to build concurrent programs out of concurrent
|
|
84
98
|
objects just as easily as they build sequential programs out of sequential objects
|
|
85
99
|
email:
|
|
@@ -133,6 +147,10 @@ files:
|
|
|
133
147
|
- lib/celluloid/registry.rb
|
|
134
148
|
- lib/celluloid/responses.rb
|
|
135
149
|
- lib/celluloid/rspec.rb
|
|
150
|
+
- lib/celluloid/rspec/actor_examples.rb
|
|
151
|
+
- lib/celluloid/rspec/example_actor_class.rb
|
|
152
|
+
- lib/celluloid/rspec/mailbox_examples.rb
|
|
153
|
+
- lib/celluloid/rspec/task_examples.rb
|
|
136
154
|
- lib/celluloid/signals.rb
|
|
137
155
|
- lib/celluloid/stack_dump.rb
|
|
138
156
|
- lib/celluloid/supervision_group.rb
|
|
@@ -170,12 +188,9 @@ files:
|
|
|
170
188
|
- spec/celluloid/tasks/task_fiber_spec.rb
|
|
171
189
|
- spec/celluloid/tasks/task_thread_spec.rb
|
|
172
190
|
- spec/celluloid/thread_handle_spec.rb
|
|
191
|
+
- spec/celluloid/timer_spec.rb
|
|
173
192
|
- spec/celluloid/uuid_spec.rb
|
|
174
193
|
- spec/spec_helper.rb
|
|
175
|
-
- spec/support/actor_examples.rb
|
|
176
|
-
- spec/support/example_actor_class.rb
|
|
177
|
-
- spec/support/mailbox_examples.rb
|
|
178
|
-
- spec/support/task_examples.rb
|
|
179
194
|
homepage: https://github.com/celluloid/celluloid
|
|
180
195
|
licenses:
|
|
181
196
|
- MIT
|
|
@@ -196,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
196
211
|
version: 1.3.6
|
|
197
212
|
requirements: []
|
|
198
213
|
rubyforge_project:
|
|
199
|
-
rubygems_version: 2.2.
|
|
214
|
+
rubygems_version: 2.2.2
|
|
200
215
|
signing_key:
|
|
201
216
|
specification_version: 4
|
|
202
217
|
summary: Actor-based concurrent object framework for Ruby
|
|
File without changes
|
|
File without changes
|
|
File without changes
|