celluloid 0.14.0 → 0.14.1.pre
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.
- 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
|