about summary refs log tree commit homepage
path: root/lib/mongrel.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mongrel.rb')
-rw-r--r--lib/mongrel.rb76
1 files changed, 24 insertions, 52 deletions
diff --git a/lib/mongrel.rb b/lib/mongrel.rb
index a97972b..424b7f0 100644
--- a/lib/mongrel.rb
+++ b/lib/mongrel.rb
@@ -26,6 +26,7 @@ require 'mongrel/const'
 require 'mongrel/http_request'
 require 'mongrel/header_out'
 require 'mongrel/http_response'
+require 'mongrel/semaphore'
 
 # Mongrel module containing all of the classes (include C extensions) for running
 # a Mongrel web server.  It contains a minimalist HTTP server with just enough
@@ -79,13 +80,20 @@ module Mongrel
     attr_reader :port
     attr_reader :throttle
     attr_reader :timeout
-    attr_reader :num_processors
+    attr_reader :max_queued_threads
+    
+    DEFAULTS = {
+      :max_queued_threads => 20,
+      :max_concurrent_threads => 20,
+      :throttle => 0,
+      :timeout => 60
+    }
 
     # Creates a working server on host:port (strange things happen if port isn't a Number).
     # Use HttpServer::run to start the server and HttpServer.acceptor.join to
     # join the thread that's processing incoming requests on the socket.
     #
-    # The num_processors optional argument is the maximum number of concurrent
+    # The max_queued_threads optional argument is the maximum number of concurrent
     # processors to accept, anything over this is closed immediately to maintain
     # server processing performance.  This may seem mean but it is the most efficient
     # way to deal with overload.  Other schemes involve still parsing the client's request
@@ -94,20 +102,21 @@ module Mongrel
     # The throttle parameter is a sleep timeout (in hundredths of a second) that is placed between
     # socket.accept calls in order to give the server a cheap throttle time.  It defaults to 0 and
     # actually if it is 0 then the sleep is not done at all.
-    def initialize(host, port, app, opts = {})
+    def initialize(host, port, app, options = {})
+      options = DEFAULTS.merge(options)
+
       tries = 0
       @socket = TCPServer.new(host, port)
       if defined?(Fcntl::FD_CLOEXEC)
         @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
       end
-      @host = host
-      @port = port
+      @host, @port, @app = host, port, app
       @workers = ThreadGroup.new
-      # Set default opts
-      @app = app
-      @num_processors = opts.delete(:num_processors) || 950
-      @throttle       = (opts.delete(:throttle) || 0) / 100
-      @timeout        = opts.delete(:timeout) || 60
+
+      @throttle = options[:throttle] / 100.0
+      @timeout = options[:timeout]
+      @max_queued_threads = options[:max_queued_threads]
+      @max_concurrent_threads = options[:max_concurrent_threads]
     end
 
     # Does the majority of the IO processing.  It has been written in Ruby using
@@ -245,6 +254,7 @@ module Mongrel
     # Runs the thing.  It returns the thread used so you can "join" it.  You can also
     # access the HttpServer::acceptor attribute to get the thread later.
     def start!
+      semaphore = Semaphore.new(@max_concurrent_threads)
       BasicSocket.do_not_reverse_lookup=true
 
       configure_socket_options
@@ -264,12 +274,12 @@ module Mongrel
               end
   
               worker_list = @workers.list
-              if worker_list.length >= @num_processors
-                Mongrel.logger.error "Server overloaded with #{worker_list.length} processors (#@num_processors max). Dropping connection."
+              if worker_list.length >= @max_queued_threads
+                Mongrel.logger.error "Server overloaded with #{worker_list.length} processors (#@max_queued_threads max). Dropping connection."
                 client.close rescue nil
                 reap_dead_workers("max processors")
               else
-                thread = Thread.new(client) {|c| process_client(c) }
+                thread = Thread.new(client) {|c| semaphore.synchronize { process_client(c) } }
                 thread[:started_on] = Time.now
                 @workers.add(thread)
   
@@ -298,49 +308,11 @@ module Mongrel
       return @acceptor
     end
 
-    # Simply registers a handler with the internal URIClassifier.  When the URI is
-    # found in the prefix of a request then your handler's HttpHandler::process method
-    # is called.  See Mongrel::URIClassifier#register for more information.
-    #
-    # If you set in_front=true then the passed in handler will be put in the front of the list
-    # for that particular URI. Otherwise it's placed at the end of the list.
-    def register(uri, handler, in_front=false)
-      begin
-        @classifier.register(uri, [handler])
-      rescue URIClassifier::RegistrationError => e
-        handlers = @classifier.resolve(uri)[2]
-        if handlers
-          # Already registered
-          method_name = in_front ? 'unshift' : 'push'
-          handlers.send(method_name, handler)
-        else
-          raise
-        end
-      end
-      handler.listener = self
-    end
-
-    # Removes any handlers registered at the given URI.  See Mongrel::URIClassifier#unregister
-    # for more information.  Remember this removes them *all* so the entire
-    # processing chain goes away.
-    def unregister(uri)
-      @classifier.unregister(uri)
-    end
-
     # Stops the acceptor thread and then causes the worker threads to finish
     # off the request queue before finally exiting.
     def stop(synchronous=false)
       @acceptor.raise(StopServer.new)
-
-      if synchronous
-        sleep(0.5) while @acceptor.alive?
-      end
+      (sleep(0.5) while @acceptor.alive?) if synchronous
     end
-
   end
 end
-
-# Load experimental library, if present. We put it here so it can override anything
-# in regular Mongrel.
-
-$LOAD_PATH.unshift 'projects/mongrel_experimental/lib/'