<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -392,12 +392,16 @@ class Merb::BootLoader::LoadClasses &lt; Merb::BootLoader
       Merb::Controller.send :include, Merb::GlobalHelpers
     end
     
+    # Wait for any children to exit, remove the &quot;main&quot; PID, and
+    # exit.
     def exit_gracefully
       Process.waitall
       Merb::Server.remove_pid(&quot;main&quot;)
       exit
     end
     
+    # If using fork-based code reloading, set up the BEGIN
+    # point and set up any signals in the parent and child.
     def start_transaction
       Merb.logger.warn! &quot;Parent pid: #{Process.pid}&quot;
       reader, writer = nil, nil
@@ -421,7 +425,10 @@ class Merb::BootLoader::LoadClasses &lt; Merb::BootLoader
         else
           trap(&quot;INT&quot;) do 
             Merb.logger.warn! &quot;Killing children&quot;
-            Process.kill(&quot;ABRT&quot;, pid)
+            begin
+              Process.kill(&quot;ABRT&quot;, pid)
+            rescue SystemCallError
+            end
             exit_gracefully
           end
         end
@@ -465,6 +472,14 @@ class Merb::BootLoader::LoadClasses &lt; Merb::BootLoader
       end
     end
     
+    # Kill any children of the spawner process and exit with
+    # an appropriate status code.
+    #
+    # Note that exiting the spawner process with a status code
+    # of 128 when a master process exists will cause the
+    # spawner process to be recreated, and the app code reloaded.
+    #
+    # @param status&lt;Integer&gt; The status code to exit with
     def kill_children(status = 0)
       Merb.exiting = true unless status == 128
       
@@ -491,10 +506,27 @@ class Merb::BootLoader::LoadClasses &lt; Merb::BootLoader
     # ==== Parameters
     # file&lt;String&gt;:: The file to load.
     def load_file(file)
-      klasses = ObjectSpace.classes.dup
-      load file
-      LOADED_CLASSES[file] = ObjectSpace.classes - klasses
-      MTIMES[file] = File.mtime(file)
+      # Don't do this expensive operation unless we need to
+      unless Merb::Config[:fork_for_class_load]
+        klasses = ObjectSpace.classes.dup
+      end
+      
+      # Ignore the file for syntax errors. The next time
+      # the file is changed, it'll be reloaded again
+      begin
+        load file
+      rescue SyntaxError
+        return
+      ensure
+        if Merb::Config[:reload_classes]
+          MTIMES[file] = File.mtime(file)
+        end
+      end
+      
+      # Don't do this expensive operation unless we need to
+      unless Merb::Config[:fork_for_class_load]
+        LOADED_CLASSES[file] = ObjectSpace.classes - klasses
+      end
     end
     
     # Load classes from given paths - using path/glob pattern.
@@ -518,7 +550,7 @@ class Merb::BootLoader::LoadClasses &lt; Merb::BootLoader
     # ==== Parameters
     # file&lt;String&gt;:: The file to reload.
     def reload(file)
-      if Merb::Config[:fork_for_class_load]
+      if !Merb::Config[:fork_for_class_load]
         remove_classes_in_file(file) { |f| load_file(f) }
       else
         kill_children(128)</diff>
      <filename>lib/merb-core/bootloader.rb</filename>
    </modified>
    <modified>
      <diff>@@ -103,6 +103,12 @@ module Merb
       #   Configuration settings to use. These are merged with the defaults.
       def setup(settings = {})
         @configuration = defaults.merge(settings)
+        
+        unless @configuration[:reload_classes]
+          @configuration[:fork_for_class_load] = false
+        end
+        
+        @configuration
       end
 
       # Parses the command line arguments and stores them in the config.</diff>
      <filename>lib/merb-core/config.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,17 +2,19 @@ module Merb
   module Rack
     class AbstractAdapter
     
+      # Spawn a new worker process at a port.
       def self.spawn_worker(port)
-        pid = Kernel.fork
-        start_at_port(port, @opts) unless pid
+        child_pid = Kernel.fork
+        start_at_port(port, @opts) unless child_pid
 
-        # pid means we're in the parent, which means continue the loop
-        throw(:new_worker) unless pid
+        # If we have a child_pid, we're in the parent. If we're
+        throw(:new_worker) unless child_pid
         
-        @pids[port] = pid
+        @pids[port] = child_pid
         $CHILDREN = @pids.values
       end
     
+      # The main start method for bootloaders that support forking.
       def self.start(opts={})
         @opts = opts
         $CHILDREN ||= []
@@ -24,6 +26,8 @@ module Merb
         
         Merb.logger.warn! &quot;Cluster: #{max_port}&quot;
         
+        # If we only have a single merb, just start it up and dispense with
+        # the spawner/worker setup.
         if max_port == 0
           start_at_port(port)
           return
@@ -31,34 +35,49 @@ module Merb
         
         $0 = &quot;merb: spawner&quot;
 
