diff -Nru ruby-celluloid-0.14.0/.coveralls.yml ruby-celluloid-0.15.2/.coveralls.yml --- ruby-celluloid-0.14.0/.coveralls.yml 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/.coveralls.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -service-name: travis-pro diff -Nru ruby-celluloid-0.14.0/.document ruby-celluloid-0.15.2/.document --- ruby-celluloid-0.14.0/.document 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/.document 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -lib/**/*.rb -bin/* -- -features/**/*.feature -LICENSE.txt diff -Nru ruby-celluloid-0.14.0/.gitignore ruby-celluloid-0.15.2/.gitignore --- ruby-celluloid-0.14.0/.gitignore 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -coverage/ -rdoc/ -doc/ -pkg/ -.yardoc -.bundle -Gemfile.lock diff -Nru ruby-celluloid-0.14.0/.rspec ruby-celluloid-0.15.2/.rspec --- ruby-celluloid-0.14.0/.rspec 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/.rspec 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ ---color ---format documentation ---backtrace ---default_path spec diff -Nru ruby-celluloid-0.14.0/.travis.yml ruby-celluloid-0.15.2/.travis.yml --- ruby-celluloid-0.14.0/.travis.yml 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/.travis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -script: rake ci -rvm: - - 1.9.3 - - 2.0.0 - - ruby-head - - jruby-19mode - - jruby-head - - rbx-19mode - -matrix: - allow_failures: - - rvm: ruby-head - - rvm: jruby-19mode # jruby 1.7.3 fibers are broken - - rvm: jruby-head - - rvm: rbx-19mode # deadlocks :( - -notifications: - irc: "irc.freenode.org#celluloid" diff -Nru ruby-celluloid-0.14.0/CHANGES.md ruby-celluloid-0.15.2/CHANGES.md --- ruby-celluloid-0.14.0/CHANGES.md 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/CHANGES.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,259 +0,0 @@ -0.14.0 (2013-05-07) -------------------- -* Use a Thread-subclass for Celluloid - * Implement actor-local variables - * Add helper methods to the class -* Move IO::Mailbox to EventedMailbox to remove dependency between - celluloid-io and celluloid-zmq. This makes it easier to maintain - the evented style of Mailbox. -* Install the `at_exit` handler by default -* Show backtrace for all tasks. Currently only for TaskThread -* Implement mailbox bounds where overflow is logged -* Fix Thread self-join -* Execute blocks on the sender by default -* Fix CPU counter on windows - -0.13.0 ------- -* API change: Require Celluloid with: require 'celluloid/autostart' to - automatically start support actors and configure at_exit handler which - automatically terminates all actors. -* API change: use_mailbox has been removed -* API change: finalizers must be declared with "finalizer :my_finalizer" -* Bugfix: receivers don't crash when methods are called incorrectly -* Celluloid::Condition provides ConditionVariable-like signaling -* Shutdown timeout reduced to 10 seconds -* Stack traces across inter-actor calls! Should make Celluloid backtraces - much easier to understand -* Celluloid#call_chain_id provides UUIDs for calls across actors -* Give all thread locals a :celluloid_* prefix - -0.12.4 ------- -* Bugfix: Clear dead/crashed actors out of links -* Bugfix: Exclusive mode was broken -* Bugfix: Celluloid::SupervisionGroup#run was broken -* Celluloid::ClassMethods#proxy_class allows configurable proxies -* Improved error messages for Fiber-related problems -* Better object leakage detection when inspecting -* Use #public_send to dispatch Celluloid methods -* #idle_size and #busy_size for Celluloid::PoolManager - -0.12.3 ------- -* Bugfix: Ensure exclusive mode works correctly for per-method case -* Bugfix: Exit handlers were not being inherited correctly - -0.12.2 ------- -* Disable IncidentReporter by default - -0.12.1 ------- -* Fix bug in unsetting of exclusive mode -* New incident report system for providing better debugging reports -* Revert BasicObject proxies for now... they are causing problems -* String inspect that reveals bare object leaks -* Fix bug reporting proper task statuses -* Initial thread dumper support -* Remove Celluloid#alive? as it cannot be called in any manner that will ever - return anything but true, rendering it useless - -0.12.0 ------- -* Alternative async syntax: actor.async.method in lieu of actor.method! - Original syntax still available but will be removed in Celluloid 1.0 -* Alternative future syntax: actor.future.method in lieu of future(:method) -* All methods in the Celluloid module are now available on its singleton -* The #join and #kill methods are no longer available on the actor proxy. - Please use Celluloid::Actor.join(actor) and .kill(actor) instead. -* Celluloid::Future#ready? can be used to query for future readiness -* Celluloid::Group constant removed. Please use Celluloid::SupervisionGroup -* #monitor, #unmonitor, and #monitoring? provide unidirectional linking -* Linking is now performed via a SystemEvent -* SystemEvents are no longer exceptions. Boo exceptions as flow control! -* Celluloid::Mailbox#system_event eliminated and replaced with Mailbox#<< - SystemEvents are now automatically high priority -* The task_class class method can be used to override the class used for - tasks, allowing different task implementations to be configured on an - actor-by-actor-basis -* Celluloid::TaskThread provides tasks backed by Threads instead of Fibers -* ActorProxy is now a BasicObject -* A bug prevented Celluloid subclasses from retaining custom mailboxes - defined by use_mailbox. This is now fixed. -* `exclusive` class method without arguments makes the whole actor exclusive - -0.11.1 ------- -* 'exclusive' class method marks methods as always exclusive and runs them - outside of a Fiber (useful if you need more stack than Fibers provide) -* Celluloid::PoolManager returns its own class when #class is called, instead - of proxying to a cell/actor in the pool. -* #receive now handles SystemEvents internally -* Celluloid::Timers extracted into the timers gem, which Celluloid now - uses for its own timers - -0.11.0 ------- -* Celluloid::Application constant permanently removed -* Celluloid::Pool removed in favor of Celluloid.pool -* Celluloid::Group renamed to Celluloid::SupervisionGroup, old name is - still available and has not been deprecated -* Celluloid::ThreadPool renamed to Celluloid::InternalPool to emphasize its - internalness -* Support for asynchronously calling private methods inside actors -* Future is now an instance method on all actors -* Async call exception logs now contain the failed method -* MyActor#async makes async calls for those who dislike the predicate syntax -* abort can now accept a string instead of an exception object and will raise - RuntimeError in the caller's context - -0.10.0 ------- -* Celluloid::Actor.current is now the de facto way to obtain the current actor -* #terminate now uses system messages, making termination take priority over - other pending methods -* #terminate! provides asynchronous termination - -0.9.1 ------ -* Recurring timers with Celluloid#every(n) { ... } -* Obtain UUIDs with Celluloid.uuid -* Obtain the number of CPU cores available with Celluloid.cores -* Celluloid::Pool defaults to one actor per CPU core max by default - -0.9.0 ------ -* Celluloid::Pool supervises pools of actors -* Graceful shutdown which calls #terminate on all actors -* Celluloid::Actor.all returns all running actors -* Celluloid#exclusive runs a high priority block which prevents other methods - from executing -* Celluloid.exception_handler { |ex| ... } defines a callback for notifying - exceptions (for use with Airbrake, exception_notifier, etc.) - -0.8.0 ------ -* Celluloid::Application is now Celluloid::Group -* Futures no longer use a thread unless created with a block -* No more future thread-leaks! Future threads auto-terminate now -* Rename Celluloid#async to Celluloid#defer -* Celluloid#tasks now returns an array of tasks with a #status attribute -* Reduce coupling between Celluloid and DCell. Breaks compatibility with - earlier versions of DCell. -* Celluloid::FSMs are no longer actors themselves -* Benchmarks using benchmark_suite - -0.7.2 ------ -* Workaround fiber problems on JRuby 1.6.5.1 in addition to 1.6.5 -* Fix class displayed when inspecting dead actors - -0.7.1 ------ -* More examples! -* Cancel all pending tasks when actors crash -* Log all errors that occur during signaling failures -* Work around thread-local issues on rbx (see 52325ecd) - -0.7.0 ------ -* Celluloid::Task abstraction replaces Celluloid::Fiber -* Celluloid#tasks API to introspect on running tasks -* Move Celluloid::IO into its own gem, celluloid-io -* Finite state machines with Celluloid::FSM -* Fix bugs in supervisors handling actors that crash during initialize -* Old syntax Celluloid::Future() { ... } deprecated. Please use the #future - method or Celluloid::Future.new { ... } to create futures -* New timer subsystem! Bullet point-by-bullet point details below -* Celluloid#after registers a callback to fire after a given time interval -* Celluloid.sleep and Celluloid#sleep let an actor continue processing messages -* Celluloid.receive and Celluloid#receive now accept an optional timeout -* Celluloid::Mailbox#receive now accepts an optional timeout - -0.6.2 ------ -* List all registered actors with Celluloid::Actor.registered -* All logging now handled through Celluloid::Logger -* Rescue DeadActorError in Celluloid::ActorProxy#inspect - -0.6.1 ------ -* Celluloid#links obtains Celluloid::Links for a given actor -* The #class method is now proxied to actors -* Celluloid::Fiber replaces the Celluloid.fiber and Celluloid.resume_fiber API -* Use Thread.mailbox instead of Thread.current.mailbox to obtain the mailbox - for the current thread - -0.6.0 ------ -* Celluloid::Application classes for describing the structure of applications - built with Celluloid -* Methods of actors can now participate in the actor protocol directly via - Celluloid#receive -* Configure custom mailbox types using Celluloid.use_mailbox -* Define a custom finalizer for an actor by defining MyActor#finalize -* Actor.call and Actor.async API for making direct calls to mailboxes -* Fix bugs in Celluloid::Supervisors which would crash on startup if the actor - they're supervising also crashes on startup -* Add Celluloid.fiber and Celluloid.resume_fiber to allow extension APIs to - participate in the Celluloid fiber protocol - -0.5.0 ------ -* "include Celluloid::Actor" no longer supported. Use "include Celluloid" -* New Celluloid::IO module for actors that multiplex IO operations -* Major overhaul of Celluloid::Actor internals (see 25e22cc1) -* Actor threads are pooled in Celluloid::Actor::Pool, improving the speed - of creating short-lived actors by over 2X -* Classes that include Celluloid now have a #current_actor instance method -* Celluloid#async allows actors to make indefinitely blocking calls while - still responding to messages -* Fix a potential thread safety bug in Thread#mailbox -* Experimental Celluloid::TCPServer for people wanting to write servers in - Celluloid. This may wind up in another gem, so use at your own risk! -* Magically skip ahead a few version numbers to impart the magnitude of this - release. It's my versioning scheme and I can do what I wanna. - -0.2.2 ------ - -* AbortErrors now reraise in caller scope and get a caller-focused backtrace -* Log failed async calls instead of just letting them fail silently -* Properly handle arity of synchronous calls -* Actors can now make async calls to themselves -* Resolve crashes that occur when sending responses to exited/dead callers - -0.2.1 ------ - -* Hack around a bug of an indeterminate cause (2baba3d2) -* COLON!#@! - -0.2.0 ------ - -* Support for future method calls with MyActor#future -* Initial signaling support via MyActor#signal and MyActor#wait -* Just "include Celluloid" works in lieu of "include Celluloid::Actor" -* Futures terminate implicitly when their values are obtained -* Add an underscore prefix to all of Celluloid's instance variables so they don't - clash with user-defined ones. - -0.1.0 ------ -* Fiber-based reentrant actors. Requires Ruby 1.9 -* MyActor.new (where MyActor includes Celluloid::Actor) is now identical to .spawn -* Terminate actors with MyActor#terminate -* Obtain current actor with Celluloid.current_actor -* Configurable logger with Celluloid.logger -* Synchronization now based on ConditionVariables instead of Celluloid::Waker -* Determine if you're in actor scope with Celluloid.actor? - -0.0.3 ------ -* Remove self-referential dependency in gemspec - -0.0.1 ------ -* Initial release diff -Nru ruby-celluloid-0.14.0/CONTRIBUTING.md ruby-celluloid-0.15.2/CONTRIBUTING.md --- ruby-celluloid-0.14.0/CONTRIBUTING.md 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -# Contribution Guidelines - -If you are seeking support, or for discussions about Celluloid, you can use [the mailing list](http://groups.google.com/group/celluloid-ruby) or the IRC channel, #celluloid on freenode. - -If you encounter an issue with Celluloid itself, you should go through the following checklist: - -* Is this a known bug or are you falling into a common trap? Check the [Gotchas wiki page](https://github.com/celluloid/celluloid/wiki/Gotchas). -* Is there already an issue filed which looks like your issue? Check the [issue tracker](https://github.com/celluloid/celluloid/issues). -* Is the problem present in the latest released version of Celluloid? Upgrade and check! -* Is the problem present on the master branch of Celluloid? [Run pre-release](#running-pre-release-celluloid) from source control and check! - -If you don't get anywhere with this checklist, please feel free to [file a bug report](#filing-a-bug-report). - -## Running pre-release Celluloid - -If you encounter a bug, it's entirely possible that it has already been fixed but not yet included in a released version. You can establish this by trying to run your application with a pre-release version of Celluloid direct from source control. You can do this by modifying your application's Gemfile as follows: - -```ruby -gem 'celluloid', github: 'celluloid' -``` - -If it is suggested to you that you try a different branch, add `branch: 'somebranch'`. - -If the problem is resolved, feel free to voice your desire for a new release of Celluloid on IRC (`irc.freenode.net/#celluloid`). - -If it persists, you should consider [filing a bug report](#filing-a-bug-report). - -## Filing a bug report - -* Bug reports should be filed on the [GitHub issue tracker](https://github.com/celluloid/celluloid/issues). Bug reports should contain the following things: - * A sensible subject that helps quickly identify the issue. - * Full steps to reproduce the issue, including minimal reproduction code. A minimal reproduction means only what is necessary to display the problem and nothing more. This is perhaps the most important thing, don't skip it! - * Output from a reproduction. - * Full references for version numbers (of Celluloid, dependencies, Ruby, Operating System, etc). One easy way to do this is to post your Gemfile.lock, though you will still need to tell us what version of Ruby is in use. -* Some more guidelines on filing good bug reports: - * http://www.chiark.greenend.org.uk/~sgtatham/bugs.html - * http://itscommonsensestupid.blogspot.com/2008/07/tips-to-write-good-bug-report.html - * http://timheuer.com/blog/archive/2011/10/12/anatomy-of-a-good-bug-report.aspx diff -Nru ruby-celluloid-0.14.0/Gemfile ruby-celluloid-0.15.2/Gemfile --- ruby-celluloid-0.14.0/Gemfile 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/Gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -source 'https://rubygems.org' -gemspec - -gem 'coveralls', require: false - -if RUBY_PLATFORM =~ /darwin/ - gem 'rb-fsevent', '~> 0.9.1' -end diff -Nru ruby-celluloid-0.14.0/Guardfile ruby-celluloid-0.15.2/Guardfile --- ruby-celluloid-0.14.0/Guardfile 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/Guardfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -guard 'rspec', :version => 2, :cli => '--format documentation' do - watch(%r{^spec/.+_spec\.rb$}) - watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } - watch('spec/spec_helper.rb') { "spec/" } -end diff -Nru ruby-celluloid-0.14.0/LICENSE.txt ruby-celluloid-0.15.2/LICENSE.txt --- ruby-celluloid-0.14.0/LICENSE.txt 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -Copyright (c) 2013 Tony Arcieri - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -Nru ruby-celluloid-0.14.0/README.md ruby-celluloid-0.15.2/README.md --- ruby-celluloid-0.14.0/README.md 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/README.md 2013-11-26 19:53:19.000000000 +0000 @@ -99,7 +99,9 @@ Add this line to your application's Gemfile: - gem 'celluloid' +```ruby +gem 'celluloid' +``` And then execute: @@ -111,7 +113,9 @@ Inside of your Ruby program, require Celluloid with: - require 'celluloid/autostart' +```ruby +require 'celluloid/autostart' +``` Supported Platforms ------------------- diff -Nru ruby-celluloid-0.14.0/Rakefile ruby-celluloid-0.15.2/Rakefile --- ruby-celluloid-0.14.0/Rakefile 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/Rakefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -require "bundler/gem_tasks" -Dir["tasks/**/*.task"].each { |task| load task } - -task :default => :spec -task :ci => %w(spec benchmark) diff -Nru ruby-celluloid-0.14.0/benchmarks/actor.rb ruby-celluloid-0.15.2/benchmarks/actor.rb --- ruby-celluloid-0.14.0/benchmarks/actor.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/benchmarks/actor.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -#!/usr/bin/env ruby - -require 'rubygems' -require 'bundler/setup' -require 'celluloid' -require 'benchmark/ips' - -class ExampleActor - include Celluloid - - def initialize - @condition = Condition.new - end - - def example_method; end - - def finished - @condition.signal - end - - def wait_until_finished - @condition.wait - end -end - -example_actor = ExampleActor.new -mailbox = Celluloid::Mailbox.new - -latch_in, latch_out = Queue.new, Queue.new -latch = Thread.new do - while true - n = latch_in.pop - for i in 0..n; mailbox.receive; end - latch_out << :done - end -end - -Benchmark.ips do |ips| - ips.report("spawn") { ExampleActor.new.terminate } - - ips.report("calls") { example_actor.example_method } - - ips.report("async calls") do |n| - waiter = example_actor.future.wait_until_finished - - (n - 1).times { example_actor.async.example_method } - example_actor.async.finished - - waiter.value - end - - ips.report("messages") do |n| - latch_in << n - for i in 0..n; mailbox << :message; end - latch_out.pop - end -end diff -Nru ruby-celluloid-0.14.0/benchmarks/parallel_hash.rb ruby-celluloid-0.15.2/benchmarks/parallel_hash.rb --- ruby-celluloid-0.14.0/benchmarks/parallel_hash.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/benchmarks/parallel_hash.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -#!/usr/bin/env ruby - -require 'rubygems' -require 'bundler/setup' -require 'celluloid' -require 'benchmark/ips' -require File.expand_path("../../examples/pool", __FILE__) - -pool = Rehasher.new - -Benchmark.ips do |ips| - ips.report("parallel hash") do - 64.times.map { pool.future(:rehash, 'w3rd', 10_000) }.map(&:value) - end -end diff -Nru ruby-celluloid-0.14.0/benchmarks/ring.rb ruby-celluloid-0.15.2/benchmarks/ring.rb --- ruby-celluloid-0.14.0/benchmarks/ring.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/benchmarks/ring.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -#!/usr/bin/env ruby - -require 'rubygems' -require 'bundler/setup' -require 'celluloid' -require 'benchmark/ips' -require File.expand_path("../../examples/ring", __FILE__) - -# 512-node ring -ring = Ring.new 512 - -Benchmark.ips do |ips| - ips.report("ring-around") { |n| ring.run n } -end diff -Nru ruby-celluloid-0.14.0/benchmarks/uuid.rb ruby-celluloid-0.15.2/benchmarks/uuid.rb --- ruby-celluloid-0.14.0/benchmarks/uuid.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/benchmarks/uuid.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -#!/usr/bin/env ruby - -require 'rubygems' -require 'bundler/setup' -require 'celluloid' -require 'benchmark/ips' - -Benchmark.ips do |ips| - ips.report("uuid") { Celluloid.uuid } -end diff -Nru ruby-celluloid-0.14.0/celluloid.gemspec ruby-celluloid-0.15.2/celluloid.gemspec --- ruby-celluloid-0.14.0/celluloid.gemspec 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/celluloid.gemspec 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -# -*- encoding: utf-8 -*- -$:.push File.expand_path('../lib', __FILE__) -require 'celluloid/version' - -Gem::Specification.new do |gem| - gem.name = 'celluloid' - gem.version = Celluloid::VERSION - gem.platform = Gem::Platform::RUBY - gem.summary = 'Actor-based concurrent object framework for Ruby' - gem.description = 'Celluloid enables people to build concurrent programs out of concurrent objects just as easily as they build sequential programs out of sequential objects' - gem.licenses = ['MIT'] - - gem.authors = ['Tony Arcieri'] - gem.email = ['tony.arcieri@gmail.com'] - gem.homepage = 'https://github.com/celluloid/celluloid' - - gem.required_ruby_version = '>= 1.9.2' - gem.required_rubygems_version = '>= 1.3.6' - - gem.files = Dir['README.md', 'lib/**/*', 'spec/support/**/*'] - gem.require_path = 'lib' - - gem.add_runtime_dependency 'timers', '>= 1.0.0' - - gem.add_development_dependency 'rake' - gem.add_development_dependency 'rspec' - gem.add_development_dependency 'guard-rspec' - gem.add_development_dependency 'benchmark_suite' -end Binary files /tmp/j0ahoKaXsy/ruby-celluloid-0.14.0/checksums.yaml.gz and /tmp/VwY7_6wvEG/ruby-celluloid-0.15.2/checksums.yaml.gz differ diff -Nru ruby-celluloid-0.14.0/debian/changelog ruby-celluloid-0.15.2/debian/changelog --- ruby-celluloid-0.14.0/debian/changelog 2013-05-17 22:14:53.000000000 +0000 +++ ruby-celluloid-0.15.2/debian/changelog 2014-01-24 00:20:00.000000000 +0000 @@ -1,3 +1,23 @@ +ruby-celluloid (0.15.2-1) unstable; urgency=medium + + * Team upload. + * Imported Upstream version 0.15.2 + * Bump Standards-Version to 3.9.5 (no changes needed) + * Refresh patches + * Install README.md; do not install CHANGES.md, missing from this upstream + version + * Create a log/ dir for the tests and remove it afterwards + + -- Cédric Boutillier Fri, 24 Jan 2014 00:41:07 +0100 + +ruby-celluloid (0.14.0-2) unstable; urgency=low + + * Team upload + * install files from spec/support in $vendorlib/celluloid/support/ + * add fix_relative_path_rspec.patch to fix paths in celluloid/rspec.rb + + -- Cédric Boutillier Thu, 23 Jan 2014 23:03:39 +0100 + ruby-celluloid (0.14.0-1) unstable; urgency=low * Initial release (Closes: #708709) diff -Nru ruby-celluloid-0.14.0/debian/control ruby-celluloid-0.15.2/debian/control --- ruby-celluloid-0.14.0/debian/control 2013-05-17 22:16:55.000000000 +0000 +++ ruby-celluloid-0.15.2/debian/control 2014-01-23 23:56:13.000000000 +0000 @@ -4,7 +4,7 @@ Maintainer: Debian Ruby Extras Maintainers Uploaders: Praveen Arimbrathodiyil Build-Depends: debhelper (>= 7.0.50~), gem2deb (>= 0.3.1~), ruby-timers, rake, ruby-rspec -Standards-Version: 3.9.4 +Standards-Version: 3.9.5 Vcs-Git: git://anonscm.debian.org/pkg-ruby-extras/ruby-celluloid.git Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-ruby-extras/ruby-celluloid.git;a=summary Homepage: https://github.com/celluloid/celluloid diff -Nru ruby-celluloid-0.14.0/debian/patches/fix_relative_path_rspec.patch ruby-celluloid-0.15.2/debian/patches/fix_relative_path_rspec.patch --- ruby-celluloid-0.14.0/debian/patches/fix_relative_path_rspec.patch 1970-01-01 00:00:00.000000000 +0000 +++ ruby-celluloid-0.15.2/debian/patches/fix_relative_path_rspec.patch 2014-01-23 23:44:18.000000000 +0000 @@ -0,0 +1,17 @@ +Description: install files in spec/support in $vendorlib/celluloid/support + fixing the corresponding paths in requires +Author: Cédric Boutillier +Last-Update: 2013-11-04 + +--- a/lib/celluloid/rspec.rb ++++ b/lib/celluloid/rspec.rb +@@ -1,6 +1,6 @@ +-require File.expand_path('../../../spec/support/example_actor_class', __FILE__) +-require File.expand_path('../../../spec/support/actor_examples', __FILE__) +-require File.expand_path('../../../spec/support/mailbox_examples', __FILE__) ++require 'celluloid/support/example_actor_class' ++require 'celluloid/support/actor_examples' ++require 'celluloid/support/mailbox_examples' + + module Celluloid + # Timer accuracy enforced by the tests (50ms) diff -Nru ruby-celluloid-0.14.0/debian/patches/remove-rubygems-bundler-coveralls.patch ruby-celluloid-0.15.2/debian/patches/remove-rubygems-bundler-coveralls.patch --- ruby-celluloid-0.14.0/debian/patches/remove-rubygems-bundler-coveralls.patch 2013-05-17 22:14:53.000000000 +0000 +++ ruby-celluloid-0.15.2/debian/patches/remove-rubygems-bundler-coveralls.patch 2014-01-23 23:42:40.000000000 +0000 @@ -6,17 +6,17 @@ --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb -@@ -1,9 +1,9 @@ +@@ -1,8 +1,8 @@ +-require 'coveralls' +-Coveralls.wear! +- -require 'rubygems' -require 'bundler/setup' ++#require 'coveralls' ++#Coveralls.wear! ++# +#require 'rubygems' +#require 'bundler/setup' - require 'celluloid/autostart' require 'celluloid/rspec' --require 'coveralls' --Coveralls.wear! -+#require 'coveralls' -+#Coveralls.wear! logfile = File.open(File.expand_path("../../log/test.log", __FILE__), 'a') - logfile.sync = true diff -Nru ruby-celluloid-0.14.0/debian/patches/series ruby-celluloid-0.15.2/debian/patches/series --- ruby-celluloid-0.14.0/debian/patches/series 2013-05-17 22:14:53.000000000 +0000 +++ ruby-celluloid-0.15.2/debian/patches/series 2014-01-23 22:03:12.000000000 +0000 @@ -1 +1,2 @@ remove-rubygems-bundler-coveralls.patch +fix_relative_path_rspec.patch diff -Nru ruby-celluloid-0.14.0/debian/ruby-celluloid.docs ruby-celluloid-0.15.2/debian/ruby-celluloid.docs --- ruby-celluloid-0.14.0/debian/ruby-celluloid.docs 2013-05-17 22:14:53.000000000 +0000 +++ ruby-celluloid-0.15.2/debian/ruby-celluloid.docs 2014-01-23 23:53:06.000000000 +0000 @@ -1,2 +1 @@ -# FIXME: READMEs found -# README.md +README.md diff -Nru ruby-celluloid-0.14.0/debian/rules ruby-celluloid-0.15.2/debian/rules --- ruby-celluloid-0.14.0/debian/rules 2013-05-17 22:14:53.000000000 +0000 +++ ruby-celluloid-0.15.2/debian/rules 2014-01-23 23:53:17.000000000 +0000 @@ -14,5 +14,12 @@ %: dh $@ --buildsystem=ruby --with ruby -override_dh_installchangelogs: - dh_installchangelogs CHANGES.md +override_dh_auto_install: + mkdir log/ + cp -R spec/support lib/celluloid/ + dh_auto_install + +override_dh_clean: + $(RM) -rf lib/celluloid/support + $(RM) -rf log/ + dh_clean diff -Nru ruby-celluloid-0.14.0/examples/basic_usage.rb ruby-celluloid-0.15.2/examples/basic_usage.rb --- ruby-celluloid-0.14.0/examples/basic_usage.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/examples/basic_usage.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -#!/usr/bin/env ruby - -$:.push File.expand_path('../../lib', __FILE__) -require 'celluloid/autostart' - -class Counter - # This is all you have to do to turn any Ruby class into one which creates - # Celluloid actors instead of normal objects - include Celluloid - - # Now just define methods like you ordinarily would - attr_reader :count - - def initialize - @count = 0 - end - - def increment(n = 1) - @count += n - end -end - -# Create objects just like you normally would. 'actor' is now a proxy object -# which talks to a Celluloid actor running in its own thread -actor = Counter.new - -# The proxy obeys normal method invocation the way we'd expect. This prints 0 -p actor.count - -# This increments @count by 1 and prints 1 -p actor.increment - -# By using actor.async, you can make calls asynchronously. This immediately -# requests execution of method by sending a message, and we have no idea -# whether or not that request will actually complete because we don't wait -# for a response. Async calls immediately return nil regardless of how long -# the method takes to execute. Therefore, this will print nil. -p actor.async.increment 41 - -# In practice, the asynchronous call made above will increment the count before -# we get here. However, do not rely on this behavior! Asynchronous methods are -# inherently uncoordinated. If you need to coordinate asynchronous activities, -# you will need to use futures or FSMs. See the corresponding examples for those. -# Signals can also be used to coordinate asynchronous activities. -# -# The following line could possibly print either 1 or 42, depending on if the -# asynchronous call above completed. In practice, it prints 42 on all Ruby -# implementations because the asynchronous call above will always execute -p actor.count diff -Nru ruby-celluloid-0.14.0/examples/cigarette_smokers.rb ruby-celluloid-0.15.2/examples/cigarette_smokers.rb --- ruby-celluloid-0.14.0/examples/cigarette_smokers.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/examples/cigarette_smokers.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,323 +0,0 @@ -#!/usr/bin/env ruby - -require 'rubygems' -require 'bundler/setup' -require 'celluloid/autostart' - -# -# THE CIGARETTE SMOKERS PROBLEM -# See http://en.wikipedia.org/wiki/Cigarette_smokers_problem -# -# Three smokers are sitting at a table. One is a tobacco grower, the second a -# papermaker, and the third a matchstick maker. They have all brought with -# them an abundance of their own fare, and they're here to smoke! However, in -# order to smoke each man will need the goods of the other two. -# -# After a great deal of disagreement about the best way to settle the three-way -# exchange needed for any one man to enjoy a cigarette, the three men -# eventually negotiate a rather unusual arrangement. Whenever the table in -# front of them is empty they notify the waitress, who selects two of the men -# at random, taking a single unit of their particular good. She then places -# their goods on the table and gives a wink and a nod to the third man. -# -# If the third man whose goods she did not take is not smoking, he'll take -# the two items and use his own supply of the third to enjoy a cigarette. -# If, however, he's already smoking, he'll smile and nod in return, perhaps -# taking an extra long drag on his cigarette, possibly to the chagrin of his -# compatriates. For you see, the rules are that only the third man in this -# exchange is allowed to remove the items from the table. If he's already -# enjoying a cigarette, the other two are forced to wait. -# -# One way or another, the third man will eventually collect the items from the -# table. When he does, he'll whistle for the waitress, and she'll again select -# two men at random, replenishing the table. - -# Each of the three men at the table is a smoker -class Smoker - include Celluloid - - # These guys are smoking MACHINES (literally, they're finite state machines!) - class Machine - include Celluloid::FSM - - default_state :standing - - state :waiting, :to => :procuring do - actor.check_table - end - - state :procuring, :to => [:waiting, :smoking] do - if actor.take_items - transition :smoking - else - transition :waiting - end - end - - state :smoking do - actor.smoke - end - - state :done do - actor.smoking = false - puts "#{actor.name} has finished smoking" - transition :procuring - end - end - - def initialize(commodity, rate) - @commodity, @rate = commodity, rate - @table = nil - - @cigarette = nil - @match = nil - @smoking = false - - @machine = Machine.new - end - - attr_accessor :smoking - alias_method :smoking?, :smoking - - def name - "#{@commodity} Guy" - end - - def inspect - "#" - end - - # Sit down at the table - def sit(table) - @table = table - @table.async.welcome(Actor.current) - end - - def sat_down - @machine.transition :procuring - end - - # Obtain this smoker's commodity - def dispense_commodity - @commodity.new - end - - # The table should now have the items I need - def notify_ready - if @machine.state == :smoking - puts "#{name} says: I'm good on smokes, thanks" - else - @machine.transition :procuring - end - end - - # Check the table for the items we're waiting for - def check_table - if @table.empty? - puts "#{name} whistles at waitress... get me smokes!" - @table.waitress.async.whistle # We'll decide what to do when the waitress arrives - end - end - - # Take the items from the table - def take_items - items = @table.items - unless complimentary? items - if items - puts "#{name} eyes the table: #{items.map(&:class).join(' and ')} are useless to me!" - else - puts "#{name} says: The table is empty!" - end - - return - end - - puts "#{name} takes the items from the table" - items = @table.take - - puts "#{name} whistles for the waitress because the table is empty" - @table.waitress.async.whistle - - tobacco = find_item items, Tobacco - paper = find_item items, Paper - @match = find_item items, Matches - - @cigarette = paper.roll tobacco - true - end - - def find_item(items, type) - return @commodity.new if type == @commodity - item = items.find { |i| i.class == type } - raise "can't find any #{type}" unless item - item - end - - def smoke - @smoking = true - @match.light - @cigarette.light @match - - puts "#{name} enjoys a smoke" - @cigarette.smoke - - @machine.transition :done, :delay => @rate * 5 - end - - def complimentary?(items) - return unless items - klasses = [Tobacco, Paper, Matches] - [@commodity] - items.map { |i| klasses.include?(i.class) }.all? - end -end - -# The waitress fills the table -class Waitress - include Celluloid - - def initialize(table) - @table = table - @refilling = false - end - - # Handle incoming whistles - def whistle - unless @table.smokers.size == 3 - puts "Waitress says: Nothing I can do for ya hon, your party isn't completely seated" - return - end - - if @table.items - puts "Waitress says: The table already has stuff on it!" - elsif @refilling - puts "Waitress says: I'm WORKIN' on it! Hold your horses!" - else - refill_table - end - end - - def refill_table - @refilling = true - - begin - smokers = @table.smokers.dup - receiver = smokers.delete_at rand(smokers.size) - puts "#{self.class} decides that #{receiver.name} gets to smoke!" - - items = smokers.map { |s| s.dispense_commodity } - - puts "Waitress collects #{items.map(&:class).join(' and ')} and puts them on the table" - @table.place(items) - ensure - @refilling = false - end - - puts "Waitress tells #{receiver.name} he can smoke now" - receiver.async.notify_ready - note_smokers - end - - def note_smokers - active_smokers = @table.smokers.select { |s| s.smoking? } - puts "*** Active smokers: #{active_smokers.map(&:name).join(", ")}" - puts "!!! EVERYBODY SMOKES !!!" if active_smokers.size == @table.smokers.size - end -end - -# The table is the central state holder of the system -class Table - include Celluloid - attr_reader :smokers - attr_reader :waitress - attr_reader :items - - def initialize - @smokers = [] - @waitress = Waitress.new(Actor.current) # Always use Actor.current instead of self! - @items = nil - end - - def welcome(smoker) - @smokers << smoker - smoker.async.sat_down - end - - def place(items) - abort RuntimeError.new("there's already stuff on the table") if @items - @items = items - puts "Table now contains: #{items.map(&:class).join(', ')}" - return @items - end - - def take - raise "there's nothing on the table" unless @items - items = @items - @items = nil - items - end - - def empty? - !@items - end -end - -# -# The following are effectively data objects passed around between smokers -# - -class Tobacco - def burn - carcinogens = [:polonium, :nitrosamine, :benzopyrene] - [:nicotine, *carcinogens] - end -end - -class Paper - def roll(tobacco) - Cigarette.new(tobacco, self) - end - def burn; [:ash]; end -end - -class Matches - def initialize - @lit = false - end - - def light; @lit = true; end - def lit?; @lit; end -end - -class Cigarette - def initialize(tobacco, paper) - @lit = false - @tobacco, @paper = tobacco, paper - end - - def light(match) - @lit = true if match.lit? - end - - def lit?; @lit end - - def smoke - raise "not lit" unless @lit - @tobacco.burn + @paper.burn - end -end - -# -# Run the simulation -# - -smokers = [ - Smoker.new(Tobacco, 1.0), - Smoker.new(Paper, 1.5), - Smoker.new(Matches, 0.3) # he smokes faster because he likes to burn things -] - -table = Table.new -smokers.each { |smoker| smoker.sit(table) } - -# The main thread is done! Sleep forever -sleep diff -Nru ruby-celluloid-0.14.0/examples/futures.rb ruby-celluloid-0.15.2/examples/futures.rb --- ruby-celluloid-0.14.0/examples/futures.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/examples/futures.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -#!/usr/bin/env ruby - -$:.push File.expand_path('../../lib', __FILE__) -require 'celluloid/autostart' -require 'digest/sha2' - -class Hasher - include Celluloid - - def initialize(secret) - @hash = Digest::SHA2.hexdigest(secret) - end - - # Add some data into our hash. This demonstrates a non-trivial computation - # of the same sort as, say, calculating Fibonacci numbers. Since Celluloid - # uses several threads, doing something like this won't grind our entire - # application to a halt - def add(data, n = 100000) - string = @hash + data - n.times { string = Digest::SHA2.hexdigest(string) } - @hash = string - end -end - -# Create the hasher -hasher = Hasher.new("super secret initialization data") - -# Ask the hasher to perform a complex computation. However, since we're using -# a future, this doesn't block the current thread -future = hasher.future.add("some data to be hashed") - -# We've kicked off the hasher, but this thread can continue performing other -# activities while the hasher runs in the background -puts "The hasher is now running, but this thread is free to do whatever it wants" - -# Now let's ask for the return value from the hasher -puts "Getting the hasher's return value... " -p future.value diff -Nru ruby-celluloid-0.14.0/examples/pool.rb ruby-celluloid-0.15.2/examples/pool.rb --- ruby-celluloid-0.14.0/examples/pool.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/examples/pool.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -#!/usr/bin/env ruby -# -# Worker Pool example -# -# Looking for a way to light up all your cores? This is it! Celluloid::Worker -# lets you create fixed-sized thread pools for executing expensive background -# processing tasks. - -PARALLEL_RUBIES = %w(jruby rbx) - -$:.push File.expand_path('../../lib', __FILE__) -require 'celluloid/autostart' -require 'digest/sha2' - -class Rehasher - include Celluloid - - def rehash(string, rounds) - raise ArgumentError, "hurr" unless rounds > 1 - penultimate = (rounds - 1).times.inject(string) { |s| Digest::SHA512.digest(s) } - Digest::SHA512.hexdigest(penultimate) - end -end - -if $0 == __FILE__ - pool = Rehasher.pool - puts "Megahashing!" - if PARALLEL_RUBIES.include?(RUBY_ENGINE) - puts "Since you're using a Ruby with parallel thread execution, this should light up all your cores" - elsif RUBY_ENGINE == "ruby" - puts "Sorry, this Ruby interpreter has a GIL, so this will only use one core" - end - - futures = %w(i am the very model of a modern major general).map do |word| - pool.future.rehash(word, 1_000_000) - end - - p futures.map(&:value) -end diff -Nru ruby-celluloid-0.14.0/examples/ring.rb ruby-celluloid-0.15.2/examples/ring.rb --- ruby-celluloid-0.14.0/examples/ring.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/examples/ring.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -#!/usr/bin/env ruby - -$:.push File.expand_path('../../lib', __FILE__) -require 'celluloid/autostart' - -class Ring - include Celluloid - - class Node - include Celluloid - - def initialize(link) - @link = link - end - - def around(n) - @link.async.around n - end - end - - def initialize(size) - @node = Node.new_link current_actor - - size.times do - @node = Node.new_link @node - end - end - - # Go around the ring the given number of times - def run(n) - if n < 0 - raise ArgumentError, "I can't go around a negative number of times" - end - - async.around n - wait :done - end - - # Go around the ring the given number of times - def around(n) - if n.zero? - signal :done - else - @node.async.around n - 1 - end - end -end - -if $0 == __FILE__ - require 'benchmark' - SIZE = 512 - TIMES = 10 - - puts "*** Creating a #{SIZE} node ring..." - puts Benchmark.measure { - $ring = Ring.new(SIZE) - } - - puts "*** Sending a message around #{TIMES} times" - puts Benchmark.measure { - $ring.run(TIMES) - } -end diff -Nru ruby-celluloid-0.14.0/examples/simple_pmap.rb ruby-celluloid-0.15.2/examples/simple_pmap.rb --- ruby-celluloid-0.14.0/examples/simple_pmap.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/examples/simple_pmap.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -#!/usr/bin/env ruby - -$:.push File.expand_path('../../lib', __FILE__) -require 'celluloid/autostart' - -module Enumerable - # Simple parallel map using Celluloid::Futures - def pmap(&block) - futures = map { |elem| Celluloid::Future.new(elem, &block) } - futures.map { |future| future.value } - end -end diff -Nru ruby-celluloid-0.14.0/examples/supervisors_and_registry.rb ruby-celluloid-0.15.2/examples/supervisors_and_registry.rb --- ruby-celluloid-0.14.0/examples/supervisors_and_registry.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/examples/supervisors_and_registry.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -#!/usr/bin/env ruby - -$:.push File.expand_path('../../lib', __FILE__) -require 'celluloid/autostart' - -class MyActor - include Celluloid - attr_reader :state - - def initialize - @state = :clean - end - - def broken_method - @state = :dirty - oh_crap_im_totally_broken - end -end - -# -# Using the Supervisor API directly -# - -puts "*** Demonstrating using the Supervisor API directly" - -# Calling supervise directly returns the supervisor -supervisor = MyActor.supervise - -# We can get to the current version of an actor by calling -# Celluloid::Supervisor#actor. This prints ':clean' -puts "We should be in a clean state now: #{supervisor.actor.state}" -puts "Brace yourself for a crash message..." - -# If we call a method that crashes an actor, it will print out a debug message, -# then restart an actor in a clean state -begin - supervisor.actor.broken_method -rescue NameError - puts "Uhoh, we crashed the actor..." -end - -puts "The supervisor should automatically restart the actor" - -# By now we'll be back in a :clean state! -begin - puts "We should now be in a clean state again: #{supervisor.actor.state}" -rescue Celluloid::DeadActorError - # Perhaps we got ahold of the actor before the supervisor restarted it - retry -end - -# -# Using the Actor Registry -# This is the preferred approach and will make using DCell easier -# - -puts "*** Demonstrating using the actor registry" - -# We can give our actor a name and thus avoid interacting with the supervisor -MyActor.supervise_as :my_actor - -# Same as above, just getting the actor from a different place -puts "We should be in a clean state now: #{Celluloid::Actor[:my_actor].state}" -puts "Brace yourself for a crash message..." - -# If we call a method that crashes an actor, it will print out a debug message, -# then restart an actor in a clean state -begin - Celluloid::Actor[:my_actor].broken_method -rescue NameError - puts "Uhoh, we crashed the actor..." -end - -puts "The supervisor should automatically restart the actor" - -# By now we'll be back in a :clean state! -begin - puts "We should now be in a clean state again: #{Celluloid::Actor[:my_actor].state}" -rescue Celluloid::DeadActorError - # Perhaps we got ahold of the actor before the supervisor restarted it - # Don't want to catch Celluloid::DeadActorError all over the place? If this - # code were in a supervised Celluloid::Actor itself, the supervisor would - # catch Celluloid::DeadActorError and automatically restart this actor - retry -end - diff -Nru ruby-celluloid-0.14.0/examples/timers.rb ruby-celluloid-0.15.2/examples/timers.rb --- ruby-celluloid-0.14.0/examples/timers.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/examples/timers.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -#!/usr/bin/env ruby - -$:.push File.expand_path('../../lib', __FILE__) -require 'celluloid/autostart' - -class TimerExample - include Celluloid - attr_reader :fired, :timer - - def initialize - @fired = false - @timer = after(3) { puts "Timer fired!"; @fired = true } - end -end - -# -# Basic timer example -# - -actor = TimerExample.new - -# The timer hasn't fired yet, so this should be false -puts "Timer hasn't fired yet, so this should be false: #{actor.fired}" - -# Even if we wait a second, it still hasn't fired -sleep 1 -puts "Timer still shouldn't have fired yet: #{actor.fired}" - -# Wait until after the timer should've fired -sleep 2.1 -puts "Timer should've fired now: #{actor.fired}" - -# -# Cancelling timers -# - -actor = TimerExample.new - -# The timer hasn't fired yet, so this should be false -puts "Timer hasn't fired yet, so this should be false: #{actor.fired}" - -# Cancel the timer, which should prevent it from firing -actor.timer.cancel - -# Wait until after the timer should've fired -sleep 3.1 -puts "Timer shouldn't have fired because we cancelled it: #{actor.fired}" diff -Nru ruby-celluloid-0.14.0/lib/celluloid/actor.rb ruby-celluloid-0.15.2/lib/celluloid/actor.rb --- ruby-celluloid-0.14.0/lib/celluloid/actor.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/actor.rb 2013-11-26 19:53:19.000000000 +0000 @@ -2,16 +2,16 @@ module Celluloid # Don't do Actor-like things outside Actor scope - class NotActorError < StandardError; end + class NotActorError < Celluloid::Error; end # Trying to do something to a dead actor - class DeadActorError < StandardError; end + class DeadActorError < Celluloid::Error; end # A timeout occured before the given request could complete - class TimeoutError < StandardError; end + class TimeoutError < Celluloid::Error; end # The sender made an error, not the current actor - class AbortError < StandardError + class AbortError < Celluloid::Error attr_reader :cause def initialize(cause) @@ -27,7 +27,7 @@ # normal Ruby objects wrapped in threads which communicate with asynchronous # messages. class Actor - attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name, :locals + attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name class << self extend Forwardable @@ -77,9 +77,8 @@ # Obtain all running actors in the system def all actors = [] - Thread.list.each do |t| - next unless t.celluloid? - next if t.task + Celluloid.internal_pool.each do |t| + next unless t.role == :actor actors << t.actor.proxy if t.actor && t.actor.respond_to?(:proxy) end actors @@ -122,10 +121,7 @@ # Forcibly kill a given actor def kill(actor) actor.thread.kill - begin - actor.mailbox.shutdown - rescue DeadActorError - end + actor.mailbox.shutdown if actor.mailbox.alive? end # Wait for an actor to terminate @@ -137,12 +133,15 @@ # Wrap the given subject with an Actor def initialize(subject, options = {}) - @subject = subject - @mailbox = options[:mailbox] || Mailbox.new + @subject = subject + + @mailbox = options.fetch(:mailbox_class, Mailbox).new + @mailbox.max_size = options.fetch(:mailbox_size, nil) + + @task_class = options[:task_class] || Celluloid.task_class @exit_handler = options[:exit_handler] @exclusives = options[:exclusive_methods] @receiver_block_executions = options[:receiver_block_executions] - @task_class = options[:task_class] || Celluloid.task_class @tasks = TaskSet.new @links = Links.new @@ -152,9 +151,8 @@ @running = true @exclusive = false @name = nil - @locals = {} - @thread = ThreadHandle.new do + @thread = ThreadHandle.new(:actor) do setup_thread run end @@ -195,28 +193,9 @@ @running = false end - # Is this actor running in exclusive mode? - def exclusive? - @exclusive - end - - # Execute a code block in exclusive mode. - def exclusive - if @exclusive - yield - else - begin - @exclusive = true - yield - ensure - @exclusive = false - end - end - end - # Perform a linking request with another actor def linking_request(receiver, type) - exclusive do + Celluloid.exclusive do start_time = Time.now receiver.mailbox << LinkingRequest.new(Actor.current, type) system_events = [] @@ -247,7 +226,7 @@ # Send a signal with the given name to all waiting methods def signal(name, value = nil) - @signals.send name, value + @signals.broadcast name, value end # Wait for the given signal @@ -289,6 +268,19 @@ @timers.every(interval) { task(:timer, &block) } end + def timeout(duration) + bt = caller + task = Task.current + timer = @timers.after(duration) do + exception = Task::TimeoutError.new("execution expired") + exception.set_backtrace bt + task.resume exception + end + yield + ensure + timer.cancel if timer + end + class Sleeper def initialize(timers, interval) @timers = timers @@ -316,15 +308,17 @@ when SystemEvent handle_system_event message when Call - task(:call, message.method) { - if @receiver_block_executions && meth = message.method - if meth == :__send__ - meth = message.arguments.first - end - if @receiver_block_executions.include?(meth.to_sym) - message.execute_block_on_receiver - end + meth = message.method + if meth == :__send__ + meth = message.arguments.first + end + if @receiver_block_executions && meth + if @receiver_block_executions.include?(meth.to_sym) + message.execute_block_on_receiver end + end + + task(:call, :method_name => meth, :dangerous_suspend => meth == :initialize) { message.dispatch(@subject) } when BlockCall @@ -332,7 +326,9 @@ when BlockResponse, Response message.dispatch else - @receivers.handle_message(message) + unless @receivers.handle_message(message) + Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG + end end message end @@ -341,13 +337,13 @@ def handle_system_event(event) case event when ExitEvent - task(:exit_handler, @exit_handler) { handle_exit_event event } + task(:exit_handler, :method_name => @exit_handler) { handle_exit_event event } when LinkingRequest event.process(links) when NamingRequest @name = event.name when TerminationRequest - @running = false + terminate when SignalConditionRequest event.call end @@ -384,45 +380,42 @@ # Run the user-defined finalizer, if one is set def run_finalizer - # FIXME: remove before Celluloid 1.0 - if @subject.respond_to?(:finalize) && @subject.class.finalizer != :finalize - Logger.warn("DEPRECATION WARNING: #{@subject.class}#finalize is deprecated and will be removed in Celluloid 1.0. " + - "Define finalizers with '#{@subject.class}.finalizer :callback.'") - - task(:finalizer, :finalize) { @subject.finalize } - end - finalizer = @subject.class.finalizer - if finalizer && @subject.respond_to?(finalizer, true) - task(:finalizer, :finalize) { @subject.__send__(finalizer) } + return unless finalizer && @subject.respond_to?(finalizer, true) + + task(:finalizer, :method_name => finalizer, :dangerous_suspend => true) do + begin + @subject.__send__(finalizer) + rescue => ex + Logger.crash("#{@subject.class}#finalize crashed!", ex) + end end - rescue => ex - Logger.crash("#{@subject.class}#finalize crashed!", ex) end # Clean up after this actor def cleanup(exit_event) @mailbox.shutdown @links.each do |actor| - begin + if actor.mailbox.alive? actor.mailbox << exit_event - rescue MailboxError - # We're exiting/crashing, they're dead. Give up :( end end - tasks.each { |task| task.terminate } + tasks.to_a.each { |task| task.terminate } rescue => ex Logger.crash("#{@subject.class}: CLEANUP CRASHED!", ex) end # Run a method inside a task unless it's exclusive - def task(task_type, method_name = nil, &block) - if @exclusives && (@exclusives == :all || (method_name && @exclusives.include?(method_name.to_sym))) - exclusive { block.call } - else - @task_class.new(task_type, &block).resume - end + def task(task_type, meta = nil) + method_name = meta && meta.fetch(:method_name, nil) + @task_class.new(task_type, meta) { + if @exclusives && (@exclusives == :all || (method_name && @exclusives.include?(method_name.to_sym))) + Celluloid.exclusive { yield } + else + yield + end + }.resume end end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/autostart.rb ruby-celluloid-0.15.2/lib/celluloid/autostart.rb --- ruby-celluloid-0.14.0/lib/celluloid/autostart.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/autostart.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,3 +1,3 @@ require 'celluloid' -Celluloid.boot +Celluloid.start diff -Nru ruby-celluloid-0.14.0/lib/celluloid/call_chain.rb ruby-celluloid-0.15.2/lib/celluloid/call_chain.rb --- ruby-celluloid-0.14.0/lib/celluloid/call_chain.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/call_chain.rb 2013-11-26 19:53:19.000000000 +0000 @@ -0,0 +1,13 @@ +module Celluloid + class CallChain + def self.current_id=(value) + Thread.current[:celluloid_chain_id] = value + task = Thread.current[:celluloid_task] + task.chain_id = value if task + end + + def self.current_id + Thread.current[:celluloid_chain_id] + end + end + end \ No newline at end of file diff -Nru ruby-celluloid-0.14.0/lib/celluloid/calls.rb ruby-celluloid-0.15.2/lib/celluloid/calls.rb --- ruby-celluloid-0.14.0/lib/celluloid/calls.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/calls.rb 2013-11-26 19:53:19.000000000 +0000 @@ -54,7 +54,7 @@ class SyncCall < Call attr_reader :sender, :task, :chain_id - def initialize(sender, method, arguments = [], block = nil, task = Thread.current[:celluloid_task], chain_id = Thread.current[:celluloid_chain_id]) + def initialize(sender, method, arguments = [], block = nil, task = Thread.current[:celluloid_task], chain_id = CallChain.current_id) super(method, arguments, block) @sender = sender @@ -63,7 +63,7 @@ end def dispatch(obj) - Thread.current[:celluloid_chain_id] = @chain_id + CallChain.current_id = @chain_id result = super(obj) respond SuccessResponse.new(self, result) rescue Exception => ex @@ -76,7 +76,7 @@ # Otherwise, it's a bug in this actor and should be reraised raise unless ex.is_a?(AbortError) ensure - Thread.current[:celluloid_chain_id] = nil + CallChain.current_id = nil end def cleanup @@ -86,9 +86,6 @@ def respond(message) @sender << message - rescue MailboxError - # It's possible the sender exited or crashed before we could send a - # response to them. end def value @@ -121,13 +118,13 @@ class AsyncCall < Call def dispatch(obj) - Thread.current[:celluloid_chain_id] = Celluloid.uuid + CallChain.current_id = Celluloid.uuid super(obj) rescue AbortError => ex # Swallow aborted async calls, as they indicate the sender made a mistake Logger.debug("#{obj.class}: async call `#@method` aborted!\n#{Logger.format_exception(ex.cause)}") ensure - Thread.current[:celluloid_chain_id] = nil + CallChain.current_id = nil end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/condition.rb ruby-celluloid-0.15.2/lib/celluloid/condition.rb --- ruby-celluloid-0.14.0/lib/celluloid/condition.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/condition.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,28 +1,49 @@ module Celluloid - class ConditionError < StandardError; end + class ConditionError < Celluloid::Error; end - # ConditionVariable-like signaling between tasks and actors + # ConditionVariable-like signaling between tasks and threads class Condition - attr_reader :owner + class Waiter + def initialize(condition, task, mailbox) + @condition = condition + @task = task + @mailbox = mailbox + end + attr_reader :condition, :task + + def <<(message) + @mailbox << message + end + + def wait + message = @mailbox.receive do |msg| + msg.is_a?(SignalConditionRequest) && msg.task == Thread.current + end + message.value + end + end def initialize @mutex = Mutex.new - @owner = Thread.current[:celluloid_actor] - @tasks = [] + @waiters = [] end # Wait for the given signal and return the associated value def wait raise ConditionError, "cannot wait for signals while exclusive" if Celluloid.exclusive? + if Thread.current[:celluloid_actor] + task = Task.current + else + task = Thread.current + end + waiter = Waiter.new(self, task, Celluloid.mailbox) + @mutex.synchronize do - actor = Thread.current[:celluloid_actor] - raise ConditionError, "can't wait for conditions outside actors" unless actor - raise ConditionError, "can't wait unless owner" unless actor == @owner - @tasks << Task.current + @waiters << waiter end - result = Task.suspend :condwait + result = Celluloid.suspend :condwait, waiter raise result if result.is_a? ConditionError result end @@ -30,38 +51,19 @@ # Send a signal to the first task waiting on this condition def signal(value = nil) @mutex.synchronize do - raise ConditionError, "no owner for this condition" unless @owner - - if task = @tasks.shift - @owner.mailbox << SignalConditionRequest.new(task, value) + if waiter = @waiters.shift + waiter << SignalConditionRequest.new(waiter.task, value) else Logger.debug("Celluloid::Condition signaled spuriously") end end end - # Broadcast a value to all waiting tasks + # Broadcast a value to all waiting tasks and threads def broadcast(value = nil) @mutex.synchronize do - raise ConditionError, "no owner for this condition" unless @owner - - @tasks.each { |task| @owner.mailbox << SignalConditionRequest.new(task, value) } - @tasks.clear - end - end - - # Change the owner of this condition - def owner=(actor) - @mutex.synchronize do - if @owner != actor - @tasks.each do |task| - ex = ConditionError.new("ownership changed") - @owner.mailbox << SignalConditionRequest.new(task, ex) - end - @tasks.clear - end - - @owner = actor + @waiters.each { |waiter| waiter << SignalConditionRequest.new(waiter.task, value) } + @waiters.clear end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/cpu_counter.rb ruby-celluloid-0.15.2/lib/celluloid/cpu_counter.rb --- ruby-celluloid-0.14.0/lib/celluloid/cpu_counter.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/cpu_counter.rb 2013-11-26 19:53:19.000000000 +0000 @@ -4,7 +4,7 @@ module CPUCounter case RbConfig::CONFIG['host_os'][/^[A-Za-z]+/] when 'darwin' - @cores = Integer(`sysctl hw.ncpu`[/\d+/]) + @cores = Integer(`/usr/sbin/sysctl hw.ncpu`[/\d+/]) when 'linux' @cores = if File.exists?("/sys/devices/system/cpu/present") File.read("/sys/devices/system/cpu/present").split('-').last.to_i+1 diff -Nru ruby-celluloid-0.14.0/lib/celluloid/evented_mailbox.rb ruby-celluloid-0.15.2/lib/celluloid/evented_mailbox.rb --- ruby-celluloid-0.14.0/lib/celluloid/evented_mailbox.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/evented_mailbox.rb 2013-11-26 19:53:19.000000000 +0000 @@ -13,26 +13,23 @@ def <<(message) @mutex.lock begin - if mailbox_full - Logger.debug "Discarded message: #{message}" + if mailbox_full || @dead + dead_letter(message) return end if message.is_a?(SystemEvent) - # Silently swallow system events sent to dead actors - return if @dead - # SystemEvents are high priority messages so they get added to the # head of our message queue instead of the end @messages.unshift message else - raise MailboxError, "dead recipient" if @dead @messages << message end current_actor = Thread.current[:celluloid_actor] @reactor.wakeup unless current_actor && current_actor.mailbox == self rescue IOError - raise MailboxError, "dead recipient" + Logger.crash "reactor crashed", $! + dead_letter(message) ensure @mutex.unlock rescue nil end @@ -59,7 +56,6 @@ message rescue IOError - shutdown # force shutdown of the mailbox raise MailboxShutdown, "mailbox shutdown called during receive" end @@ -75,8 +71,9 @@ # Cleanup any IO objects this Mailbox may be using def shutdown - @reactor.shutdown - super + super do + @reactor.shutdown + end end end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/fsm.rb ruby-celluloid-0.15.2/lib/celluloid/fsm.rb --- ruby-celluloid-0.14.0/lib/celluloid/fsm.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/fsm.rb 2013-11-26 19:53:19.000000000 +0000 @@ -13,7 +13,7 @@ # # # machine = MyMachine.new(current_actor) module FSM - class UnattachedError < StandardError; end # Not attached to an actor + class UnattachedError < Celluloid::Error; end # Not attached to an actor DEFAULT_STATE = :default # Default state name unless one is explicitly set diff -Nru ruby-celluloid-0.14.0/lib/celluloid/future.rb ruby-celluloid-0.15.2/lib/celluloid/future.rb --- ruby-celluloid-0.14.0/lib/celluloid/future.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/future.rb 2013-11-26 19:53:19.000000000 +0000 @@ -4,38 +4,29 @@ # Celluloid::Future objects allow methods and blocks to run in the # background, their values requested later class Future - attr_reader :address - - # Create a future bound to a given receiver, or with a block to compute - def initialize(*args, &block) - @address = Celluloid.uuid - @mutex = Mutex.new - @ready = false - @result = nil - @forwards = nil + def self.new(*args, &block) + return super unless block - if block - @call = SyncCall.new(self, :call, args) - Celluloid.internal_pool.get do - begin - @call.dispatch(block) - rescue - # Exceptions in blocks will get raised when the value is retrieved - end + future = new + Celluloid::ThreadHandle.new(:future) do + begin + call = SyncCall.new(future, :call, args) + call.dispatch(block) + rescue + # Exceptions in blocks will get raised when the value is retrieved end - else - @call = nil end + future end - # Execute the given method in future context - def execute(receiver, method, args, block) - @mutex.synchronize do - raise "already calling" if @call - @call = SyncCall.new(self, method, args, block) - end + attr_reader :address - receiver << @call + def initialize + @address = Celluloid.uuid + @mutex = Mutex.new + @ready = false + @result = nil + @forwards = nil end # Check if this future has a value yet @@ -49,7 +40,6 @@ begin @mutex.lock - raise "no call requested" unless @call if @ready ready = true diff -Nru ruby-celluloid-0.14.0/lib/celluloid/internal_pool.rb ruby-celluloid-0.15.2/lib/celluloid/internal_pool.rb --- ruby-celluloid-0.14.0/lib/celluloid/internal_pool.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/internal_pool.rb 2013-11-26 19:53:19.000000000 +0000 @@ -3,34 +3,76 @@ module Celluloid # Maintain a thread pool FOR SPEED!! class InternalPool - attr_accessor :busy_size, :idle_size, :max_idle + attr_accessor :max_idle def initialize - @pool = [] + @group = ThreadGroup.new @mutex = Mutex.new - @busy_size = @idle_size = 0 + @threads = [] - reset - end - - def reset # TODO: should really adjust this based on usage @max_idle = 16 + @running = true + end + + def busy_size + @threads.select(&:busy).size + end + + def idle_size + @threads.reject(&:busy).size + end + + def assert_running + unless running? + raise Error, "Thread pool is not running" + end + end + + def assert_inactive + if active? + message = "Thread pool is still active" + if defined?(JRUBY_VERSION) + Celluloid.logger.warn message + else + raise Error, message + end + end + end + + def running? + @running + end + + def active? + to_a.any? + end + + def each + @threads.each do |thread| + yield thread + end + end + + def to_a + @threads end # Get a thread from the pool, running the given block def get(&block) @mutex.synchronize do + assert_running + begin - if @pool.empty? + idle = @threads.reject(&:busy) + if idle.empty? thread = create else - thread = @pool.shift - @idle_size -= 1 + thread = idle.first end end until thread.status # handle crashed threads - @busy_size += 1 + thread.busy = true thread[:celluloid_queue] << block thread end @@ -39,13 +81,12 @@ # Return a thread to the pool def put(thread) @mutex.synchronize do - if @pool.size >= @max_idle + thread.busy = false + if idle_size >= @max_idle thread[:celluloid_queue] << nil + @threads.delete(thread) else - thread.recycle - @pool << thread - @idle_size += 1 - @busy_size -= 1 + clean_thread_locals(thread) end end end @@ -66,18 +107,44 @@ end thread[:celluloid_queue] = queue + @threads << thread + @group.add(thread) thread end + # Clean the thread locals of an incoming thread + def clean_thread_locals(thread) + thread.keys.each do |key| + next if key == :celluloid_queue + + # Ruby seems to lack an API for deleting thread locals. WTF, Ruby? + thread[key] = nil + end + end + def shutdown @mutex.synchronize do - @max_idle = 0 - @pool.each do |thread| + finalize + @threads.each do |thread| thread[:celluloid_queue] << nil end end end - end - self.internal_pool = InternalPool.new -end \ No newline at end of file + def kill + @mutex.synchronize do + finalize + @running = false + + @threads.shift.kill until @threads.empty? + @group.list.each(&:kill) + end + end + + private + + def finalize + @max_idle = 0 + end + end +end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/legacy.rb ruby-celluloid-0.15.2/lib/celluloid/legacy.rb --- ruby-celluloid-0.14.0/lib/celluloid/legacy.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/legacy.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,41 +1,3 @@ -module Celluloid - class ActorProxy - # method_missing black magic to call bang predicate methods asynchronously - def method_missing(meth, *args, &block) - # bang methods are async calls - if meth.match(/!$/) - Logger.deprecate("'bang method'-style async syntax is deprecated and will be removed in Celluloid 1.0." + - "Call async methods with 'actor.async.method'.") - - unbanged_meth = meth.to_s - unbanged_meth.slice!(-1, 1) - async unbanged_meth, *args, &block - else - super - end - end - end - - module InstanceMethods - # Process async calls via method_missing - def method_missing(meth, *args, &block) - # bang methods are async calls - if meth.to_s.match(/!$/) - Logger.deprecate("'bang method'-style async syntax is deprecated and will be removed in Celluloid 1.0." + - "Call async methods with 'actor.async.method'.") - - unbanged_meth = meth.to_s.sub(/!$/, '') - args.unshift unbanged_meth - - async :__send__, *args, &block - return - end - - super - end - end -end - class Thread def self.mailbox Celluloid.mailbox diff -Nru ruby-celluloid-0.14.0/lib/celluloid/mailbox.rb ruby-celluloid-0.15.2/lib/celluloid/mailbox.rb --- ruby-celluloid-0.14.0/lib/celluloid/mailbox.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/mailbox.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,8 +1,8 @@ require 'thread' module Celluloid - class MailboxError < StandardError; end # you can't message the dead - class MailboxShutdown < StandardError; end # raised if the mailbox can no longer be used + class MailboxDead < Celluloid::Error; end # you can't receive from the dead + class MailboxShutdown < Celluloid::Error; end # raised if the mailbox can no longer be used # Actors communicate with asynchronous messages. Messages are buffered in # Mailboxes until Actors can act upon them. @@ -26,19 +26,15 @@ def <<(message) @mutex.lock begin - if mailbox_full - Logger.debug "Discarded message: #{message}" + if mailbox_full || @dead + dead_letter(message) return end if message.is_a?(SystemEvent) - # Silently swallow system events sent to dead actors - return if @dead - # SystemEvents are high priority messages so they get added to the # head of our message queue instead of the end @messages.unshift message else - raise MailboxError, "dead recipient" if @dead @messages << message end @@ -55,7 +51,7 @@ @mutex.lock begin - raise MailboxError, "attempted to receive from a dead mailbox" if @dead + raise MailboxDead, "attempted to receive from a dead mailbox" if @dead begin message = next_message(&block) @@ -99,8 +95,11 @@ # Shut down this mailbox and clean up its contents def shutdown + raise MailboxDead, "mailbox already shutdown" if @dead + @mutex.lock begin + yield if block_given? messages = @messages @messages = [] @dead = true @@ -108,7 +107,10 @@ @mutex.unlock rescue nil end - messages.each { |msg| msg.cleanup if msg.respond_to? :cleanup } + messages.each do |msg| + dead_letter msg + msg.cleanup if msg.respond_to? :cleanup + end true end @@ -138,6 +140,11 @@ end private + + def dead_letter(message) + Logger.debug "Discarded message (mailbox is dead): #{message}" if $CELLULOID_DEBUG + end + def mailbox_full @max_size && @messages.size >= @max_size end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/pool_manager.rb ruby-celluloid-0.15.2/lib/celluloid/pool_manager.rb --- ruby-celluloid-0.14.0/lib/celluloid/pool_manager.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/pool_manager.rb 2013-11-26 19:53:19.000000000 +0000 @@ -27,7 +27,7 @@ terminators = (@idle + @busy).each do |actor| begin actor.future(:terminate) - rescue DeadActorError, MailboxError + rescue DeadActorError end end @@ -91,6 +91,7 @@ # Provision a new worker def __provision_worker__ + Task.current.guard_warnings = true while @idle.empty? # Wait for responses from one of the busy workers response = exclusive { receive { |msg| msg.is_a?(Response) } } diff -Nru ruby-celluloid-0.14.0/lib/celluloid/properties.rb ruby-celluloid-0.15.2/lib/celluloid/properties.rb --- ruby-celluloid-0.14.0/lib/celluloid/properties.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/properties.rb 2013-11-26 19:53:19.000000000 +0000 @@ -0,0 +1,24 @@ +module Celluloid + # Properties define inheritable attributes of classes, somewhat similar to + # Rails cattr_*/mattr_* or class_attribute + module Properties + def property(name, opts = {}) + default = opts.fetch(:default, nil) + multi = opts.fetch(:multi, false) + ivar_name = "@#{name}".to_sym + + ancestors.first.send(:define_singleton_method, name) do |value = nil, *extra| + if value + value = value ? [value, *extra] : [] if multi + instance_variable_set(ivar_name, value) + elsif instance_variables.include?(ivar_name) + instance_variable_get(ivar_name) + elsif superclass.respond_to? name + superclass.send(name) + else + default + end + end + end + end +end \ No newline at end of file diff -Nru ruby-celluloid-0.14.0/lib/celluloid/proxies/abstract_proxy.rb ruby-celluloid-0.15.2/lib/celluloid/proxies/abstract_proxy.rb --- ruby-celluloid-0.14.0/lib/celluloid/proxies/abstract_proxy.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/proxies/abstract_proxy.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,6 +1,9 @@ module Celluloid # Base class of all Celluloid proxies class AbstractProxy < BasicObject + # Used for reflecting on proxy objects themselves + def __class__; AbstractProxy; end + # Needed for storing proxies in data structures needed = [:object_id, :__id__, :hash] - instance_methods if needed.any? diff -Nru ruby-celluloid-0.14.0/lib/celluloid/proxies/actor_proxy.rb ruby-celluloid-0.15.2/lib/celluloid/proxies/actor_proxy.rb --- ruby-celluloid-0.14.0/lib/celluloid/proxies/actor_proxy.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/proxies/actor_proxy.rb 2013-11-26 19:53:19.000000000 +0000 @@ -4,6 +4,9 @@ class ActorProxy < SyncProxy attr_reader :thread + # Used for reflecting on proxy objects themselves + def __class__; ActorProxy; end + def initialize(actor) @thread = actor.thread @@ -13,14 +16,6 @@ @future_proxy = FutureProxy.new(@mailbox, @klass) end - def class - method_missing :__send__, :class - end - - def send(meth, *args, &block) - method_missing :send, meth, *args, &block - end - def _send_(meth, *args, &block) method_missing :__send__, meth, *args, &block end @@ -31,26 +26,6 @@ "#" end - def name - method_missing :name - end - - def is_a?(klass) - method_missing :is_a?, klass - end - - def kind_of?(klass) - method_missing :kind_of?, klass - end - - def respond_to?(meth, include_private = false) - method_missing :respond_to?, meth, include_private - end - - def methods(include_ancestors = true) - method_missing :methods, include_ancestors - end - def method(name) Method.new(self, name) end @@ -59,10 +34,6 @@ @mailbox.alive? end - def to_s - method_missing :to_s - end - alias_method :sync, :method_missing # Obtain an async proxy or explicitly invoke a named async method diff -Nru ruby-celluloid-0.14.0/lib/celluloid/proxies/async_proxy.rb ruby-celluloid-0.15.2/lib/celluloid/proxies/async_proxy.rb --- ruby-celluloid-0.14.0/lib/celluloid/proxies/async_proxy.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/proxies/async_proxy.rb 2013-11-26 19:53:19.000000000 +0000 @@ -3,6 +3,9 @@ class AsyncProxy < AbstractProxy attr_reader :mailbox + # Used for reflecting on proxy objects themselves + def __class__; AsyncProxy; end + def initialize(mailbox, klass) @mailbox, @klass = mailbox, klass end @@ -22,14 +25,7 @@ raise "Cannot use blocks with async yet" end - begin - @mailbox << AsyncCall.new(meth, args, block) - rescue MailboxError - # Silently swallow asynchronous calls to dead actors. There's no way - # to reliably generate DeadActorErrors for async calls, so users of - # async calls should find other ways to deal with actors dying - # during an async call (i.e. linking/supervisors) - end + @mailbox << AsyncCall.new(meth, args, block) end end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/proxies/future_proxy.rb ruby-celluloid-0.15.2/lib/celluloid/proxies/future_proxy.rb --- ruby-celluloid-0.14.0/lib/celluloid/proxies/future_proxy.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/proxies/future_proxy.rb 2013-11-26 19:53:19.000000000 +0000 @@ -3,6 +3,9 @@ class FutureProxy < AbstractProxy attr_reader :mailbox + # Used for reflecting on proxy objects themselves + def __class__; FutureProxy; end + def initialize(mailbox, klass) @mailbox, @klass = mailbox, klass end @@ -11,14 +14,21 @@ "#" end - # method_missing black magic to call bang predicate methods asynchronously def method_missing(meth, *args, &block) + unless @mailbox.alive? + raise DeadActorError, "attempted to call a dead actor" + end + if block_given? # FIXME: nicer exception raise "Cannot use blocks with futures yet" end + future = Future.new - future.execute(@mailbox, meth, args, block) + call = SyncCall.new(future, meth, args, block) + + @mailbox << call + future end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/proxies/sync_proxy.rb ruby-celluloid-0.15.2/lib/celluloid/proxies/sync_proxy.rb --- ruby-celluloid-0.14.0/lib/celluloid/proxies/sync_proxy.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/proxies/sync_proxy.rb 2013-11-26 19:53:19.000000000 +0000 @@ -3,6 +3,9 @@ class SyncProxy < AbstractProxy attr_reader :mailbox + # Used for reflecting on proxy objects themselves + def __class__; SyncProxy; end + def initialize(mailbox, klass) @mailbox, @klass = mailbox, klass end @@ -11,20 +14,22 @@ "#" end + def respond_to?(meth, include_private = false) + __class__.instance_methods.include?(meth) || super + end + def method_missing(meth, *args, &block) + unless @mailbox.alive? + raise DeadActorError, "attempted to call a dead actor" + end + if @mailbox == ::Thread.current[:celluloid_mailbox] args.unshift meth meth = :__send__ end call = SyncCall.new(::Celluloid.mailbox, meth, args, block) - - begin - @mailbox << call - rescue MailboxError - raise DeadActorError, "attempted to call a dead actor" - end - + @mailbox << call call.value end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/rspec.rb ruby-celluloid-0.15.2/lib/celluloid/rspec.rb --- ruby-celluloid-0.14.0/lib/celluloid/rspec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/rspec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -5,4 +5,8 @@ module Celluloid # Timer accuracy enforced by the tests (50ms) TIMER_QUANTUM = 0.05 -end \ No newline at end of file +end + +$CELLULOID_DEBUG = true + +require 'celluloid/test' diff -Nru ruby-celluloid-0.14.0/lib/celluloid/signals.rb ruby-celluloid-0.15.2/lib/celluloid/signals.rb --- ruby-celluloid-0.14.0/lib/celluloid/signals.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/signals.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,51 +1,23 @@ module Celluloid # Event signaling between methods of the same object class Signals - attr_reader :waiting - def initialize - @waiting = {} + @conditions = {} end # Wait for the given signal and return the associated value - def wait(signal) + def wait(name) raise "cannot wait for signals while exclusive" if Celluloid.exclusive? - tasks = @waiting[signal] - case tasks - when Array - tasks << Task.current - when NilClass - @waiting[signal] = Task.current - else - @waiting[signal] = [tasks, Task.current] - end - - Task.suspend :sigwait + @conditions[name] ||= Condition.new + @conditions[name].wait end # Send a signal to all method calls waiting for the given name - # Returns true if any calls were signaled, or false otherwise - def send(name, value = nil) - tasks = @waiting.delete name - - case tasks - when Array - tasks.each { |task| run_task task, value } - true if tasks.size > 0 - when NilClass - false - else - run_task tasks, value - true + def broadcast(name, value = nil) + if condition = @conditions.delete(name) + condition.broadcast(value) end end - - # Run the given task, reporting errors that occur - def run_task(task, value) - task.resume(value) - rescue => ex - Logger.crash("signaling error", ex) - end end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/stack_dump.rb ruby-celluloid-0.15.2/lib/celluloid/stack_dump.rb --- ruby-celluloid-0.14.0/lib/celluloid/stack_dump.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/stack_dump.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,16 +1,60 @@ module Celluloid class StackDump + module DisplayBacktrace + def display_backtrace(backtrace, output, indent = nil) + backtrace ||= ["EMPTY BACKTRACE"] + backtrace.each do |line| + output << indent if indent + output << "\t" << line << "\n" + end + output << "\n\n" + end + end - class TaskState < Struct.new(:task_class, :status, :backtrace) + class TaskState < Struct.new(:task_class, :type, :meta, :status, :backtrace) end class ActorState + include DisplayBacktrace + attr_accessor :subject_id, :subject_class, :name attr_accessor :status, :tasks attr_accessor :backtrace + + def dump + string = "" + string << "Celluloid::Actor 0x#{subject_id.to_s(16)}: #{subject_class}" + string << " [#{name}]" if name + string << "\n" + + if status == :idle + string << "State: Idle (waiting for messages)\n" + display_backtrace backtrace, string + else + string << "State: Running (executing tasks)\n" + display_backtrace backtrace, string + string << "\tTasks:\n" + + tasks.each_with_index do |task, i| + string << "\t #{i+1}) #{task.task_class}[#{task.type}]: #{task.status}\n" + string << "\t #{task.meta.inspect}\n" + display_backtrace task.backtrace, string, "\t" + end + end + + string + end end class ThreadState < Struct.new(:thread_id, :backtrace) + include DisplayBacktrace + + def dump + string = "" + string << "Thread 0x#{thread_id.to_s(16)}:\n" + display_backtrace backtrace, string + string + end end attr_accessor :actors, :threads @@ -23,9 +67,8 @@ end def snapshot - Thread.list.each do |thread| - if thread.celluloid? - next if thread.task + Celluloid.internal_pool.each do |thread| + if thread.role == :actor @actors << snapshot_actor(thread.actor) if thread.actor else @threads << snapshot_thread(thread) @@ -43,7 +86,7 @@ state.status = :idle else state.status = :running - state.tasks = tasks.collect { |t| TaskState.new(t.class, t.status, t.backtrace) } + state.tasks = tasks.to_a.map { |t| TaskState.new(t.class, t.type, t.meta, t.status, t.backtrace) } end state.backtrace = actor.thread.backtrace if actor.thread @@ -56,41 +99,11 @@ def dump(output = STDERR) @actors.each do |actor| - string = "" - string << "Celluloid::Actor 0x#{actor.subject_id.to_s(16)}: #{actor.subject_class}" - string << " [#{actor.name}]" if actor.name - string << "\n" - - if actor.status == :idle - string << "State: Idle (waiting for messages)\n" - display_backtrace actor.backtrace, string - else - string << "State: Running (executing tasks)\n" - display_backtrace actor.backtrace, string - string << "Tasks:\n" - - actor.tasks.each_with_index do |task, i| - string << " #{i+1}) #{task.task_class}: #{task.status}\n" - display_backtrace task.backtrace, string - end - end - - output.print string + output.print actor.dump end @threads.each do |thread| - string = "" - string << "Thread 0x#{thread.thread_id.to_s(16)}:\n" - display_backtrace thread.backtrace, string - output.print string - end - end - - def display_backtrace(backtrace, output) - if backtrace - output << "\t" << backtrace.join("\n\t") << "\n\n" - else - output << "EMPTY BACKTRACE\n\n" + output.print thread.dump end end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/supervision_group.rb ruby-celluloid-0.15.2/lib/celluloid/supervision_group.rb --- ruby-celluloid-0.14.0/lib/celluloid/supervision_group.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/supervision_group.rb 2013-11-26 19:53:19.000000000 +0000 @@ -11,8 +11,8 @@ end # Start this application (and watch it with a supervisor) - def run! - group = new do |_group| + def run!(registry = nil) + group = new(registry) do |_group| blocks.each do |block| block.call(_group) end @@ -21,9 +21,9 @@ end # Run the application in the foreground with a simple watchdog - def run + def run(registry = nil) loop do - supervisor = run! + supervisor = run!(registry) # Take five, toplevel supervisor sleep 5 while supervisor.alive? @@ -148,8 +148,9 @@ end def terminate + @registry.delete(@name) if @name @actor.terminate if @actor - rescue DeadActorError, MailboxError + rescue DeadActorError end end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/system_events.rb ruby-celluloid-0.15.2/lib/celluloid/system_events.rb --- ruby-celluloid-0.14.0/lib/celluloid/system_events.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/system_events.rb 2013-11-26 19:53:19.000000000 +0000 @@ -57,6 +57,7 @@ def initialize(task, value) @task, @value = task, value end + attr_reader :task, :value def call @task.resume(@value) diff -Nru ruby-celluloid-0.14.0/lib/celluloid/task_set.rb ruby-celluloid-0.15.2/lib/celluloid/task_set.rb --- ruby-celluloid-0.14.0/lib/celluloid/task_set.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/task_set.rb 2013-11-26 19:53:19.000000000 +0000 @@ -0,0 +1,49 @@ +require 'set' +require 'forwardable' + +module Celluloid + if defined? JRUBY_VERSION + require 'jruby/synchronized' + + class TaskSet + extend Forwardable + include JRuby::Synchronized + + def_delegators :@tasks, :<<, :delete, :first, :empty?, :to_a + + def initialize + @tasks = Set.new + end + end + elsif defined? Rubinius + class TaskSet + def initialize + @tasks = Set.new + end + + def <<(task) + Rubinius.synchronize(self) { @tasks << task } + end + + def delete(task) + Rubinius.synchronize(self) { @tasks.delete task } + end + + def first + Rubinius.synchronize(self) { @tasks.first } + end + + def empty? + Rubinius.synchronize(self) { @tasks.empty? } + end + + def to_a + Rubinius.synchronize(self) { @tasks.to_a } + end + end + else + # Assume we're on MRI, where we have the GIL. But what about IronRuby? + # Or MacRuby. Do people care? This will break Celluloid::StackDumps + TaskSet = Set + end +end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/tasks/task_fiber.rb ruby-celluloid-0.15.2/lib/celluloid/tasks/task_fiber.rb --- ruby-celluloid-0.14.0/lib/celluloid/tasks/task_fiber.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/tasks/task_fiber.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,11 +1,15 @@ module Celluloid - class FiberStackError < StandardError; end + class FiberStackError < Celluloid::Error; end # Tasks with a Fiber backend class TaskFiber < Task def create + queue = Thread.current[:celluloid_queue] @fiber = Fiber.new do + # FIXME: cannot use the writer as specs run inside normal Threads + Thread.current[:celluloid_role] = :actor + Thread.current[:celluloid_queue] = queue yield end end @@ -30,4 +34,4 @@ # If we're getting this the task should already be dead end end -end \ No newline at end of file +end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/tasks/task_thread.rb ruby-celluloid-0.15.2/lib/celluloid/tasks/task_thread.rb --- ruby-celluloid-0.14.0/lib/celluloid/tasks/task_thread.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/tasks/task_thread.rb 2013-11-26 19:53:19.000000000 +0000 @@ -2,7 +2,7 @@ # Tasks with a Thread backend class TaskThread < Task # Run the given block within a task - def initialize(type) + def initialize(type, meta) @resume_queue = Queue.new @exception_queue = Queue.new @yield_mutex = Mutex.new @@ -12,7 +12,7 @@ end def create - @thread = Celluloid.internal_pool.get do + @thread = Celluloid::ThreadHandle.new(:task) do begin ex = @resume_queue.pop raise ex if ex.is_a?(Task::TerminatedError) diff -Nru ruby-celluloid-0.14.0/lib/celluloid/tasks.rb ruby-celluloid-0.15.2/lib/celluloid/tasks.rb --- ruby-celluloid-0.14.0/lib/celluloid/tasks.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/tasks.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,13 +1,18 @@ module Celluloid # Asked to do task-related things outside a task - class NotTaskError < StandardError; end + class NotTaskError < Celluloid::Error; end # Trying to resume a dead task - class DeadTaskError < StandardError; end + class DeadTaskError < Celluloid::Error; end + + # Errors which should be resumed automatically + class ResumableError < Celluloid::Error; end # Tasks are interruptable/resumable execution contexts used to run methods class Task - class TerminatedError < StandardError; end # kill a running task + class TerminatedError < ResumableError; end # kill a running task after terminate + + class TimeoutError < ResumableError; end # kill a running task after timeout # Obtain the current task def self.current @@ -19,24 +24,32 @@ Task.current.suspend(status) end - attr_reader :type, :status + attr_reader :type, :meta, :status + attr_accessor :chain_id, :guard_warnings # Create a new task - def initialize(type) - @type = type - @status = :new + def initialize(type, meta) + @type = type + @meta = meta + @status = :new + + @exclusive = false + @dangerous_suspend = @meta ? @meta.delete(:dangerous_suspend) : false + @guard_warnings = false - actor = Thread.current[:celluloid_actor] - chain_id = Thread.current[:celluloid_chain_id] + actor = Thread.current[:celluloid_actor] + @chain_id = CallChain.current_id raise NotActorError, "can't create tasks outside of actors" unless actor + guard "can't create tasks inside of tasks" if Thread.current[:celluloid_task] create do begin @status = :running actor.setup_thread - Thread.current[:celluloid_task] = self - Thread.current[:celluloid_chain_id] = chain_id + + Thread.current[:celluloid_task] = self + CallChain.current_id = @chain_id actor.tasks << self yield @@ -55,24 +68,68 @@ # Suspend the current task, changing the status to the given argument def suspend(status) + raise "Cannot suspend while in exclusive mode" if exclusive? + raise "Cannot suspend a task from outside of itself" unless Task.current == self + @status = status + + if $CELLULOID_DEBUG && @dangerous_suspend + warning = "Dangerously suspending task: " + warning << [ + "type=#{@type.inspect}", + "meta=#{@meta.inspect}", + "status=#{@status.inspect}" + ].join(", ") + + Logger.warn [warning, *caller[2..8]].join("\n\t") + end + value = signal - raise value if value.is_a?(Task::TerminatedError) @status = :running + raise value if value.is_a?(Celluloid::ResumableError) value end # Resume a suspended task, giving it a value to return if needed def resume(value = nil) + guard "Cannot resume a task from inside of a task" if Thread.current[:celluloid_task] deliver(value) nil end + # Execute a code block in exclusive mode. + def exclusive + if @exclusive + yield + else + begin + @exclusive = true + yield + ensure + @exclusive = false + end + end + end + # Terminate this task def terminate - resume Task::TerminatedError.new("task was terminated") if running? + raise "Cannot terminate an exclusive task" if exclusive? + + if running? + Celluloid.logger.warn "Terminating task: type=#{@type.inspect}, meta=#{@meta.inspect}, status=#{@status.inspect}" + exception = Task::TerminatedError.new("task was terminated") + exception.set_backtrace(caller) + resume exception + else + raise DeadTaskError, "task is already dead" + end + end + + # Is this task running in exclusive mode? + def exclusive? + @exclusive end def backtrace @@ -83,35 +140,15 @@ # Nicer string inspect for tasks def inspect - "#<#{self.class}:0x#{object_id.to_s(16)} @type=#{@type.inspect}, @status=#{@status.inspect}>" + "#<#{self.class}:0x#{object_id.to_s(16)} @type=#{@type.inspect}, @meta=#{@meta.inspect}, @status=#{@status.inspect}>" end - end - - class TaskSet - include Enumerable - - def initialize - @tasks = Set.new - end - - def <<(task) - @tasks += [task] - end - - def delete(task) - @tasks -= [task] - end - - def each(&blk) - @tasks.each(&blk) - end - - def first - @tasks.first - end - - def empty? - @tasks.empty? + + def guard(message) + if @guard_warnings + Logger.warn message if $CELLULOID_DEBUG + else + raise message if $CELLULOID_DEBUG + end end end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/test.rb ruby-celluloid-0.15.2/lib/celluloid/test.rb --- ruby-celluloid-0.14.0/lib/celluloid/test.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/test.rb 2013-11-26 19:53:19.000000000 +0000 @@ -0,0 +1,3 @@ +$CELLULOID_TEST = true + +require 'celluloid' diff -Nru ruby-celluloid-0.14.0/lib/celluloid/thread.rb ruby-celluloid-0.15.2/lib/celluloid/thread.rb --- ruby-celluloid-0.14.0/lib/celluloid/thread.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/thread.rb 2013-11-26 19:53:19.000000000 +0000 @@ -2,20 +2,21 @@ module Celluloid class Thread < ::Thread - # FIXME: these should be replaced using APIs on Celluloid::Thread itself - # e.g. Thread.current[:celluloid_actor] => Thread.current.actor - CELLULOID_LOCALS = [ - :celluloid_actor, - :celluloid_mailbox, - :celluloid_queue, - :celluloid_task, - :celluloid_chain_id - ] - def celluloid? true end + attr_accessor :busy + + # Obtain the role of this thread + def role + self[:celluloid_role] + end + + def role=(role) + self[:celluloid_role] = role + end + # Obtain the Celluloid::Actor object for this thread def actor self[:celluloid_actor] @@ -35,58 +36,5 @@ def call_chain_id self[:celluloid_chain_id] end - - # - # Override default thread local behavior, making thread locals actor-local - # - - # Obtain an actor-local value - def [](key) - actor = super(:celluloid_actor) - if !actor || CELLULOID_LOCALS.include?(key) - super(key) - else - actor.locals[key] - end - end - - # Set an actor-local value - def []=(key, value) - actor = self[:celluloid_actor] - if !actor || CELLULOID_LOCALS.include?(key) - super(key, value) - else - actor.locals[key] = value - end - end - - # Obtain the keys to all actor-locals - def keys - actor = self[:celluloid_actor] - if actor - actor.locals.keys - else - super - end - end - - # Is the given actor local set? - def key?(key) - actor = self[:celluloid_actor] - if actor - actor.locals.has_key?(key) - else - super - end - end - - # Clear thread state so it can be reused via thread pools - def recycle - # This thread local mediates access to the others, so we must clear it first - self[:celluloid_actor] = nil - - # Clearing :celluloid_queue would break the thread pool! - keys.each { |key| self[key] = nil unless key == :celluloid_queue } - end end end diff -Nru ruby-celluloid-0.14.0/lib/celluloid/thread_handle.rb ruby-celluloid-0.15.2/lib/celluloid/thread_handle.rb --- ruby-celluloid-0.14.0/lib/celluloid/thread_handle.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/thread_handle.rb 2013-11-26 19:53:19.000000000 +0000 @@ -3,11 +3,12 @@ # accidentally do things to threads which have been returned to the pool, # such as, say, killing them class ThreadHandle - def initialize + def initialize(role = nil) @mutex = Mutex.new @join = ConditionVariable.new @thread = Celluloid.internal_pool.get do + Thread.current.role = role begin yield ensure diff -Nru ruby-celluloid-0.14.0/lib/celluloid/version.rb ruby-celluloid-0.15.2/lib/celluloid/version.rb --- ruby-celluloid-0.14.0/lib/celluloid/version.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid/version.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -module Celluloid - VERSION = '0.14.0' - def self.version; VERSION; end -end diff -Nru ruby-celluloid-0.14.0/lib/celluloid.rb ruby-celluloid-0.15.2/lib/celluloid.rb --- ruby-celluloid-0.14.0/lib/celluloid.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/lib/celluloid.rb 2013-11-26 19:53:19.000000000 +0000 @@ -3,7 +3,14 @@ require 'timeout' require 'set' +if defined?(JRUBY_VERSION) && JRUBY_VERSION == "1.7.3" + raise "Celluloid is broken on JRuby 1.7.3. Please upgrade to 1.7.4+" +end + module Celluloid + VERSION = '0.15.2' + Error = Class.new StandardError + extend self # expose all instance methods as singleton methods # Warning message added to Celluloid objects accessed outside their actors @@ -18,6 +25,24 @@ def included(klass) klass.send :extend, ClassMethods klass.send :include, InstanceMethods + + klass.send :extend, Properties + + klass.property :mailbox_class, :default => Celluloid::Mailbox + klass.property :proxy_class, :default => Celluloid::ActorProxy + klass.property :task_class, :default => Celluloid.task_class + klass.property :mailbox_size + + klass.property :execute_block_on_receiver, + :default => [:after, :every, :receive], + :multi => true + + klass.property :finalizer + klass.property :exit_handler + + klass.send(:define_singleton_method, :trap_exit) do |*args| + exit_handler(*args) + end end # Are we currently inside of an actor? @@ -48,6 +73,18 @@ end alias_method :dump, :stack_dump + # Detect if a particular call is recursing through multiple actors + def detect_recursion + actor = Thread.current[:celluloid_actor] + return unless actor + + task = Thread.current[:celluloid_task] + return unless task + + chain_id = CallChain.current_id + actor.tasks.to_a.any? { |t| t != task && t.chain_id == chain_id } + end + # Define an exception handler for actor crashes def exception_handler(&block) Logger.exception_handler(&block) @@ -63,14 +100,26 @@ end end + def boot + init + start + end + + def init + self.internal_pool = InternalPool.new + end + # Launch default services # FIXME: We should set up the supervision hierarchy here - def boot - internal_pool.reset + def start Celluloid::Notifications::Fanout.supervise_as :notifications_fanout Celluloid::IncidentReporter.supervise_as :default_incident_reporter, STDERR end + def running? + internal_pool + end + def register_shutdown return if @shutdown_registered # Terminate all actors at exit @@ -90,11 +139,12 @@ # Shut down all running actors def shutdown + actors = Actor.all + Timeout.timeout(shutdown_timeout) do internal_pool.shutdown - actors = Actor.all - Logger.debug "Terminating #{actors.size} actors..." if actors.size > 0 + Logger.debug "Terminating #{actors.size} #{(actors.size > 1) ? 'actors' : 'actor'}..." if actors.size > 0 # Attempt to shut down the supervision tree, if available Supervisor.root.terminate if Supervisor.root @@ -103,21 +153,31 @@ actors.each do |actor| begin actor.terminate! - rescue DeadActorError, MailboxError + rescue DeadActorError end end actors.each do |actor| begin Actor.join(actor) - rescue DeadActorError, MailboxError + rescue DeadActorError end end - - Logger.debug "Shutdown completed cleanly" end rescue Timeout::Error Logger.error("Couldn't cleanly terminate all actors in #{shutdown_timeout} seconds!") + actors.each do |actor| + begin + Actor.kill(actor) + rescue DeadActorError, MailboxDead + end + end + ensure + internal_pool.kill + end + + def version + VERSION end end @@ -173,63 +233,6 @@ Actor.join(new(*args, &block)) end - # Trap errors from actors we're linked to when they exit - def exit_handler(callback = nil) - if callback - @exit_handler = callback.to_sym - elsif defined?(@exit_handler) - @exit_handler - elsif superclass.respond_to? :exit_handler - superclass.exit_handler - end - end - alias_method :trap_exit, :exit_handler - - # Define a callback to run when the actor is finalized. - def finalizer(callback = nil) - if callback - @finalizer = callback.to_sym - elsif defined?(@finalizer) - @finalizer - elsif superclass.respond_to? :finalizer - superclass.finalizer - end - end - - # Define the mailbox class for this class - def mailbox_class(klass = nil) - if klass - mailbox.class = klass - else - mailbox.class - end - end - - def proxy_class(klass = nil) - if klass - @proxy_class = klass - elsif defined?(@proxy_class) - @proxy_class - elsif superclass.respond_to? :proxy_class - superclass.proxy_class - else - Celluloid::ActorProxy - end - end - - # Define the default task type for this class - def task_class(klass = nil) - if klass - @task_class = klass - elsif defined?(@task_class) - @task_class - elsif superclass.respond_to? :task_class - superclass.task_class - else - Celluloid.task_class - end - end - # Mark methods as running exclusively def exclusive(*methods) if methods.empty? @@ -240,55 +243,22 @@ end end - # Mark methods as running blocks on the receiver - def execute_block_on_receiver(*methods) - receiver_block_executions.merge methods.map(&:to_sym) - end - - def receiver_block_executions - @receiver_block_executions ||= Set.new([:after, :every, :receive]) - end - # Configuration options for Actor#new def actor_options { - :mailbox => mailbox.build, + :mailbox_class => mailbox_class, + :mailbox_size => mailbox_size, :proxy_class => proxy_class, :task_class => task_class, :exit_handler => exit_handler, :exclusive_methods => defined?(@exclusive_methods) ? @exclusive_methods : nil, - :receiver_block_executions => receiver_block_executions + :receiver_block_executions => execute_block_on_receiver } end def ===(other) other.kind_of? self end - - def mailbox - @mailbox_factory ||= MailboxFactory.new(self) - end - - class MailboxFactory - attr_accessor :class, :max_size - - def initialize(actor) - @actor = actor - @class = nil - @max_size = nil - end - - def build - mailbox = mailbox_class.new - mailbox.max_size = @max_size - mailbox - end - - private - def mailbox_class - @class || (@actor.superclass.respond_to?(:mailbox_class) && @actor.superclass.mailbox_class) || Celluloid::Mailbox - end - end end # These are methods we don't want added to the Celluloid singleton but to be @@ -326,6 +296,8 @@ end def inspect + return "..." if Celluloid.detect_recursion + str = "#<" if leaked? @@ -363,7 +335,7 @@ # Terminate this actor def terminate - Thread.current[:celluloid_actor].terminate + Thread.current[:celluloid_actor].proxy.terminate! end # Send a signal with the given name to all waiting methods @@ -383,7 +355,7 @@ # Obtain the UUID of the current call chain def call_chain_id - Thread.current[:celluloid_chain_id] + CallChain.current_id end # Obtain the running tasks for this actor @@ -446,16 +418,23 @@ end end + # Timeout on task suspension (eg Sync calls to other actors) + def timeout(duration) + Thread.current[:celluloid_actor].timeout(duration) do + yield + end + end + # Run given block in an exclusive mode: all synchronous calls block the whole # actor, not only current message processing. def exclusive(&block) - Thread.current[:celluloid_actor].exclusive(&block) + Thread.current[:celluloid_task].exclusive(&block) end # Are we currently exclusive def exclusive? - actor = Thread.current[:celluloid_actor] - actor && actor.exclusive? + task = Thread.current[:celluloid_task] + task && task.exclusive? end # Call a block after a given interval, returning a Celluloid::Timer object @@ -488,9 +467,8 @@ end end -require 'celluloid/version' - require 'celluloid/calls' +require 'celluloid/call_chain' require 'celluloid/condition' require 'celluloid/thread' require 'celluloid/core_ext' @@ -503,6 +481,7 @@ require 'celluloid/mailbox' require 'celluloid/evented_mailbox' require 'celluloid/method' +require 'celluloid/properties' require 'celluloid/receivers' require 'celluloid/registry' require 'celluloid/responses' @@ -510,6 +489,7 @@ require 'celluloid/stack_dump' require 'celluloid/system_events' require 'celluloid/tasks' +require 'celluloid/task_set' require 'celluloid/thread_handle' require 'celluloid/uuid' @@ -534,4 +514,8 @@ Celluloid.task_class = Celluloid::TaskFiber Celluloid.logger = Logger.new(STDERR) Celluloid.shutdown_timeout = 10 -Celluloid.register_shutdown + +unless $CELLULOID_TEST + Celluloid.register_shutdown + Celluloid.init +end diff -Nru ruby-celluloid-0.14.0/log/.gitignore ruby-celluloid-0.15.2/log/.gitignore --- ruby-celluloid-0.14.0/log/.gitignore 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/log/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -*.log diff -Nru ruby-celluloid-0.14.0/metadata.yml ruby-celluloid-0.15.2/metadata.yml --- ruby-celluloid-0.14.0/metadata.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-celluloid-0.15.2/metadata.yml 2013-11-26 19:53:19.000000000 +0000 @@ -0,0 +1,193 @@ +--- !ruby/object:Gem::Specification +name: celluloid +version: !ruby/object:Gem::Version + version: 0.15.2 +platform: ruby +authors: +- Tony Arcieri +autorequire: +bindir: bin +cert_chain: [] +date: 2013-10-06 00:00:00.000000000 Z +dependencies: +- !ruby/object:Gem::Dependency + name: timers + requirement: !ruby/object:Gem::Requirement + requirements: + - - ~> + - !ruby/object:Gem::Version + version: 1.1.0 + type: :runtime + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ~> + - !ruby/object:Gem::Version + version: 1.1.0 +- !ruby/object:Gem::Dependency + name: rake + requirement: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: '0' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: '0' +- !ruby/object:Gem::Dependency + name: rspec + requirement: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: '0' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: '0' +- !ruby/object:Gem::Dependency + name: guard-rspec + requirement: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: '0' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: '0' +- !ruby/object:Gem::Dependency + name: benchmark_suite + requirement: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: '0' + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: '0' +description: Celluloid enables people to build concurrent programs out of concurrent + objects just as easily as they build sequential programs out of sequential objects +email: +- tony.arcieri@gmail.com +executables: [] +extensions: [] +extra_rdoc_files: [] +files: +- README.md +- lib/celluloid/actor.rb +- lib/celluloid/autostart.rb +- lib/celluloid/call_chain.rb +- lib/celluloid/calls.rb +- lib/celluloid/condition.rb +- lib/celluloid/core_ext.rb +- lib/celluloid/cpu_counter.rb +- lib/celluloid/evented_mailbox.rb +- lib/celluloid/fiber.rb +- lib/celluloid/fsm.rb +- lib/celluloid/future.rb +- lib/celluloid/internal_pool.rb +- lib/celluloid/legacy.rb +- lib/celluloid/links.rb +- lib/celluloid/logger.rb +- lib/celluloid/logging/incident.rb +- lib/celluloid/logging/incident_logger.rb +- lib/celluloid/logging/incident_reporter.rb +- lib/celluloid/logging/log_event.rb +- lib/celluloid/logging/ring_buffer.rb +- lib/celluloid/logging.rb +- lib/celluloid/mailbox.rb +- lib/celluloid/method.rb +- lib/celluloid/notifications.rb +- lib/celluloid/pool_manager.rb +- lib/celluloid/properties.rb +- lib/celluloid/proxies/abstract_proxy.rb +- lib/celluloid/proxies/actor_proxy.rb +- lib/celluloid/proxies/async_proxy.rb +- lib/celluloid/proxies/block_proxy.rb +- lib/celluloid/proxies/future_proxy.rb +- lib/celluloid/proxies/sync_proxy.rb +- lib/celluloid/receivers.rb +- lib/celluloid/registry.rb +- lib/celluloid/responses.rb +- lib/celluloid/rspec.rb +- lib/celluloid/signals.rb +- lib/celluloid/stack_dump.rb +- lib/celluloid/supervision_group.rb +- lib/celluloid/supervisor.rb +- lib/celluloid/system_events.rb +- lib/celluloid/task_set.rb +- lib/celluloid/tasks/task_fiber.rb +- lib/celluloid/tasks/task_thread.rb +- lib/celluloid/tasks.rb +- lib/celluloid/test.rb +- lib/celluloid/thread.rb +- lib/celluloid/thread_handle.rb +- lib/celluloid/uuid.rb +- lib/celluloid.rb +- spec/celluloid/actor_spec.rb +- spec/celluloid/block_spec.rb +- spec/celluloid/calls_spec.rb +- spec/celluloid/condition_spec.rb +- spec/celluloid/evented_mailbox_spec.rb +- spec/celluloid/fsm_spec.rb +- spec/celluloid/future_spec.rb +- spec/celluloid/internal_pool_spec.rb +- spec/celluloid/links_spec.rb +- spec/celluloid/logging/ring_buffer_spec.rb +- spec/celluloid/mailbox_spec.rb +- spec/celluloid/notifications_spec.rb +- spec/celluloid/pool_spec.rb +- spec/celluloid/properties_spec.rb +- spec/celluloid/registry_spec.rb +- spec/celluloid/stack_dump_spec.rb +- spec/celluloid/supervision_group_spec.rb +- spec/celluloid/supervisor_spec.rb +- spec/celluloid/tasks/task_fiber_spec.rb +- spec/celluloid/tasks/task_thread_spec.rb +- spec/celluloid/thread_handle_spec.rb +- spec/celluloid/uuid_spec.rb +- spec/spec_helper.rb +- spec/support/actor_examples.rb +- spec/support/example_actor_class.rb +- spec/support/mailbox_examples.rb +- spec/support/task_examples.rb +homepage: https://github.com/celluloid/celluloid +licenses: +- MIT +metadata: {} +post_install_message: +rdoc_options: [] +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: 1.9.2 +required_rubygems_version: !ruby/object:Gem::Requirement + requirements: + - - '>=' + - !ruby/object:Gem::Version + version: 1.3.6 +requirements: [] +rubyforge_project: +rubygems_version: 2.0.3 +signing_key: +specification_version: 4 +summary: Actor-based concurrent object framework for Ruby +test_files: [] diff -Nru ruby-celluloid-0.14.0/spec/celluloid/calls_spec.rb ruby-celluloid-0.15.2/spec/celluloid/calls_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/calls_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/calls_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -39,4 +39,4 @@ uuid, next_actor_uuid = actor2.chained_call_ids uuid.should eq next_actor_uuid end -end \ No newline at end of file +end diff -Nru ruby-celluloid-0.14.0/spec/celluloid/condition_spec.rb ruby-celluloid-0.15.2/spec/celluloid/condition_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/condition_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/condition_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -13,6 +13,10 @@ @signaled_times = 0 end + def signal_condition(condition, value) + condition.signal value + end + def wait_for_condition @waiting = true begin @@ -53,16 +57,9 @@ future.value.should be(:example_value) end - it "transfers ownership between actors" do - another_actor = ConditionExample.new - begin - future = actor.future(:wait_for_condition) - condition = actor.condition - condition.owner = another_actor - condition.owner.should eq another_actor - expect { future.value }.to raise_exception(Celluloid::ConditionError) - ensure - another_actor.terminate - end + it "supports waiting outside actors" do + condition = Celluloid::Condition.new + actor.async.signal_condition condition, :value + condition.wait.should eq(:value) end end diff -Nru ruby-celluloid-0.14.0/spec/celluloid/fsm_spec.rb ruby-celluloid-0.15.2/spec/celluloid/fsm_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/fsm_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/fsm_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -31,7 +31,7 @@ end end - let(:subject) { TestMachine.new } + subject { TestMachine.new } it "starts in the default state" do subject.state.should eq(TestMachine.default_state) @@ -86,8 +86,6 @@ end context "actor is not set" do - let(:subject) { TestMachine.new } - context "transition is delayed" do it "raises an unattached error" do expect { subject.transition :another, :delay => 100 } \ @@ -97,8 +95,6 @@ end context "transitioning to an invalid state" do - let(:subject) { TestMachine.new } - it "raises an argument error" do expect { subject.transition :invalid_state }.to raise_error(ArgumentError) end diff -Nru ruby-celluloid-0.14.0/spec/celluloid/internal_pool_spec.rb ruby-celluloid-0.15.2/spec/celluloid/internal_pool_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/internal_pool_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/internal_pool_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -28,4 +28,25 @@ sleep 0.01 #hax thread[:foo].should be_nil end + + it "doesn't fail if a third-party thread is spawned" do + subject.idle_size.should be_zero + subject.busy_size.should be_zero + + subject.get { ::Thread.new { sleep 0.5 } }.should be_a(Celluloid::Thread) + + sleep 0.01 # hax + + subject.idle_size.should eq 1 + subject.busy_size.should eq 0 + end + + it "doesn't leak dead threads" do + subject.max_idle = 0 # Instruct the pool to immediately shut down the thread. + subject.get { true }.should be_a(Celluloid::Thread) + + sleep 0.01 # hax + + subject.to_a.should have(0).items + end end diff -Nru ruby-celluloid-0.14.0/spec/celluloid/links_spec.rb ruby-celluloid-0.15.2/spec/celluloid/links_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/links_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/links_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -2,7 +2,7 @@ describe Celluloid::Links do subject { Celluloid::Links.new } - + let(:mailbox_mock) do Class.new(Array) do attr_reader :address @@ -21,7 +21,7 @@ end it 'is Enumerable' do - subject.is_a?(Enumerable).should be_true + subject.should be_an(Enumerable) end it 'adds actors by their mailbox address' do @@ -42,4 +42,4 @@ subject << second_actor subject.inject([]) { |all, a| all << a }.should == [first_actor, second_actor] end -end \ No newline at end of file +end diff -Nru ruby-celluloid-0.14.0/spec/celluloid/pool_spec.rb ruby-celluloid-0.15.2/spec/celluloid/pool_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/pool_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/pool_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -49,4 +49,11 @@ it "terminates" do expect { subject.terminate }.to_not raise_exception end + + it "handles many requests" do + futures = 10.times.map do + subject.future.process + end + futures.map(&:value) + end end diff -Nru ruby-celluloid-0.14.0/spec/celluloid/properties_spec.rb ruby-celluloid-0.15.2/spec/celluloid/properties_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/properties_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/properties_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Celluloid::Properties do + let(:default_value) { 42 } + let(:changed_value) { 43 } + + let(:example_class) do + Class.new do + extend Celluloid::Properties + property :baz, :default => 42 + end + end + + let(:example_subclass) do + Class.new(example_class) + end + + let(:example_subclass_subclass) do + Class.new(example_subclass) + end + + it "adds properties to classes" do + example_class.baz.should eq default_value + example_class.baz changed_value + example_class.baz.should eq changed_value + end + + it "allows properties to be inherited" do + example_subclass.baz.should eq default_value + example_subclass.baz changed_value + example_subclass.baz.should eq changed_value + example_class.baz.should eq default_value + end + + it "allows properties to be deeply inherited" do + example_subclass_subclass.baz.should eq default_value + example_subclass_subclass.baz changed_value + example_subclass_subclass.baz.should eq changed_value + example_subclass.baz.should eq default_value + example_class.baz.should eq default_value + end +end \ No newline at end of file diff -Nru ruby-celluloid-0.14.0/spec/celluloid/stack_dump_spec.rb ruby-celluloid-0.15.2/spec/celluloid/stack_dump_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/stack_dump_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/stack_dump_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,12 +1,35 @@ require 'spec_helper' describe Celluloid::StackDump do + class BlockingActor + include Celluloid + + def blocking + Kernel.sleep + end + end + + before(:each) do + [Celluloid::TaskFiber, Celluloid::TaskThread].each do |task_klass| + actor_klass = Class.new(BlockingActor) do + task_class task_klass + end + actor = actor_klass.new + actor.async.blocking + end + + Celluloid.internal_pool.get do + Thread.current.role = :testing + sleep + end + end it 'should include all actors' do subject.actors.size.should == Celluloid::Actor.all.size end it 'should include threads that are not actors' do - subject.threads.size.should == Thread.list.reject(&:celluloid?).size + pending "bugs" + subject.threads.size.should == 2 end end diff -Nru ruby-celluloid-0.14.0/spec/celluloid/supervision_group_spec.rb ruby-celluloid-0.15.2/spec/celluloid/supervision_group_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/supervision_group_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/supervision_group_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -20,6 +20,20 @@ Celluloid::Actor[:example].should be_running end + it "accepts a private actor registry" do + my_registry = Celluloid::Registry.new + MyGroup.run!(my_registry) + sleep 0.01 + + my_registry[:example].should be_running + end + + it "removes actors from the registry when terminating" do + group = MyGroup.run! + group.terminate + Celluloid::Actor[:example].should be_nil + end + context "pool" do before :all do class MyActor diff -Nru ruby-celluloid-0.14.0/spec/celluloid/tasks/task_fiber_spec.rb ruby-celluloid-0.15.2/spec/celluloid/tasks/task_fiber_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/tasks/task_fiber_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/tasks/task_fiber_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -2,4 +2,4 @@ describe Celluloid::TaskFiber do it_behaves_like "a Celluloid Task", Celluloid::TaskFiber -end \ No newline at end of file +end diff -Nru ruby-celluloid-0.14.0/spec/celluloid/thread_handle_spec.rb ruby-celluloid-0.15.2/spec/celluloid/thread_handle_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/thread_handle_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/thread_handle_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -15,4 +15,8 @@ it "joins to thread handles" do Celluloid::ThreadHandle.new { sleep 0.01 }.join end + + it "supports passing a role" do + Celluloid::ThreadHandle.new(:useful) { Thread.current.role.should == :useful }.join + end end diff -Nru ruby-celluloid-0.14.0/spec/celluloid/uuid_spec.rb ruby-celluloid-0.15.2/spec/celluloid/uuid_spec.rb --- ruby-celluloid-0.14.0/spec/celluloid/uuid_spec.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/celluloid/uuid_spec.rb 2013-11-26 19:53:19.000000000 +0000 @@ -3,7 +3,7 @@ describe Celluloid::UUID do U = Celluloid::UUID - it "should generate unique IDs across the BLOCK_SIZE boundary" do + it "generates unique IDs across the BLOCK_SIZE boundary" do upper_bound = U::BLOCK_SIZE * 2 + 10 uuids = (1..upper_bound).map{ U.generate } uuids.size.should == uuids.uniq.size diff -Nru ruby-celluloid-0.14.0/spec/spec_helper.rb ruby-celluloid-0.15.2/spec/spec_helper.rb --- ruby-celluloid-0.14.0/spec/spec_helper.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/spec_helper.rb 2013-11-26 19:53:19.000000000 +0000 @@ -1,13 +1,16 @@ +require 'coveralls' +Coveralls.wear! + require 'rubygems' require 'bundler/setup' -require 'celluloid/autostart' require 'celluloid/rspec' -require 'coveralls' -Coveralls.wear! logfile = File.open(File.expand_path("../../log/test.log", __FILE__), 'a') logfile.sync = true -Celluloid.logger = Logger.new(logfile) + +logger = Celluloid.logger = Logger.new(logfile) + +Celluloid.shutdown_timeout = 1 Dir['./spec/support/*.rb'].map {|f| require f } @@ -15,8 +18,14 @@ config.filter_run :focus => true config.run_all_when_everything_filtered = true - config.before do |example| - Celluloid.shutdown + config.before do + Celluloid.logger = logger + if Celluloid.running? + Celluloid.shutdown + sleep 0.01 + Celluloid.internal_pool.assert_inactive + end + Celluloid.boot end end diff -Nru ruby-celluloid-0.14.0/spec/support/actor_examples.rb ruby-celluloid-0.15.2/spec/support/actor_examples.rb --- ruby-celluloid-0.14.0/spec/support/actor_examples.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/support/actor_examples.rb 2013-11-26 19:53:19.000000000 +0000 @@ -34,6 +34,11 @@ actor.object_id.should_not eq(Kernel.object_id) end + it "implements respond_to? correctly" do + actor = actor_class.new 'Troy McClure' + actor.should respond_to(:alive?) + end + it "supports synchronous calls" do actor = actor_class.new "Troy McClure" actor.greet.should eq("Hi, I'm Troy McClure") @@ -91,6 +96,36 @@ ponycopter.greet_by_proxy(actor).should eq("Hi, I'm a ponycopter!") end + it "detects recursion" do + klass1 = Class.new do + include included_module + task_class task_klass + + def recursion_test(recurse_through = nil) + if recurse_through + recurse_through.recursion_thunk(Celluloid::Actor.current) + else + Celluloid.detect_recursion + end + end + end + + klass2 = Class.new do + include included_module + task_class task_klass + + def recursion_thunk(other) + other.recursion_test + end + end + + actor1 = klass1.new + actor2 = klass2.new + + actor1.recursion_test.should be_false + actor1.recursion_test(actor2).should be_true + end + it "properly handles method_missing" do actor = actor_class.new "Method Missing" actor.should respond_to(:first) @@ -103,6 +138,24 @@ actor.respond_to?(:zomg_private, true).should be_true end + it "warns about suspending the initialize" do + klass = Class.new do + include included_module + task_class task_klass + + def initialize + sleep 0.1 + end + end + + Celluloid.logger = double.as_null_object + Celluloid.logger.should_receive(:warn).with(/Dangerously suspending task: type=:call, meta={:method_name=>:initialize}, status=:sleeping/) + + actor = klass.new + actor.terminate + Celluloid::Actor.join(actor) unless defined?(JRUBY_VERSION) + end + it "calls the user defined finalizer" do actor = actor_class.new "Mr. Bean" actor.wrapped_object.should_receive(:my_finalizer) @@ -110,6 +163,26 @@ Celluloid::Actor.join(actor) end + it "warns about suspending the finalizer" do + klass = Class.new do + include included_module + task_class task_klass + + finalizer :cleanup + + def cleanup + sleep 0.1 + end + end + + Celluloid.logger = double.as_null_object + Celluloid.logger.should_receive(:warn).with(/Dangerously suspending task: type=:finalizer, meta={:method_name=>:cleanup}, status=:sleeping/) + + actor = klass.new + actor.terminate + Celluloid::Actor.join(actor) + end + it "supports async(:method) syntax for asynchronous calls" do actor = actor_class.new "Troy McClure" actor.async :change_name, "Charlie Sheen" @@ -162,6 +235,27 @@ actor.inspect.should include('dead') end + it "supports recursive inspect with other actors" do + klass = Class.new do + include included_module + task_class task_klass + + attr_accessor :other + + def initialize(other = nil) + @other = other + end + end + + itchy = klass.new + scratchy = klass.new(itchy) + itchy.other = scratchy + + inspection = itchy.inspect + inspection.should match(/Celluloid::ActorProxy\(/) + inspection.should include("...") + end + it "allows access to the wrapped object" do actor = actor_class.new "Troy McClure" actor.wrapped_object.should be_a actor_class @@ -239,6 +333,8 @@ actor = actor_class.new "James Dean" actor.crash rescue nil + sleep 0.1 # hax to prevent a race between exit handling and the next call + expect do actor.greet end.to raise_exception(Celluloid::DeadActorError) @@ -283,6 +379,14 @@ actor.should_not be_alive end + it "can be terminated by a SyncCall" do + actor = actor_class.new "Arnold Schwarzenegger" + actor.should be_alive + actor.shutdown + Celluloid::Actor.join(actor) + actor.should_not be_alive + end + it "kills" do # THOU SHALT ALWAYS KILL actor = actor_class.new "Woody Harrelson" actor.should be_alive @@ -308,6 +412,17 @@ actor.terminate! end.to raise_exception(Celluloid::DeadActorError, "actor already terminated") end + + it "logs a warning when terminating tasks" do + Celluloid.logger = double.as_null_object + Celluloid.logger.should_receive(:warn).with("Terminating task: type=:call, meta={:method_name=>:sleepy}, status=:sleeping") + + actor = actor_class.new "Arnold Schwarzenegger" + actor.async.sleepy 10 + actor.greet # make sure the actor has started sleeping + + actor.terminate + end end context :current_actor do @@ -323,41 +438,6 @@ end end - context "thread locals" do - let(:example_class) do - Class.new do - include included_module - task_class task_klass - - def initialize(value) - Thread.current[:example_thread_local] = value - end - - def value - Thread.current[:example_thread_local] - end - - def deferred_value - defer do - Thread.current[:example_thread_local] - end - end - end - end - - let(:example_value) { "foobar" } - - it "preserves thread locals between tasks" do - actor = example_class.new(example_value) - actor.value.should eq example_value - end - - it "isolates thread locals in defer blocks" do - actor = example_class.new(example_value) - actor.deferred_value.should eq nil - end - end - context :linking do before :each do @kevin = actor_class.new "Kevin Bacon" # Some six degrees action here @@ -473,8 +553,6 @@ raise "already signaled" if @signaled @waiting = true - signal :future - value = wait :ponycopter @waiting = false @@ -482,11 +560,6 @@ value end - def wait_for_future - return true if @waiting - wait :future - end - def send_signal(value) signal :ponycopter, value end @@ -502,9 +575,11 @@ obj.async.wait_for_signal obj.should_not be_signaled + obj.should be_waiting obj.send_signal :foobar obj.should be_signaled + obj.should_not be_waiting end it "sends values along with signals" do @@ -513,7 +588,6 @@ future = obj.future(:wait_for_signal) - obj.wait_for_future obj.should be_waiting obj.should_not be_signaled @@ -834,12 +908,12 @@ end end - context :mailbox_limit do + context :mailbox_size do subject do Class.new do include included_module task_class task_klass - mailbox.max_size = 100 + mailbox_size 100 end end @@ -892,4 +966,46 @@ subclass.new.tasks.first.should be_a ExampleTask end end + + context :timeouts do + let :actor_class do + Class.new do + include included_module + + def name + sleep 0.5 + :foo + end + + def ask_name_with_timeout(other, duration) + timeout(duration) { other.name } + end + end + end + + it "allows timing out tasks, raising Celluloid::Task::TimeoutError" do + a1 = actor_class.new + a2 = actor_class.new + + expect { a1.ask_name_with_timeout a2, 0.3 }.to raise_error(Celluloid::Task::TimeoutError) + end + + it "does not raise when it completes in time" do + a1 = actor_class.new + a2 = actor_class.new + + a1.ask_name_with_timeout(a2, 0.6).should == :foo + end + end + + context "raw message sends" do + it "logs on unhandled messages" do + Celluloid.logger = double.as_null_object + Celluloid.logger.should_receive(:debug).with("Discarded message (unhandled): first") + + actor = actor_class.new "Irma Gladden" + actor.mailbox << :first + sleep Celluloid::TIMER_QUANTUM + end + end end diff -Nru ruby-celluloid-0.14.0/spec/support/example_actor_class.rb ruby-celluloid-0.15.2/spec/support/example_actor_class.rb --- ruby-celluloid-0.14.0/spec/support/example_actor_class.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/support/example_actor_class.rb 2013-11-26 19:53:19.000000000 +0000 @@ -12,6 +12,10 @@ @delegate = [:bar] end + def sleepy(duration) + sleep duration + end + def change_name(new_name) @name = new_name end @@ -66,6 +70,10 @@ string.reverse end + def shutdown + terminate + end + def method_missing(method_name, *args, &block) if delegates?(method_name) @delegate.send method_name, *args, &block diff -Nru ruby-celluloid-0.14.0/spec/support/mailbox_examples.rb ruby-celluloid-0.15.2/spec/support/mailbox_examples.rb --- ruby-celluloid-0.14.0/spec/support/mailbox_examples.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/support/mailbox_examples.rb 2013-11-26 19:53:19.000000000 +0000 @@ -43,7 +43,7 @@ subject.size.should be_zero subject << :foo subject << :foo - subject.size.should be 2 + subject.should have(2).entries end it "discards messages received when when full" do @@ -55,12 +55,24 @@ end it "logs discarded messages" do - Celluloid.logger = mock.as_null_object - Celluloid.logger.should_receive(:debug).with("Discarded message: third") + Celluloid.logger = double.as_null_object + Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): third") subject.max_size = 2 subject << :first subject << :second subject << :third end + + it "discard messages when dead" do + Celluloid.logger = double.as_null_object + Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): first") + Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): second") + Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): third") + + subject << :first + subject << :second + subject.shutdown + subject << :third + end end diff -Nru ruby-celluloid-0.14.0/spec/support/task_examples.rb ruby-celluloid-0.15.2/spec/support/task_examples.rb --- ruby-celluloid-0.14.0/spec/support/task_examples.rb 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/spec/support/task_examples.rb 2013-11-26 19:53:19.000000000 +0000 @@ -14,7 +14,7 @@ let(:suspend_state) { :doing_something } let(:actor) { MockActor.new } - subject { task_class.new(task_type) { Celluloid::Task.suspend(suspend_state) } } + subject { task_class.new(task_type, {}) { Celluloid::Task.suspend(suspend_state) } } before :each do Thread.current[:celluloid_actor] = actor @@ -37,7 +37,7 @@ end it "raises exceptions outside" do - task = task_class.new(task_type) do + task = task_class.new(task_type, {}) do raise "failure" end expect do diff -Nru ruby-celluloid-0.14.0/tasks/benchmarks.task ruby-celluloid-0.15.2/tasks/benchmarks.task --- ruby-celluloid-0.14.0/tasks/benchmarks.task 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/tasks/benchmarks.task 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -require 'timeout' - -desc "Run Celluloid benchmarks" -task :benchmark do - begin - Timeout.timeout(120) do - glob = File.expand_path("../../benchmarks/*.rb", __FILE__) - Dir[glob].each { |benchmark| load benchmark } - end - rescue Exception, Timeout::Error => ex - puts "ERROR: Couldn't complete benchmark: #{ex.class}: #{ex}" - puts " #{ex.backtrace.join("\n ")}" - - exit 1 unless ENV['CI'] # Hax for running benchmarks on Travis - end -end diff -Nru ruby-celluloid-0.14.0/tasks/rspec.task ruby-celluloid-0.15.2/tasks/rspec.task --- ruby-celluloid-0.14.0/tasks/rspec.task 2013-05-17 22:14:34.000000000 +0000 +++ ruby-celluloid-0.15.2/tasks/rspec.task 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -require 'rspec/core/rake_task' - -RSpec::Core::RakeTask.new - -RSpec::Core::RakeTask.new(:rcov) do |task| - task.rcov = true -end \ No newline at end of file