Skip to content

Commit

Permalink
'exclusive' class method
Browse files Browse the repository at this point in the history
The 'exclusive' method can be used to mark certain instance methods as
always running exclusive. This has the side effect (which so happens to
be the main use case) of running code outside of a Ruby Fiber, allowing
that code to consumer more stack space than the 4kB stacks of YARV
fibers would otherwise allow.
  • Loading branch information
tarcieri committed Jun 30, 2012
1 parent 9298dd7 commit ad678b1
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 2 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
@@ -1,3 +1,8 @@
HEAD
----
* 'exclusive' class method marks methods as always exclusive and runs them
outside of a Fiber (useful if you need more stack than Fibers provide)

0.11.0
------
* Celluloid::Application constant permanently removed
Expand Down
13 changes: 13 additions & 0 deletions lib/celluloid.rb
@@ -1,6 +1,7 @@
require 'logger'
require 'thread'
require 'timeout'
require 'set'

module Celluloid
SHUTDOWN_TIMEOUT = 120 # How long actors have to terminate
Expand Down Expand Up @@ -169,6 +170,13 @@ def use_mailbox(klass = nil, &block)
end
end

# Mark methods as running exclusively
def exclusive(*methods)
@exclusive_methods ||= Set.new
@exclusive_methods.merge methods.map(&:to_sym)
end
attr_reader :exclusive_methods

# Create a mailbox for this actor
def mailbox_factory
if defined?(@mailbox_factory)
Expand Down Expand Up @@ -297,6 +305,11 @@ def exclusive(&block)
Thread.current[:actor].exclusive(&block)
end

# Are we currently exclusive
def exclusive?
Celluloid.exclusive?
end

# Call a block after a given interval, returning a Celluloid::Timer object
def after(interval, &block)
Thread.current[:actor].after(interval, &block)
Expand Down
7 changes: 6 additions & 1 deletion lib/celluloid/actor.rb
Expand Up @@ -106,6 +106,7 @@ def initialize(subject)
@subject = subject
@mailbox = subject.class.mailbox_factory
@exit_handler = subject.class.exit_handler
@exclusives = subject.class.exclusive_methods

@tasks = Set.new
@links = Links.new
Expand Down Expand Up @@ -226,7 +227,11 @@ def sleep(interval)
def handle_message(message)
case message
when Call
Task.new(:message_handler) { message.dispatch(@subject) }.resume
if @exclusives && @exclusives.include?(message.method)
exclusive { message.dispatch(@subject) }
else
Task.new(:message_handler) { message.dispatch(@subject) }.resume
end
when Response
message.call.task.resume message
else
Expand Down
16 changes: 16 additions & 0 deletions spec/support/actor_examples.rb
Expand Up @@ -341,6 +341,22 @@ def signaled?; @signaled end
end
end

context :exclusive do
subject do
Class.new do
include included_module
def exclusive_example
exclusive?
end
exclusive :exclusive_example
end.new
end

it "supports exclusive methods" do
subject.exclusive_example.should be_true
end
end

context :receiving do
before do
@receiver = Class.new do
Expand Down
2 changes: 1 addition & 1 deletion spec/support/example_actor_class.rb
Expand Up @@ -76,4 +76,4 @@ def delegates?(method_name)
end
end
end
end
end

0 comments on commit ad678b1

Please sign in to comment.