+        # For each port, spawn a new worker. The parent will continue in
+        # the loop, while the child will throw :new_worker and be booted
+        # out of the loop.
         catch(:new_worker) do
           0.upto(max_port) do |i|
             parent = spawn_worker(port + i)
           end
         end
 
-        # pid means we're in the parent, so start watching the children
-        # no pid means we're in a child, so just move on
+        # If we're in a worker, we're done. Otherwise, we've completed
+        # setting up workers and now need to watch them.
         return unless parent
 
+        # For each worker, set up a thread in the spawner to watch it
         0.upto(max_port) do |i|
           Thread.new do
             catch(:new_worker) do
               loop do
                 pid = @pids[port + i]
                 begin
+                  # Watch for the pid to exit.
                   _, status = Process.wait2(pid)
+                
+                # If the pid doesn't exist, we want to silently exit instead of
+                # raising here.
                 rescue SystemCallError =&gt; e
                 ensure
+                  # If there was no worker with that PID, the status was non-0
+                  # (we send back a status of 128 when ABRT is called on a 
+                  # child, and Merb.fatal! exits with a status of 1), or if
+                  # Merb is in the process of exiting, *then* don't respawn.
                   Thread.exit if !status || status.exitstatus != 0 || Merb.exiting
                 end
               
+                # Otherwise, respawn the worker, and watch it again.
                 spawn_worker(port + i)
               end
             end
           end
         end
 
+        # The spawner process will make it here, and when it does, it should just 
+        # sleep so it can pick up ctrl-c if it's in console mode.
         sleep
         
       end
@@ -68,37 +87,56 @@ module Merb
           Merb::Server.remove_pid(port)
         end
         
+        # If Merb is daemonized, trap INT. If it's not daemonized,
+        # we let the master process' ctrl-c control the cluster
+        # of workers.
         if Merb::Config[:daemonize]
           trap('INT') do
             stop
             Merb.logger.warn! &quot;Exiting port #{port}\n&quot;
             exit_process
           end
+        # If it was not fork_for_class_load, we already set up
+        # ctrl-c handlers in the master thread.
         elsif Merb::Config[:fork_for_class_load]
           trap('INT') { 1 }
         end
         
+        # In daemonized mode or not, support HUPing the process to
+        # restart it.
         trap('HUP') do
           stop
           Merb.logger.warn! &quot;Exiting port #{port} on #{Process.pid}\n&quot;
           exit_process
         end
         
+        # ABRTing the process will kill it, and it will not be respawned.
         trap('ABRT') do
           stopped = stop(128)
           Merb.logger.warn! &quot;Exiting port #{port}\n&quot; if stopped
           exit_process(128)
         end
         
+        # Each worker gets its own `ps' name.
         $0 = &quot;merb: worker (port #{port})&quot;
         
+        # Store the PID for this worker
         Merb::Server.store_pid(port)
-        Merb.logger = Merb::Logger.new(Merb.log_file(port), Merb::Config[:log_level], Merb::Config[:log_delimiter], Merb::Config[:log_auto_flush])
+        
+        # Set up the logger for this worker to point to its process.
+        Merb.logger = Merb::Logger.new(Merb.log_file(port), 
+          Merb::Config[:log_level], Merb::Config[:log_delimiter], 
+          Merb::Config[:log_auto_flush])
+          
         Merb.logger.warn!(&quot;Starting #{self.name.split(&quot;::&quot;).last} at port #{port}&quot;)
         
+        # If we can't connect to the port, keep trying until we can. Print
+        # a warning about this once. Try every 0.25s.
         printed_warning = false
         loop do
           begin
+            # Call the adapter's new_server method, which should attempt
+            # to bind to a port.
             new_server(port)
           rescue Errno::EADDRINUSE
             unless printed_warning
@@ -117,9 +155,11 @@ module Merb
         
         Merb::Server.change_privilege
         
+        # Call the adapter's start_server method.
         start_server
       end
       
+      # This can be overridden in adapters, but shouldn't need to be.
       def self.exit_process(status = 0)
         exit(status)
       end</diff>
      <filename>lib/merb-core/rack/adapter/abstract.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>acb90a6e57e075717a235f5896df545937880416</id>
    </parent>
  </parents>
  <author>
    <name>Yehuda Katz</name>
    <email>wycats@gmail.com</email>
  </author>
  <url>http://github.com/wycats/merb-core/commit/f4fd0d39ea76e1722ee115f15f307732603d7ce4</url>
  <id>f4fd0d39ea76e1722ee115f15f307732603d7ce4</id>
  <committed-date>2008-09-27T18:27:11-07:00</committed-date>
  <authored-date>2008-09-25T23:18:02-07:00</authored-date>
  <message>Tons of comments; support for various forking configurations</message>
  <tree>9ec5a670f27e5c4a73ce8bd312fc795566d21427</tree>
  <committer>
    <name>Yehuda Katz</name>
    <email>wycats@gmail.com</email>
  </committer>
</commit>
