celluloid 0.14.0 → 0.14.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/celluloid/actor.rb +3 -5
- data/lib/celluloid/condition.rb +32 -28
- data/lib/celluloid/future.rb +18 -27
- data/lib/celluloid/internal_pool.rb +11 -1
- data/lib/celluloid/proxies/future_proxy.rb +9 -1
- data/lib/celluloid/stack_dump.rb +1 -1
- data/lib/celluloid/system_events.rb +1 -0
- data/lib/celluloid/tasks/task_fiber.rb +3 -1
- data/lib/celluloid/tasks/task_thread.rb +1 -0
- data/lib/celluloid/thread.rb +9 -63
- data/lib/celluloid/thread_handle.rb +2 -1
- data/lib/celluloid/version.rb +1 -1
- data/spec/support/actor_examples.rb +0 -35
- metadata +29 -17
- checksums.yaml +0 -7
data/lib/celluloid/actor.rb
CHANGED
@@ -27,7 +27,7 @@ module Celluloid
|
|
27
27
|
# normal Ruby objects wrapped in threads which communicate with asynchronous
|
28
28
|
# messages.
|
29
29
|
class Actor
|
30
|
-
attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name
|
30
|
+
attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name
|
31
31
|
|
32
32
|
class << self
|
33
33
|
extend Forwardable
|
@@ -78,8 +78,7 @@ module Celluloid
|
|
78
78
|
def all
|
79
79
|
actors = []
|
80
80
|
Thread.list.each do |t|
|
81
|
-
next unless t.celluloid?
|
82
|
-
next if t.task
|
81
|
+
next unless t.celluloid? && t.role == :actor
|
83
82
|
actors << t.actor.proxy if t.actor && t.actor.respond_to?(:proxy)
|
84
83
|
end
|
85
84
|
actors
|
@@ -152,9 +151,8 @@ module Celluloid
|
|
152
151
|
@running = true
|
153
152
|
@exclusive = false
|
154
153
|
@name = nil
|
155
|
-
@locals = {}
|
156
154
|
|
157
|
-
@thread = ThreadHandle.new do
|
155
|
+
@thread = ThreadHandle.new(:actor) do
|
158
156
|
setup_thread
|
159
157
|
run
|
160
158
|
end
|
data/lib/celluloid/condition.rb
CHANGED
@@ -3,11 +3,30 @@ module Celluloid
|
|
3
3
|
|
4
4
|
# ConditionVariable-like signaling between tasks and actors
|
5
5
|
class Condition
|
6
|
+
class Waiter
|
7
|
+
def initialize(condition, task, mailbox)
|
8
|
+
@condition = condition
|
9
|
+
@task = task
|
10
|
+
@mailbox = mailbox
|
11
|
+
end
|
12
|
+
attr_reader :condition, :task
|
13
|
+
|
14
|
+
def <<(message)
|
15
|
+
@mailbox << message
|
16
|
+
end
|
17
|
+
|
18
|
+
def wait
|
19
|
+
message = @mailbox.receive do |msg|
|
20
|
+
msg.is_a?(SignalConditionRequest) && msg.task == Thread.current
|
21
|
+
end
|
22
|
+
message.value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
6
26
|
attr_reader :owner
|
7
27
|
|
8
28
|
def initialize
|
9
29
|
@mutex = Mutex.new
|
10
|
-
@owner = Thread.current[:celluloid_actor]
|
11
30
|
@tasks = []
|
12
31
|
end
|
13
32
|
|
@@ -15,14 +34,18 @@ module Celluloid
|
|
15
34
|
def wait
|
16
35
|
raise ConditionError, "cannot wait for signals while exclusive" if Celluloid.exclusive?
|
17
36
|
|
37
|
+
if Thread.current[:celluloid_actor]
|
38
|
+
task = Task.current
|
39
|
+
else
|
40
|
+
task = Thread.current
|
41
|
+
end
|
42
|
+
waiter = Waiter.new(self, task, Celluloid.mailbox)
|
43
|
+
|
18
44
|
@mutex.synchronize do
|
19
|
-
|
20
|
-
raise ConditionError, "can't wait for conditions outside actors" unless actor
|
21
|
-
raise ConditionError, "can't wait unless owner" unless actor == @owner
|
22
|
-
@tasks << Task.current
|
45
|
+
@tasks << waiter
|
23
46
|
end
|
24
47
|
|
25
|
-
result =
|
48
|
+
result = Celluloid.suspend :condwait, waiter
|
26
49
|
raise result if result.is_a? ConditionError
|
27
50
|
result
|
28
51
|
end
|
@@ -30,10 +53,8 @@ module Celluloid
|
|
30
53
|
# Send a signal to the first task waiting on this condition
|
31
54
|
def signal(value = nil)
|
32
55
|
@mutex.synchronize do
|
33
|
-
|
34
|
-
|
35
|
-
if task = @tasks.shift
|
36
|
-
@owner.mailbox << SignalConditionRequest.new(task, value)
|
56
|
+
if waiter = @tasks.shift
|
57
|
+
waiter << SignalConditionRequest.new(waiter.task, value)
|
37
58
|
else
|
38
59
|
Logger.debug("Celluloid::Condition signaled spuriously")
|
39
60
|
end
|
@@ -43,28 +64,11 @@ module Celluloid
|
|
43
64
|
# Broadcast a value to all waiting tasks
|
44
65
|
def broadcast(value = nil)
|
45
66
|
@mutex.synchronize do
|
46
|
-
|
47
|
-
|
48
|
-
@tasks.each { |task| @owner.mailbox << SignalConditionRequest.new(task, value) }
|
67
|
+
@tasks.each { |waiter| waiter << SignalConditionRequest.new(waiter.task, value) }
|
49
68
|
@tasks.clear
|
50
69
|
end
|
51
70
|
end
|
52
71
|
|
53
|
-
# Change the owner of this condition
|
54
|
-
def owner=(actor)
|
55
|
-
@mutex.synchronize do
|
56
|
-
if @owner != actor
|
57
|
-
@tasks.each do |task|
|
58
|
-
ex = ConditionError.new("ownership changed")
|
59
|
-
@owner.mailbox << SignalConditionRequest.new(task, ex)
|
60
|
-
end
|
61
|
-
@tasks.clear
|
62
|
-
end
|
63
|
-
|
64
|
-
@owner = actor
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
72
|
alias_method :inspect, :to_s
|
69
73
|
end
|
70
74
|
end
|
data/lib/celluloid/future.rb
CHANGED
@@ -4,38 +4,30 @@ module Celluloid
|
|
4
4
|
# Celluloid::Future objects allow methods and blocks to run in the
|
5
5
|
# background, their values requested later
|
6
6
|
class Future
|
7
|
+
def self.new(*args, &block)
|
8
|
+
return super unless block
|
9
|
+
|
10
|
+
future = new
|
11
|
+
Celluloid.internal_pool.get do
|
12
|
+
Thread.current.role = :future
|
13
|
+
begin
|
14
|
+
call = SyncCall.new(future, :call, args)
|
15
|
+
call.dispatch(block)
|
16
|
+
rescue
|
17
|
+
# Exceptions in blocks will get raised when the value is retrieved
|
18
|
+
end
|
19
|
+
end
|
20
|
+
future
|
21
|
+
end
|
22
|
+
|
7
23
|
attr_reader :address
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(*args, &block)
|
24
|
+
|
25
|
+
def initialize
|
11
26
|
@address = Celluloid.uuid
|
12
27
|
@mutex = Mutex.new
|
13
28
|
@ready = false
|
14
29
|
@result = nil
|
15
30
|
@forwards = nil
|
16
|
-
|
17
|
-
if block
|
18
|
-
@call = SyncCall.new(self, :call, args)
|
19
|
-
Celluloid.internal_pool.get do
|
20
|
-
begin
|
21
|
-
@call.dispatch(block)
|
22
|
-
rescue
|
23
|
-
# Exceptions in blocks will get raised when the value is retrieved
|
24
|
-
end
|
25
|
-
end
|
26
|
-
else
|
27
|
-
@call = nil
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Execute the given method in future context
|
32
|
-
def execute(receiver, method, args, block)
|
33
|
-
@mutex.synchronize do
|
34
|
-
raise "already calling" if @call
|
35
|
-
@call = SyncCall.new(self, method, args, block)
|
36
|
-
end
|
37
|
-
|
38
|
-
receiver << @call
|
39
31
|
end
|
40
32
|
|
41
33
|
# Check if this future has a value yet
|
@@ -49,7 +41,6 @@ module Celluloid
|
|
49
41
|
|
50
42
|
begin
|
51
43
|
@mutex.lock
|
52
|
-
raise "no call requested" unless @call
|
53
44
|
|
54
45
|
if @ready
|
55
46
|
ready = true
|
@@ -42,7 +42,7 @@ module Celluloid
|
|
42
42
|
if @pool.size >= @max_idle
|
43
43
|
thread[:celluloid_queue] << nil
|
44
44
|
else
|
45
|
-
thread
|
45
|
+
clean_thread_locals(thread)
|
46
46
|
@pool << thread
|
47
47
|
@idle_size += 1
|
48
48
|
@busy_size -= 1
|
@@ -69,6 +69,16 @@ module Celluloid
|
|
69
69
|
thread
|
70
70
|
end
|
71
71
|
|
72
|
+
# Clean the thread locals of an incoming thread
|
73
|
+
def clean_thread_locals(thread)
|
74
|
+
thread.keys.each do |key|
|
75
|
+
next if key == :celluloid_queue
|
76
|
+
|
77
|
+
# Ruby seems to lack an API for deleting thread locals. WTF, Ruby?
|
78
|
+
thread[key] = nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
72
82
|
def shutdown
|
73
83
|
@mutex.synchronize do
|
74
84
|
@max_idle = 0
|
@@ -17,8 +17,16 @@ module Celluloid
|
|
17
17
|
# FIXME: nicer exception
|
18
18
|
raise "Cannot use blocks with futures yet"
|
19
19
|
end
|
20
|
+
|
20
21
|
future = Future.new
|
21
|
-
|
22
|
+
call = SyncCall.new(future, meth, args, block)
|
23
|
+
|
24
|
+
begin
|
25
|
+
@mailbox << call
|
26
|
+
rescue MailboxError
|
27
|
+
raise DeadActorError, "attempted to call a dead actor"
|
28
|
+
end
|
29
|
+
|
22
30
|
future
|
23
31
|
end
|
24
32
|
end
|
data/lib/celluloid/stack_dump.rb
CHANGED
@@ -6,6 +6,8 @@ module Celluloid
|
|
6
6
|
|
7
7
|
def create
|
8
8
|
@fiber = Fiber.new do
|
9
|
+
# FIXME: cannot use the writer as specs run inside normal Threads
|
10
|
+
Thread.current[:celluloid_role] = :actor
|
9
11
|
yield
|
10
12
|
end
|
11
13
|
end
|
@@ -30,4 +32,4 @@ module Celluloid
|
|
30
32
|
# If we're getting this the task should already be dead
|
31
33
|
end
|
32
34
|
end
|
33
|
-
end
|
35
|
+
end
|
data/lib/celluloid/thread.rb
CHANGED
@@ -2,20 +2,19 @@ require 'celluloid/fiber'
|
|
2
2
|
|
3
3
|
module Celluloid
|
4
4
|
class Thread < ::Thread
|
5
|
-
# FIXME: these should be replaced using APIs on Celluloid::Thread itself
|
6
|
-
# e.g. Thread.current[:celluloid_actor] => Thread.current.actor
|
7
|
-
CELLULOID_LOCALS = [
|
8
|
-
:celluloid_actor,
|
9
|
-
:celluloid_mailbox,
|
10
|
-
:celluloid_queue,
|
11
|
-
:celluloid_task,
|
12
|
-
:celluloid_chain_id
|
13
|
-
]
|
14
|
-
|
15
5
|
def celluloid?
|
16
6
|
true
|
17
7
|
end
|
18
8
|
|
9
|
+
# Obtain the role of this thread
|
10
|
+
def role
|
11
|
+
self[:celluloid_role]
|
12
|
+
end
|
13
|
+
|
14
|
+
def role=(role)
|
15
|
+
self[:celluloid_role] = role
|
16
|
+
end
|
17
|
+
|
19
18
|
# Obtain the Celluloid::Actor object for this thread
|
20
19
|
def actor
|
21
20
|
self[:celluloid_actor]
|
@@ -35,58 +34,5 @@ module Celluloid
|
|
35
34
|
def call_chain_id
|
36
35
|
self[:celluloid_chain_id]
|
37
36
|
end
|
38
|
-
|
39
|
-
#
|
40
|
-
# Override default thread local behavior, making thread locals actor-local
|
41
|
-
#
|
42
|
-
|
43
|
-
# Obtain an actor-local value
|
44
|
-
def [](key)
|
45
|
-
actor = super(:celluloid_actor)
|
46
|
-
if !actor || CELLULOID_LOCALS.include?(key)
|
47
|
-
super(key)
|
48
|
-
else
|
49
|
-
actor.locals[key]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Set an actor-local value
|
54
|
-
def []=(key, value)
|
55
|
-
actor = self[:celluloid_actor]
|
56
|
-
if !actor || CELLULOID_LOCALS.include?(key)
|
57
|
-
super(key, value)
|
58
|
-
else
|
59
|
-
actor.locals[key] = value
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Obtain the keys to all actor-locals
|
64
|
-
def keys
|
65
|
-
actor = self[:celluloid_actor]
|
66
|
-
if actor
|
67
|
-
actor.locals.keys
|
68
|
-
else
|
69
|
-
super
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# Is the given actor local set?
|
74
|
-
def key?(key)
|
75
|
-
actor = self[:celluloid_actor]
|
76
|
-
if actor
|
77
|
-
actor.locals.has_key?(key)
|
78
|
-
else
|
79
|
-
super
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# Clear thread state so it can be reused via thread pools
|
84
|
-
def recycle
|
85
|
-
# This thread local mediates access to the others, so we must clear it first
|
86
|
-
self[:celluloid_actor] = nil
|
87
|
-
|
88
|
-
# Clearing :celluloid_queue would break the thread pool!
|
89
|
-
keys.each { |key| self[key] = nil unless key == :celluloid_queue }
|
90
|
-
end
|
91
37
|
end
|
92
38
|
end
|
@@ -3,11 +3,12 @@ module Celluloid
|
|
3
3
|
# accidentally do things to threads which have been returned to the pool,
|
4
4
|
# such as, say, killing them
|
5
5
|
class ThreadHandle
|
6
|
-
def initialize
|
6
|
+
def initialize(role = nil)
|
7
7
|
@mutex = Mutex.new
|
8
8
|
@join = ConditionVariable.new
|
9
9
|
|
10
10
|
@thread = Celluloid.internal_pool.get do
|
11
|
+
Thread.current.role = role
|
11
12
|
begin
|
12
13
|
yield
|
13
14
|
ensure
|
data/lib/celluloid/version.rb
CHANGED
@@ -323,41 +323,6 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
323
323
|
end
|
324
324
|
end
|
325
325
|
|
326
|
-
context "thread locals" do
|
327
|
-
let(:example_class) do
|
328
|
-
Class.new do
|
329
|
-
include included_module
|
330
|
-
task_class task_klass
|
331
|
-
|
332
|
-
def initialize(value)
|
333
|
-
Thread.current[:example_thread_local] = value
|
334
|
-
end
|
335
|
-
|
336
|
-
def value
|
337
|
-
Thread.current[:example_thread_local]
|
338
|
-
end
|
339
|
-
|
340
|
-
def deferred_value
|
341
|
-
defer do
|
342
|
-
Thread.current[:example_thread_local]
|
343
|
-
end
|
344
|
-
end
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
let(:example_value) { "foobar" }
|
349
|
-
|
350
|
-
it "preserves thread locals between tasks" do
|
351
|
-
actor = example_class.new(example_value)
|
352
|
-
actor.value.should eq example_value
|
353
|
-
end
|
354
|
-
|
355
|
-
it "isolates thread locals in defer blocks" do
|
356
|
-
actor = example_class.new(example_value)
|
357
|
-
actor.deferred_value.should eq nil
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
326
|
context :linking do
|
362
327
|
before :each do
|
363
328
|
@kevin = actor_class.new "Kevin Bacon" # Some six degrees action here
|
metadata
CHANGED
@@ -1,83 +1,94 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: celluloid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.14.
|
4
|
+
version: 0.14.1.pre
|
5
|
+
prerelease: 7
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Tony Arcieri
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-31 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: timers
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
|
-
- - '>='
|
19
|
+
- - ! '>='
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: 1.0.0
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
|
-
- - '>='
|
27
|
+
- - ! '>='
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 1.0.0
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: rake
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
30
34
|
requirements:
|
31
|
-
- - '>='
|
35
|
+
- - ! '>='
|
32
36
|
- !ruby/object:Gem::Version
|
33
37
|
version: '0'
|
34
38
|
type: :development
|
35
39
|
prerelease: false
|
36
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
37
42
|
requirements:
|
38
|
-
- - '>='
|
43
|
+
- - ! '>='
|
39
44
|
- !ruby/object:Gem::Version
|
40
45
|
version: '0'
|
41
46
|
- !ruby/object:Gem::Dependency
|
42
47
|
name: rspec
|
43
48
|
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
44
50
|
requirements:
|
45
|
-
- - '>='
|
51
|
+
- - ! '>='
|
46
52
|
- !ruby/object:Gem::Version
|
47
53
|
version: '0'
|
48
54
|
type: :development
|
49
55
|
prerelease: false
|
50
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
51
58
|
requirements:
|
52
|
-
- - '>='
|
59
|
+
- - ! '>='
|
53
60
|
- !ruby/object:Gem::Version
|
54
61
|
version: '0'
|
55
62
|
- !ruby/object:Gem::Dependency
|
56
63
|
name: guard-rspec
|
57
64
|
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
58
66
|
requirements:
|
59
|
-
- - '>='
|
67
|
+
- - ! '>='
|
60
68
|
- !ruby/object:Gem::Version
|
61
69
|
version: '0'
|
62
70
|
type: :development
|
63
71
|
prerelease: false
|
64
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
65
74
|
requirements:
|
66
|
-
- - '>='
|
75
|
+
- - ! '>='
|
67
76
|
- !ruby/object:Gem::Version
|
68
77
|
version: '0'
|
69
78
|
- !ruby/object:Gem::Dependency
|
70
79
|
name: benchmark_suite
|
71
80
|
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
72
82
|
requirements:
|
73
|
-
- - '>='
|
83
|
+
- - ! '>='
|
74
84
|
- !ruby/object:Gem::Version
|
75
85
|
version: '0'
|
76
86
|
type: :development
|
77
87
|
prerelease: false
|
78
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
79
90
|
requirements:
|
80
|
-
- - '>='
|
91
|
+
- - ! '>='
|
81
92
|
- !ruby/object:Gem::Version
|
82
93
|
version: '0'
|
83
94
|
description: Celluloid enables people to build concurrent programs out of concurrent
|
@@ -143,25 +154,26 @@ files:
|
|
143
154
|
homepage: https://github.com/celluloid/celluloid
|
144
155
|
licenses:
|
145
156
|
- MIT
|
146
|
-
metadata: {}
|
147
157
|
post_install_message:
|
148
158
|
rdoc_options: []
|
149
159
|
require_paths:
|
150
160
|
- lib
|
151
161
|
required_ruby_version: !ruby/object:Gem::Requirement
|
162
|
+
none: false
|
152
163
|
requirements:
|
153
|
-
- - '>='
|
164
|
+
- - ! '>='
|
154
165
|
- !ruby/object:Gem::Version
|
155
166
|
version: 1.9.2
|
156
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
168
|
+
none: false
|
157
169
|
requirements:
|
158
|
-
- - '>='
|
170
|
+
- - ! '>='
|
159
171
|
- !ruby/object:Gem::Version
|
160
172
|
version: 1.3.6
|
161
173
|
requirements: []
|
162
174
|
rubyforge_project:
|
163
|
-
rubygems_version:
|
175
|
+
rubygems_version: 1.8.23
|
164
176
|
signing_key:
|
165
|
-
specification_version:
|
177
|
+
specification_version: 3
|
166
178
|
summary: Actor-based concurrent object framework for Ruby
|
167
179
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 14c9f61bd8924c3c5ab4265d3a7ca3d6c43e0fcc
|
4
|
-
data.tar.gz: 65e57a0119a677575a6fbf1663717812f3ca5e1c
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: 0f92f13dde36f666893891344073856a4283c402bf259bffa6d076aec33d3c607805ca84373fba854d198b17fe27415eee41283485b7cc4957f715aff00e9f06
|
7
|
-
data.tar.gz: 4b1cd7b742b028163e9a1af68343b5f3489997ced697383ae9e1737d01f0d9b4f16bc3406e8ea22f8c8668533e4a1ca2cb5a3184ce4b0b5cd7481b3e33e0944d
|