kulesa-celluloid 0.10.2

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/README.md ADDED
@@ -0,0 +1,116 @@
1
+ ![Celluloid](https://github.com/celluloid/celluloid/raw/master/logo.png)
2
+ =========
3
+ [![Build Status](https://secure.travis-ci.org/celluloid/celluloid.png?branch=master)](http://travis-ci.org/celluloid/celluloid)
4
+ [![Dependency Status](https://gemnasium.com/celluloid/celluloid.png)](https://gemnasium.com/celluloid/celluloid)
5
+
6
+ > "I thought of objects being like biological cells and/or individual
7
+ > computers on a network, only able to communicate with messages"
8
+ > _--Alan Kay, creator of Smalltalk, on the meaning of "object oriented programming"_
9
+
10
+ Celluloid provides a simple and natural way to build fault-tolerant concurrent
11
+ programs in Ruby. With Celluloid, you can build systems out of concurrent
12
+ objects just as easily as you build sequential programs out of regular objects.
13
+ Recommended for any developer, including novices, Celluloid should help ease
14
+ your worries about building multithreaded Ruby programs.
15
+
16
+ Much of the difficulty with building concurrent programs in Ruby arises because
17
+ the object-oriented mechanisms for structuring code, such as classes and
18
+ inheritance, are separate from the concurrency mechanisms, such as threads and
19
+ locks. Celluloid combines these into a single structure, an active object
20
+ running within a thread, called an "actor".
21
+
22
+ By combining concurrency with object oriented programming, Celluloid frees you
23
+ up from worry about where to use threads and locks. Celluloid combines them
24
+ together into a single concurrent object oriented programming model,
25
+ encapsulating state in concurrent objects and thus avoiding many of the
26
+ problems associated with multithreaded programming. Celluloid provides many
27
+ features which make concurrent programming simple, easy, and fun:
28
+
29
+ * __Automatic "deadlock-free" synchronization:__ Celluloid uses a concurrent
30
+ object model which combines method dispatch and thread synchronization.
31
+ Each actor is a concurrent object running in its own thread, and every method
32
+ invocation is wrapped in a fiber that can be suspended whenever it calls
33
+ out to other actors, and resumed when the response is available. This means
34
+ methods which are waiting for responses from other actors, external messages,
35
+ or other system events (including I/O with Celluloid::IO) can be suspended
36
+ and will never block other methods that are ready to run. This won't prevent
37
+ bugs in Celluloid, bugs in other thread-safe libraries you use, and even
38
+ certain "dangerous" features of Celluloid from causing your program to
39
+ deadlock, but in general, programs built with Celluloid will be naturally
40
+ immune to deadlocks.
41
+
42
+ * __Fault-tolerance:__ Celluloid has taken to heart many of Erlang's ideas
43
+ about fault-tolerance in order to enable self-healing applications.
44
+ The central idea: have you tried turning it off and on again? Celluloid
45
+ takes care of rebooting subcomponents of your application when they crash,
46
+ whether it's a single actor, or large (potentially multi-tiered) groups of
47
+ actors that are all interdependent. This means rather that worrying about
48
+ rescuing every last exception, you can just sit back, relax, and let parts
49
+ of your program crash, knowing Celluloid will automatically reboot them in
50
+ a clean state. Celluloid provides its own implementation of the core
51
+ fault-tolerance concepts in Erlang including [linking](https://github.com/celluloid/celluloid/wiki/Linking),
52
+ [supervisors](https://github.com/celluloid/celluloid/wiki/Supervisors),
53
+ and [supervision trees](https://github.com/celluloid/celluloid/wiki/Groups).
54
+
55
+ * __[Futures](https://github.com/celluloid/celluloid/wiki/futures):__
56
+ Ever wanted to call a method "in the background" and retrieve the
57
+ value it returns later? Celluloid futures do just that. It's like
58
+ calling ahead to a restaurant to place an order, so they can work
59
+ on preparing your food while you're on your way to pick it up.
60
+ When you ask for a method's return value, it's returned immediately
61
+ if the method has already completed, or otherwise the current method is
62
+ suspended until the value becomes available.
63
+
64
+ You can also build distributed systems with Celluloid using its
65
+ [sister project DCell](https://github.com/celluloid/dcell). Evented IO similar
66
+ to EventMachine (with a synchronous API) is available through the
67
+ [Celluloid::IO](https://github.com/celluloid/celluloid-io) library.
68
+
69
+ [Please see the Celluloid Wiki](https://github.com/celluloid/celluloid/wiki)
70
+ for more detailed documentation and usage notes.
71
+
72
+ Like Celluloid? [Join the Google Group](http://groups.google.com/group/celluloid-ruby)
73
+ or visit us on IRC at #celluloid on freenode
74
+
75
+ ### Is it any good?
76
+
77
+ [Yes.](http://news.ycombinator.com/item?id=3067434)
78
+
79
+ ### Is It "Production Ready™"?
80
+
81
+ Yes, many users are now running Celluloid in production by using
82
+ [Sidekiq](https://github.com/mperham/sidekiq)
83
+
84
+ Supported Platforms
85
+ -------------------
86
+
87
+ Celluloid works on Ruby 1.9.3, JRuby 1.6, and Rubinius 2.0. JRuby or Rubinius
88
+ are the preferred platforms as they support true thread-level parallelism when
89
+ executing Ruby code, whereas MRI/YARV is constrained by a global interpreter
90
+ lock (GIL) and can only execute one thread at a time.
91
+
92
+ Celluloid requires Ruby 1.9 mode on all interpreters. This works out of the
93
+ box on MRI/YARV, and requires the following flags elsewhere:
94
+
95
+ * JRuby: --1.9 command line option, or JRUBY_OPTS=--1.9 environment variable
96
+ * rbx: -X19 command line option
97
+
98
+ Additional Reading
99
+ ------------------
100
+
101
+ * [Concurrent Object-Oriented Programming in Python with ATOM](http://python.org/workshops/1997-10/proceedings/atom/):
102
+ a similar system to Celluloid written in Python
103
+
104
+ Contributing to Celluloid
105
+ -------------------------
106
+
107
+ * Fork this repository on github
108
+ * Make your changes and send me a pull request
109
+ * If I like them I'll merge them
110
+ * If I've accepted a patch, feel free to ask for commit access
111
+
112
+ License
113
+ -------
114
+
115
+ Copyright (c) 2012 Tony Arcieri. Distributed under the MIT License. See
116
+ LICENSE.txt for further details.
@@ -0,0 +1,279 @@
1
+ module Celluloid
2
+ # Don't do Actor-like things outside Actor scope
3
+ class NotActorError < StandardError; end
4
+
5
+ # Trying to do something to a dead actor
6
+ class DeadActorError < StandardError; end
7
+
8
+ # The caller made an error, not the current actor
9
+ class AbortError < StandardError
10
+ attr_reader :cause
11
+
12
+ def initialize(cause)
13
+ @cause = cause
14
+ super "caused by #{cause.inspect}: #{cause.to_s}"
15
+ end
16
+ end
17
+
18
+ # Actors are Celluloid's concurrency primitive. They're implemented as
19
+ # normal Ruby objects wrapped in threads which communicate with asynchronous
20
+ # messages.
21
+ class Actor
22
+ extend Registry
23
+ attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name
24
+
25
+ class << self
26
+ # Obtain the current actor
27
+ def current
28
+ actor = Thread.current[:actor]
29
+ raise NotActorError, "not in actor scope" unless actor
30
+ actor.proxy
31
+ end
32
+
33
+ # Obtain the name of the current actor
34
+ def name
35
+ actor = Thread.current[:actor]
36
+ raise NotActorError, "not in actor scope" unless actor
37
+ actor.name
38
+ end
39
+
40
+ # Invoke a method on the given actor via its mailbox
41
+ def call(mailbox, meth, *args, &block)
42
+ call = SyncCall.new(Thread.mailbox, meth, args, block)
43
+
44
+ begin
45
+ mailbox << call
46
+ rescue MailboxError
47
+ raise DeadActorError, "attempted to call a dead actor"
48
+ end
49
+
50
+ if Celluloid.actor? and not Celluloid.exclusive?
51
+ # The current task will be automatically resumed when we get a response
52
+ Task.suspend(:callwait).value
53
+ else
54
+ # Otherwise we're inside a normal thread, so block
55
+ response = Thread.mailbox.receive do |msg|
56
+ msg.respond_to?(:call) and msg.call == call
57
+ end
58
+
59
+ response.value
60
+ end
61
+ end
62
+
63
+ # Invoke a method asynchronously on an actor via its mailbox
64
+ def async(mailbox, meth, *args, &block)
65
+ begin
66
+ mailbox << AsyncCall.new(Thread.mailbox, meth, args, block)
67
+ rescue MailboxError
68
+ # Silently swallow asynchronous calls to dead actors. There's no way
69
+ # to reliably generate DeadActorErrors for async calls, so users of
70
+ # async calls should find other ways to deal with actors dying
71
+ # during an async call (i.e. linking/supervisors)
72
+ end
73
+ end
74
+
75
+ # Call a method asynchronously and retrieve its value later
76
+ def future(mailbox, meth, *args, &block)
77
+ future = Future.new
78
+ future.execute(mailbox, meth, args, block)
79
+ future
80
+ end
81
+
82
+ # Obtain all running actors in the system
83
+ def all
84
+ actors = []
85
+ Thread.list.each do |t|
86
+ actor = t[:actor]
87
+ actors << actor.proxy if actor
88
+ end
89
+ actors
90
+ end
91
+ end
92
+
93
+ # Wrap the given subject with an Actor
94
+ def initialize(subject)
95
+ @subject = subject
96
+ @mailbox = subject.class.mailbox_factory
97
+ @tasks = Set.new
98
+ @links = Links.new
99
+ @signals = Signals.new
100
+ @receivers = Receivers.new
101
+ @timers = Timers.new
102
+ @running = true
103
+ @exclusive = false
104
+ @name = nil
105
+
106
+ @thread = ThreadHandle.new do
107
+ Thread.current[:actor] = self
108
+ Thread.current[:mailbox] = @mailbox
109
+ run
110
+ end
111
+
112
+ @proxy = ActorProxy.new(self)
113
+ end
114
+
115
+ # Is this actor running in exclusive mode?
116
+ def exclusive?
117
+ @exclusive
118
+ end
119
+
120
+ # Execute a code block in exclusive mode.
121
+ def exclusive
122
+ @exclusive = true
123
+ yield
124
+ ensure
125
+ @exclusive = false
126
+ end
127
+
128
+ # Terminate this actor
129
+ def terminate
130
+ @running = false
131
+ end
132
+
133
+ # Send a signal with the given name to all waiting methods
134
+ def signal(name, value = nil)
135
+ @signals.send name, value
136
+ end
137
+
138
+ # Wait for the given signal
139
+ def wait(name)
140
+ @signals.wait name
141
+ end
142
+
143
+ # Receive an asynchronous message
144
+ def receive(timeout = nil, &block)
145
+ @receivers.receive(timeout, &block)
146
+ end
147
+
148
+ # Run the actor loop
149
+ def run
150
+ begin
151
+ while @running
152
+ begin
153
+ message = @mailbox.receive(timeout)
154
+ rescue ExitEvent => exit_event
155
+ Task.new(:exit_handler) { handle_exit_event exit_event }.resume
156
+ retry
157
+ rescue NamingRequest => ex
158
+ @name = ex.name
159
+ retry
160
+ rescue TerminationRequest
161
+ break
162
+ end
163
+
164
+ if message
165
+ handle_message message
166
+ else
167
+ # No message indicates a timeout
168
+ @timers.fire
169
+ @receivers.fire_timers
170
+ end
171
+ end
172
+ rescue MailboxShutdown
173
+ # If the mailbox detects shutdown, exit the actor
174
+ end
175
+
176
+ shutdown
177
+ rescue Exception => ex
178
+ handle_crash(ex)
179
+ raise unless ex.is_a? StandardError
180
+ end
181
+
182
+ # How long to wait until the next timer fires
183
+ def timeout
184
+ i1 = @timers.wait_interval
185
+ i2 = @receivers.wait_interval
186
+
187
+ if i1 and i2
188
+ i1 < i2 ? i1 : i2
189
+ elsif i1
190
+ i1
191
+ else
192
+ i2
193
+ end
194
+ end
195
+
196
+ # Schedule a block to run at the given time
197
+ def after(interval)
198
+ @timers.add(interval) do
199
+ Task.new(:timer) { yield }.resume
200
+ end
201
+ end
202
+
203
+ # Schedule a block to run at the given time
204
+ def every(interval)
205
+ @timers.add(interval, true) do
206
+ Task.new(:timer) { yield }.resume
207
+ end
208
+ end
209
+
210
+ # Sleep for the given amount of time
211
+ def sleep(interval)
212
+ if Celluloid.exclusive?
213
+ Kernel.sleep(interval)
214
+ else
215
+ task = Task.current
216
+ @timers.add(interval) { task.resume }
217
+ Task.suspend :sleeping
218
+ end
219
+ end
220
+
221
+ # Handle an incoming message
222
+ def handle_message(message)
223
+ case message
224
+ when Call
225
+ Task.new(:message_handler) { message.dispatch(@subject) }.resume
226
+ when Response
227
+ message.call.task.resume message
228
+ else
229
+ @receivers.handle_message(message)
230
+ end
231
+ message
232
+ end
233
+
234
+ # Handle exit events received by this actor
235
+ def handle_exit_event(exit_event)
236
+ exit_handler = @subject.class.exit_handler
237
+ if exit_handler
238
+ return @subject.send(exit_handler, exit_event.actor, exit_event.reason)
239
+ end
240
+
241
+ # Reraise exceptions from linked actors
242
+ # If no reason is given, actor terminated cleanly
243
+ raise exit_event.reason if exit_event.reason
244
+ end
245
+
246
+ # Handle any exceptions that occur within a running actor
247
+ def handle_crash(exception)
248
+ Logger.crash("#{@subject.class} crashed!", exception)
249
+ shutdown ExitEvent.new(@proxy, exception)
250
+ rescue => ex
251
+ Logger.crash("#{@subject.class}: ERROR HANDLER CRASHED!", ex)
252
+ end
253
+
254
+ # Handle cleaning up this actor after it exits
255
+ def shutdown(exit_event = ExitEvent.new(@proxy))
256
+ run_finalizer
257
+ cleanup exit_event
258
+ ensure
259
+ Thread.current[:actor] = nil
260
+ Thread.current[:mailbox] = nil
261
+ end
262
+
263
+ # Run the user-defined finalizer, if one is set
264
+ def run_finalizer
265
+ @subject.finalize if @subject.respond_to? :finalize
266
+ rescue => ex
267
+ Logger.crash("#{@subject.class}#finalize crashed!", ex)
268
+ end
269
+
270
+ # Clean up after this actor
271
+ def cleanup(exit_event)
272
+ @mailbox.shutdown
273
+ @links.send_event exit_event
274
+ tasks.each { |task| task.terminate }
275
+ rescue => ex
276
+ Logger.crash("#{@subject.class}: CLEANUP CRASHED!", ex)
277
+ end
278
+ end
279
+ end
@@ -0,0 +1,95 @@
1
+ module Celluloid
2
+ # A proxy object returned from Celluloid::Actor.spawn/spawn_link which
3
+ # dispatches calls and casts to normal Ruby objects which are running inside
4
+ # of their own threads.
5
+ class ActorProxy
6
+ attr_reader :mailbox
7
+
8
+ def initialize(actor)
9
+ @mailbox, @thread, @klass = actor.mailbox, actor.thread, actor.subject.class.to_s
10
+
11
+ # Cache "unbanged" versions of methods, e.g. :foobar! => :foobar
12
+ @unbanged_methods = {}
13
+ end
14
+
15
+ def _send_(meth, *args, &block)
16
+ Actor.call @mailbox, :__send__, meth, *args, &block
17
+ end
18
+
19
+ def class
20
+ Actor.call @mailbox, :__send__, :class
21
+ end
22
+
23
+ def name
24
+ Actor.call @mailbox, :name
25
+ end
26
+
27
+ def is_a?(klass)
28
+ Actor.call @mailbox, :is_a?, klass
29
+ end
30
+
31
+ def kind_of?(klass)
32
+ Actor.call @mailbox, :kind_of?, klass
33
+ end
34
+
35
+ def respond_to?(meth)
36
+ Actor.call @mailbox, :respond_to?, meth
37
+ end
38
+
39
+ def methods(include_ancestors = true)
40
+ Actor.call @mailbox, :methods, include_ancestors
41
+ end
42
+
43
+ def alive?
44
+ @mailbox.alive?
45
+ end
46
+
47
+ def to_s
48
+ Actor.call @mailbox, :to_s
49
+ end
50
+
51
+ def inspect
52
+ Actor.call @mailbox, :inspect
53
+ rescue DeadActorError
54
+ "#<Celluloid::Actor(#{@klass}) dead>"
55
+ end
56
+
57
+ # Make an asynchronous call to an actor, for those who don't like the
58
+ # predicate syntax. TIMTOWTDI!
59
+ def async(method_name, *args, &block)
60
+ Actor.async @mailbox, method_name, *args, &block
61
+ end
62
+
63
+ # Create a Celluloid::Future which calls a given method
64
+ def future(method_name, *args, &block)
65
+ Actor.future @mailbox, method_name, *args, &block
66
+ end
67
+
68
+ # Terminate the associated actor
69
+ def terminate
70
+ terminate!
71
+ Thread.pass while alive?
72
+ end
73
+
74
+ # Terminate the associated actor asynchronously
75
+ def terminate!
76
+ raise DeadActorError, "actor already terminated" unless alive?
77
+ @mailbox.system_event TerminationRequest.new
78
+ end
79
+
80
+ # method_missing black magic to call bang predicate methods asynchronously
81
+ def method_missing(meth, *args, &block)
82
+ # bang methods are async calls
83
+ if meth.match(/!$/)
84
+ # This operation is idempotent and therefore thread-safe
85
+ # The worst case is that the string transformation on the right will
86
+ # run multiple times and make a little more work for the GC
87
+ meth = @unbanged_methods[meth] ||= meth.to_s.sub(/!$/, '').to_sym
88
+
89
+ Actor.async @mailbox, meth, *args, &block
90
+ else
91
+ Actor.call @mailbox, meth, *args, &block
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,105 @@
1
+ module Celluloid
2
+ # Calls represent requests to an actor
3
+ class Call
4
+ attr_reader :caller, :method, :arguments, :block
5
+
6
+ def initialize(caller, method, arguments = [], block = nil)
7
+ @caller, @method, @arguments, @block = caller, method, arguments, block
8
+ end
9
+
10
+ def check_signature(obj)
11
+ unless obj.respond_to? @method
12
+ raise NoMethodError, "undefined method `#{@method}' for #{obj.inspect}"
13
+ end
14
+
15
+ begin
16
+ arity = obj.method(@method).arity
17
+ rescue NameError
18
+ # If the object claims it responds to a method, but it doesn't exist,
19
+ # then we have to assume method_missing will do what it says
20
+ @arguments.unshift(@method)
21
+ @method = :method_missing
22
+ return
23
+ end
24
+
25
+ if arity >= 0
26
+ if arguments.size != arity
27
+ raise ArgumentError, "wrong number of arguments (#{arguments.size} for #{arity})"
28
+ end
29
+ elsif arity < -1
30
+ mandatory_args = -arity - 1
31
+ if arguments.size < mandatory_args
32
+ raise ArgumentError, "wrong number of arguments (#{arguments.size} for #{mandatory_args})"
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ # Synchronous calls wait for a response
39
+ class SyncCall < Call
40
+ attr_reader :task
41
+
42
+ def initialize(caller, method, arguments = [], block = nil, task = Fiber.current.task)
43
+ super(caller, method, arguments, block)
44
+ @task = task
45
+ end
46
+
47
+ def dispatch(obj)
48
+ begin
49
+ check_signature(obj)
50
+ rescue => ex
51
+ respond ErrorResponse.new(self, AbortError.new(ex))
52
+ return
53
+ end
54
+
55
+ begin
56
+ result = obj.send @method, *@arguments, &@block
57
+ rescue Exception => exception
58
+ # Exceptions that occur during synchronous calls are reraised in the
59
+ # context of the caller
60
+ respond ErrorResponse.new(self, exception)
61
+
62
+ if exception.is_a? AbortError
63
+ # Aborting indicates a protocol error on the part of the caller
64
+ # It should crash the caller, but the exception isn't reraised
65
+ return
66
+ else
67
+ # Otherwise, it's a bug in this actor and should be reraised
68
+ raise exception
69
+ end
70
+ end
71
+
72
+ respond SuccessResponse.new(self, result)
73
+ end
74
+
75
+ def cleanup
76
+ exception = DeadActorError.new("attempted to call a dead actor")
77
+ respond ErrorResponse.new(self, exception)
78
+ end
79
+
80
+ def respond(message)
81
+ @caller << message
82
+ rescue MailboxError
83
+ # It's possible the caller exited or crashed before we could send a
84
+ # response to them.
85
+ end
86
+ end
87
+
88
+ # Asynchronous calls don't wait for a response
89
+ class AsyncCall < Call
90
+ def dispatch(obj)
91
+ begin
92
+ check_signature(obj)
93
+ rescue Exception => ex
94
+ Logger.crash("#{obj.class}: async call `#{@method}' failed!", ex)
95
+ return
96
+ end
97
+
98
+ obj.send(@method, *@arguments, &@block)
99
+ rescue AbortError => ex
100
+ # Swallow aborted async calls, as they indicate the caller made a mistake
101
+ Logger.crash("#{obj.class}: async call `#{@method}' aborted!", ex)
102
+ end
103
+ end
104
+ end
105
+
@@ -0,0 +1,25 @@
1
+ require 'celluloid/fiber'
2
+
3
+ # Monkeypatch Thread to allow lazy access to its Celluloid::Mailbox
4
+ class Thread
5
+ attr_accessor :uuid_counter, :uuid_limit
6
+
7
+ # Retrieve the mailbox for the current thread or lazily initialize it
8
+ def self.mailbox
9
+ current[:mailbox] ||= Celluloid::Mailbox.new
10
+ end
11
+
12
+ # Receive a message either as an actor or through the local mailbox
13
+ def self.receive(timeout = nil, &block)
14
+ if Celluloid.actor?
15
+ Celluloid.receive(timeout, &block)
16
+ else
17
+ mailbox.receive(timeout, &block)
18
+ end
19
+ end
20
+ end
21
+
22
+ class Fiber
23
+ # Celluloid::Task associated with this Fiber
24
+ attr_accessor :task
25
+ end
@@ -0,0 +1,16 @@
1
+ require 'rbconfig'
2
+
3
+ module Celluloid
4
+ module CPUCounter
5
+ case RbConfig::CONFIG['host_os'][/^[A-Za-z]+/]
6
+ when 'darwin'
7
+ @cores = Integer(`sysctl hw.ncpu`[/\d+/])
8
+ when 'linux'
9
+ @cores = File.read("/proc/cpuinfo").scan(/core id\s+: \d+/).uniq.size
10
+ else
11
+ @cores = nil
12
+ end
13
+
14
+ def self.cores; @cores; end
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ module Celluloid
2
+ # Exceptional system events which need to be processed out of band
3
+ class SystemEvent < Exception; end
4
+
5
+ # An actor has exited for the given reason
6
+ class ExitEvent < SystemEvent
7
+ attr_reader :actor, :reason
8
+
9
+ def initialize(actor, reason = nil)
10
+ @actor, @reason = actor, reason
11
+ super reason.to_s
12
+ end
13
+ end
14
+
15
+ # Name an actor at the time it's registered
16
+ class NamingRequest < SystemEvent
17
+ attr_reader :name
18
+
19
+ def initialize(name)
20
+ @name = name
21
+ end
22
+ end
23
+
24
+ # Request for an actor to terminate
25
+ class TerminationRequest < SystemEvent; end
26
+ end
@@ -0,0 +1,32 @@
1
+ # Fibers are hard... let's go shopping!
2
+ begin
3
+ require 'fiber'
4
+ rescue LoadError => ex
5
+ if defined? JRUBY_VERSION
6
+ if RUBY_VERSION < "1.9.2"
7
+ raise LoadError, "Celluloid requires JRuby 1.9 mode. Please pass the --1.9 flag or set JRUBY_OPTS=--1.9"
8
+ end
9
+
10
+ # Fibers are broken on JRuby 1.6.5. This works around the issue
11
+ if JRUBY_VERSION[/^1\.6\.5/]
12
+ require 'jruby'
13
+ org.jruby.ext.fiber.FiberExtLibrary.new.load(JRuby.runtime, false)
14
+ class org::jruby::ext::fiber::ThreadFiber
15
+ field_accessor :state
16
+ end
17
+
18
+ class Fiber
19
+ def alive?
20
+ JRuby.reference(self).state != org.jruby.ext.fiber.ThreadFiberState::FINISHED
21
+ end
22
+ end
23
+ else
24
+ # Just in case subsequent JRuby releases have broken fibers :/
25
+ raise ex
26
+ end
27
+ elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
28
+ raise LoadError, "Celluloid requires Rubinius 1.9 mode. Please pass the -X19 flag."
29
+ else
30
+ raise ex
31
+ end
32
+ end