| CODENOTIFIER | HelpYou are not signed inSign in |
Project: Revactor
Revision: 123
Author: tarcieri
Date: 26 Mar 2008 01:49:01
Changes:Last minute fixups
Files:| ... | ...@@ -42,22 +42,21 @@ | |
| 42 | 42 | # |
| 43 | 43 | module Actorize |
| 44 | 44 | def spawn(*args) |
| 45 | Actor.spawn(*args, &method(:_spawn)) | |
| 45 | _actorize Actor.spawn(*args, &method(:new)) | |
| 46 | 46 | end |
| 47 | 47 | |
| 48 | 48 | def spawn_link(*args) |
| 49 | Actor.spawn_link(*args, &method(:_spawn)) | |
| 49 | _actorize Actor.spawn_link(*args, &method(:new)) | |
| 50 | 50 | end |
| 51 | 51 | |
| 52 | 52 | ####### |
| 53 | 53 | private |
| 54 | 54 | ####### |
| 55 | 55 | |
| 56 | def _spawn(*args) | |
| 57 | obj = allocate | |
| 58 | obj.extend InstanceMethods | |
| 59 | Actor.current.instance_variable_set(:@_class, self) | |
| 60 | obj.__send__(:initialize, *args) | |
| 56 | def _actorize(actor) | |
| 57 | actor.extend InstanceMethods | |
| 58 | actor.instance_variable_set(:@_class, self) | |
| 59 | actor | |
| 61 | 60 | end |
| 62 | 61 | |
| 63 | 62 | module InstanceMethods |
| ... | ...@@ -65,5 +64,13 @@ | |
| 65 | 64 | return super unless @_class.respond_to?(:call) |
| 66 | 65 | @_class.call(self, *args, &block) |
| 67 | 66 | end |
| 67 | ||
| 68 | def remote_class | |
| 69 | @_class | |
| 70 | end | |
| 71 | ||
| 72 | def inspect | |
| 73 | "#<#{self.class}(#{remote_class}):0x#{object_id.to_s(16)}>" | |
| 74 | end | |
| 68 | 75 | end |
| 69 | 76 | end |
| 70 | 77 | \ No newline at end of file |
| ... | ...@@ -32,7 +32,7 @@ | |
| 32 | 32 | end |
| 33 | 33 | |
| 34 | 34 | %w{ |
| 35 | actor scheduler mailbox delegator tcp http_client | |
| 35 | actor scheduler mailbox tcp http_client | |
| 36 | 36 | filters/line filters/packet actorize |
| 37 | 37 | }.each do |file| |
| 38 | 38 | require File.dirname(__FILE__) + '/revactor/' + file |
| ... | ...@@ -42,6 +42,5 @@ | |
| 42 | 42 | class Actor |
| 43 | 43 | Actor::TCP = Revactor::TCP unless defined? Actor::TCP |
| 44 | 44 | Actor::Filter = Revactor::Filter unless defined? Actor::Filter |
| 45 | Actor::Delegator = Revactor::Delegator unless defined? Actor::Delegator | |
| 46 | 45 | Actor::HttpClient = Revactor::HttpClient unless defined? Actor::HttpClient |
| 47 | 46 | end |
| ... | ...@@ -1,68 +0,0 @@ | |
| 1 | #-- | |
| 2 | # Copyright (C)2007 Tony Arcieri | |
| 3 | # You can redistribute this under the terms of the Ruby license | |
| 4 | # See file LICENSE for details | |
| 5 | #++ | |
| 6 | ||
| 7 | # A Delegator whose delegate runs in a separate Actor. This allows | |
| 8 | # an easy method for constructing synchronous calls to a separate Actor | |
| 9 | # which cause the current Actor to block until they complete. | |
| 10 | class Revactor::Delegator | |
| 11 | # Create a new delegator for the given object | |
| 12 | def initialize(obj) | |
| 13 | @obj = obj | |
| 14 | @running = true | |
| 15 | @actor = Actor.spawn(&method(:start)) | |
| 16 | end | |
| 17 | ||
| 18 | # Stop the delegator Actor | |
| 19 | def stop | |
| 20 | @actor << :stop | |
| 21 | nil | |
| 22 | end | |
| 23 | ||
| 24 | # Send a message to the Actor delegate | |
| 25 | def send(meth, *args, &block) | |
| 26 | @actor << T[:call, Actor.current, meth, args, block] | |
| 27 | Actor.receive do |filter| | |
| 28 | filter.when(Case[:call_reply, @actor, Object]) { |_, _, reply| reply } | |
| 29 | filter.when(Case[:call_error, @actor, Object]) { |_, _, ex| raise ex } | |
| 30 | end | |
| 31 | end | |
| 32 | ||
| 33 | alias_method :method_missing, :send | |
| 34 | ||
| 35 | ######### | |
| 36 | protected | |
| 37 | ######### | |
| 38 | ||
| 39 | # Start the server | |
| 40 | def start | |
| 41 | loop do | |
| 42 | Actor.receive do |filter| | |
| 43 | filter.when(:stop) { |_| return } | |
| 44 | filter.when(Object) { |message| handle_message(message) } | |
| 45 | end | |
| 46 | end | |
| 47 | end | |
| 48 | ||
| 49 | # Dispatch the incoming message to the appropriate handler | |
| 50 | def handle_message(message) | |
| 51 | case message.first | |
| 52 | when :call then handle_call(message) | |
| 53 | else @obj.__send__(:on_message, message) if @obj.respond_to? :on_message | |
| 54 | end | |
| 55 | end | |
| 56 | ||
| 57 | # Wrapper for calling the provided object's handle_call method | |
| 58 | def handle_call(message) | |
| 59 | _, from, meth, args, block = message | |
| 60 | ||
| 61 | begin | |
| 62 | result = @obj.__send__(meth, *args, &block) | |
| 63 | from << T[:call_reply, Actor.current, result] | |
| 64 | rescue => ex | |
| 65 | from << T[:call_error, Actor.current, ex] | |
| 66 | end | |
| 67 | end | |
| 68 | end | |
| 69 | 0 | \ No newline at end of file |
| ... | ...@@ -1,80 +0,0 @@ | |
| 1 | require 'thread' | |
| 2 | ||
| 3 | class Thread | |
| 4 | def _fiber_scheduler | |
| 5 | @fiber_scheduler ||= Fiber::Scheduler.new | |
| 6 | end | |
| 7 | end | |
| 8 | ||
| 9 | class FiberError < StandardError; end | |
| 10 | ||
| 11 | # Pseudo-Fibers built on top of Ruby 1.8's green threads | |
| 12 | class Fiber | |
| 13 | def self.current | |
| 14 | Thread.current._fiber_scheduler.current_fiber | |
| 15 | end | |
| 16 | ||
| 17 | def self.yield | |
| 18 | raise FiberError, "can't yield from root fiber" if Thread.current._fiber_scheduler.current_fiber.root? | |
| 19 | Thread.current._fiber_scheduler.yield | |
| 20 | end | |
| 21 | ||
| 22 | def initialize(&routine) | |
| 23 | raise ArgumentError, "no block given" unless block_given? | |
| 24 | scheduler = Thread.current._fiber_scheduler | |
| 25 | ||
| 26 | @dead = false | |
| 27 | @root = false | |
| 28 | @thread = Thread.new do | |
| 29 | Thread.current.instance_variable_set(:@fiber_scheduler, scheduler) | |
| 30 | Thread.stop | |
| 31 | routine.call | |
| 32 | ||
| 33 | @dead = true | |
| 34 | Fiber.yield | |
| 35 | end | |
| 36 | end | |
| 37 | ||
| 38 | def resume | |
| 39 | raise FiberError, "dead fiber called" if dead? | |
| 40 | Thread.current._fiber_scheduler << self | |
| 41 | @thread.run | |
| 42 | Thread.stop | |
| 43 | nil | |
| 44 | end | |
| 45 | ||
| 46 | def dead?; @dead; end | |
| 47 | ||
| 48 | def root?; @root; end | |
| 49 | ||
| 50 | ####### | |
| 51 | private | |
| 52 | ####### | |
| 53 | ||
| 54 | def initialize_root | |
| 55 | @dead = false | |
| 56 | @root = true | |
| 57 | @thread = Thread.current | |
| 58 | ||
| 59 | self | |
| 60 | end | |
| 61 | ||
| 62 | class Scheduler | |
| 63 | def initialize | |
| 64 | @queue = [Fiber.allocate.send(:initialize_root)] | |
| 65 | end | |
| 66 | ||
| 67 | def <<(fiber) | |
| 68 | @queue << fiber | |
| 69 | end | |
| 70 | ||
| 71 | def current_fiber | |
| 72 | @queue.last | |
| 73 | end | |
| 74 | ||
| 75 | def yield | |
| 76 | @queue.pop | |
| 77 | @queue.last.resume | |
| 78 | end | |
| 79 | end | |
| 80 | end |