about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-10-04 03:09:56 -0700
committerEric Wong <normalperson@yhbt.net>2009-10-04 03:22:53 -0700
commit4b52a167cfb7ea1d1d663844028dcde2d4536223 (patch)
tree9e179516c9e39621f78c6c0d01b6780c783481cd /lib
parentacb5cedd57a116772aae66e4af1f4383bfe16d85 (diff)
downloadrainbows-4b52a167cfb7ea1d1d663844028dcde2d4536223.tar.gz
While we're at it, make it properly 100% message-driven so
there's no more busy-waiting and polling for dead actors, No we
just wait for client actors to die off and resume listener
actors if they stopped accepting.
Diffstat (limited to 'lib')
-rw-r--r--lib/rainbows/revactor.rb33
1 files changed, 24 insertions, 9 deletions
diff --git a/lib/rainbows/revactor.rb b/lib/rainbows/revactor.rb
index 66a4ae3..a0740fa 100644
--- a/lib/rainbows/revactor.rb
+++ b/lib/rainbows/revactor.rb
@@ -68,16 +68,24 @@ module Rainbows
       trap(:QUIT) { alive = false; LISTENERS.each { |s| s.close rescue nil } }
       [:TERM, :INT].each { |sig| trap(sig) { exit!(0) } } # instant shutdown
 
-      Actor.current.trap_exit = true
+      root = Actor.current
+      root.trap_exit = true
 
+      limit = worker_connections
       listeners = revactorize_listeners
       logger.info "worker=#{worker.nr} ready with Revactor"
-      clients = []
+      clients = 0
 
       listeners.map! do |s|
         Actor.spawn(s) do |l|
           begin
-            clients << Actor.spawn(l.accept) { |c| process_client(c) }
+            while clients >= limit
+              logger.info "busy: clients=#{clients} >= limit=#{limit}"
+              Actor.receive { |filter| filter.when(:resume) {} }
+            end
+            actor = Actor.spawn(l.accept) { |c| process_client(c) }
+            clients += 1
+            root.link(actor)
           rescue Errno::EAGAIN, Errno::ECONNABORTED
           rescue Object => e
             if alive
@@ -90,13 +98,20 @@ module Rainbows
 
       nr = 0
       begin
-        Actor.sleep 1
-        clients.delete_if { |c| c.dead? }
-        if alive
-          alive.chmod(nr = 0 == nr ? 1 : 0)
-          ppid == Process.ppid or alive = false
+        Actor.receive do |filter|
+          filter.after(1) do
+            if alive
+              alive.chmod(nr = 0 == nr ? 1 : 0)
+              ppid == Process.ppid or alive = false
+            end
+          end
+          filter.when(Case[:exit, Actor, Object]) do |_,actor,_|
+            orig = clients
+            clients -= 1
+            orig >= limit and listeners.each { |l| l << :resume }
+          end
         end
-      end while alive || ! clients.empty?
+      end while alive || clients > 0
     end
 
   private