lib/celluloid/actor.rb in celluloid-0.12.3 vs lib/celluloid/actor.rb in celluloid-0.12.4.pre
- old
+ new
@@ -19,10 +19,11 @@
super "caused by #{cause.inspect}: #{cause.to_s}"
end
end
LINKING_TIMEOUT = 5 # linking times out after 5 seconds
+ OWNER_IVAR = :@celluloid_owner # reference to owning actor
# Actors are Celluloid's concurrency primitive. They're implemented as
# normal Ruby objects wrapped in threads which communicate with asynchronous
# messages.
class Actor
@@ -41,18 +42,18 @@
Registry.root.clear
end
# Obtain the current actor
def current
- actor = Thread.current[:actor]
+ actor = Thread.current[:celluloid_actor]
raise NotActorError, "not in actor scope" unless actor
actor.proxy
end
# Obtain the name of the current actor
def name
- actor = Thread.current[:actor]
+ actor = Thread.current[:celluloid_actor]
raise NotActorError, "not in actor scope" unless actor
actor.name
end
# Invoke a method on the given actor via its mailbox
@@ -63,19 +64,19 @@
mailbox << call
rescue MailboxError
raise DeadActorError, "attempted to call a dead actor"
end
- if Thread.current[:task]
+ if Thread.current[:celluloid_task] && !Celluloid.exclusive?
Task.suspend(:callwait).value
else
response = loop do
message = Thread.mailbox.receive do |msg|
msg.respond_to?(:call) and msg.call == call
end
break message unless message.is_a?(SystemEvent)
- Thread.current[:actor].handle_system_event(message)
+ Thread.current[:celluloid_actor].handle_system_event(message)
end
response.value
end
end
@@ -101,48 +102,48 @@
# Obtain all running actors in the system
def all
actors = []
Thread.list.each do |t|
- actor = t[:actor]
+ actor = t[:celluloid_actor]
actors << actor.proxy if actor and actor.respond_to?(:proxy)
end
actors
end
# Watch for exit events from another actor
def monitor(actor)
raise NotActorError, "can't link outside actor context" unless Celluloid.actor?
- Thread.current[:actor].linking_request(actor, :link)
+ Thread.current[:celluloid_actor].linking_request(actor, :link)
end
# Stop waiting for exit events from another actor
def unmonitor(actor)
raise NotActorError, "can't link outside actor context" unless Celluloid.actor?
- Thread.current[:actor].linking_request(actor, :unlink)
+ Thread.current[:celluloid_actor].linking_request(actor, :unlink)
end
# Link to another actor
def link(actor)
monitor actor
- Thread.current[:actor].links << actor
+ Thread.current[:celluloid_actor].links << actor
end
# Unlink from another actor
def unlink(actor)
unmonitor actor
- Thread.current[:actor].links.delete actor
+ Thread.current[:celluloid_actor].links.delete actor
end
# Are we monitoring the given actor?
def monitoring?(actor)
actor.links.include? Actor.current
end
# Are we bidirectionally linked to the given actor?
def linked_to?(actor)
- monitoring?(actor) && Thread.current[:actor].links.include?(actor)
+ monitoring?(actor) && Thread.current[:celluloid_actor].links.include?(actor)
end
# Forcibly kill a given actor
def kill(actor)
actor.thread.kill
@@ -161,10 +162,11 @@
# Wrap the given subject with an Actor
def initialize(subject, options = {})
@subject = subject
@mailbox = options[:mailbox] || Mailbox.new
+ @proxy_class = options[:proxy_class] || ActorProxy
@exit_handler = options[:exit_handler]
@exclusives = options[:exclusive_methods]
@task_class = options[:task_class] || Celluloid.task_class
@tasks = Set.new
@@ -175,16 +177,17 @@
@running = true
@exclusive = false
@name = nil
@thread = ThreadHandle.new do
- Thread.current[:actor] = self
- Thread.current[:mailbox] = @mailbox
+ Thread.current[:celluloid_actor] = self
+ Thread.current[:celluloid_mailbox] = @mailbox
run
end
- @proxy = ActorProxy.new(self)
+ @proxy = @proxy_class.new(self)
+ @subject.instance_variable_set(OWNER_IVAR, self)
end
# Run the actor loop
def run
begin
@@ -304,11 +307,12 @@
@timers.every(interval) { task(:timer, &block) }
end
# Sleep for the given amount of time
def sleep(interval)
- if task = Thread.current[:task]
+ task = Thread.current[:celluloid_task]
+ if task && !Celluloid.exclusive?
@timers.after(interval) { task.resume }
Task.suspend :sleeping
else
Kernel.sleep(interval)
end
@@ -343,10 +347,12 @@
end
end
# Handle exit events received by this actor
def handle_exit_event(event)
+ @links.delete event.actor
+
# Run the exit handler if available
return @subject.send(@exit_handler, event.actor, event.reason) if @exit_handler
# Reraise exceptions from linked actors
# If no reason is given, actor terminated cleanly
@@ -364,11 +370,11 @@
# Handle cleaning up this actor after it exits
def shutdown(exit_event = ExitEvent.new(@proxy))
run_finalizer
cleanup exit_event
ensure
- Thread.current[:actor] = nil
- Thread.current[:mailbox] = nil
+ Thread.current[:celluloid_actor] = nil
+ Thread.current[:celluloid_mailbox] = nil
end
# Run the user-defined finalizer, if one is set
def run_finalizer
return unless @subject.respond_to? :finalize