We got nominated! Help us out and vote for GitHub as Best Bootstrapped Startup of 2008. (You can vote once a day.) [ hide ]

public
Description: Phusion Passenger (mod_rails)
Homepage: http://www.modrails.com/
Clone URL: git://github.com/FooBarWidget/passenger.git
Click here to lend your support to: passenger and make a donation at www.pledgie.com !
Continue implementing conservative spawning..
Hongli Lai (Phusion) (author)
Wed May 07 05:46:56 -0700 2008
commit  c9461e1101901766c335d2586923cdeffea9deaf
tree    cfa08954a3542c43f8fefc9a1c4dbe825aa5f1b4
parent  bd2c430199887f59b3bf9c339f1296525337565d
...
141
142
143
144
 
 
145
146
147
...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
183
184
185
186
187
188
189
190
191
192
193
194
195
 
 
196
 
 
 
 
 
 
 
 
 
 
197
198
199
200
201
202
203
...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
 
 
 
 
 
 
 
 
359
360
361
362
363
364
365
366
367
368
369
370
 
 
 
371
372
373
...
379
380
381
382
 
383
384
 
385
386
 
387
388
389
 
390
391
392
...
141
142
143
 
144
145
146
147
148
...
150
151
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
 
 
 
 
172
173
174
175
176
177
 
 
178
179
180
181
182
183
184
185
186
187
188
189
190
191
 
 
 
192
193
194
...
333
334
335
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336
337
338
339
340
341
342
343
344
345
 
 
 
 
346
347
348
349
350
 
351
352
353
354
355
356
...
362
363
364
 
365
366
 
367
368
 
369
370
371
 
372
373
374
375
0
@@ -141,7 +141,8 @@ class ApplicationSpawner < AbstractServer
0
   # will be returned, which represents the spawned RoR application.
0
   #
0
   # Unlike spawn_application, this method may be called even when the ApplicationSpawner
0
- # server isn't started.
0
+ # server isn't started. This allows one to spawn a RoR application without preloading
0
+ # any source files.
0
   #
0
   # Raises:
0
   # - SystemCallError: Something went wrong.
0
@@ -149,55 +150,45 @@ class ApplicationSpawner < AbstractServer
0
   def spawn_application!
0
     # Double fork to prevent zombie processes.
0
     a, b = UNIXSocket.pair
0
- pid = fork do
0
- begin
0
- pid = fork do
0
- begin
0
- $0 = "Rails: #{@app_root}"
0
- a.close
0
- channel = MessageChannel.new(b)
0
- reader, writer = IO.pipe
0
- begin
0
- handler = RequestHandler.new(reader)
0
- channel.write(Process.pid, handler.socket_name,
0
- handler.using_abstract_namespace?)
0
- channel.send_io(writer)
0
- writer.close
0
- channel.close
0
- handler.main_loop
0
- ensure
0
- channel.close rescue nil
0
- writer.close rescue nil
0
- handler.cleanup rescue nil
0
- end
0
- rescue SignalException => signal
0
- if e.message != RequestHandler::HARD_TERMINATION_SIGNAL &&
0
- e.message != RequestHandler::SOFT_TERMINATION_SIGNAL
0
- print_exception('application', e)
0
- end
0
- rescue Exception => e
0
- print_exception('application', e)
0
- ensure
0
- exit!
0
+ pid = safe_fork(self.class.to_s) do
0
+ pid = safe_fork('application') do
0
+ begin
0
+ a.close
0
+ channel = MessageChannel.new(b)
0
+ ok = report_app_init_errors(channel) do
0
+ Dir.chdir(@app_root)
0
+ lower_privilege! if @lower_privilege
0
+ require 'config/enviroment'
0
+ end
0
+ exit! if !ok
0
+ channel.write('ok')
0
+ start_request_handler(channel)
0
+ rescue SignalException => signal
0
+ if e.message != RequestHandler::HARD_TERMINATION_SIGNAL &&
0
+ e.message != RequestHandler::SOFT_TERMINATION_SIGNAL
0
+ raise
0
           end
0
         end
0
- rescue Exception => e
0
- print_exception(self.class.to_s, e)
0
- ensure
0
- exit!
0
       end
0
     end
0
     b.close
0
     Process.waitpid(pid)
0
     
0
     channel = MessageChannel.new(a)
0
- pid, socket_name, using_abstract_namespace = channel.read
0
- if pid.nil?
0
+ status = channel.read
0
+ if status.nil?
0
       raise IOError, "Connection closed"
0
+ elsif status == "ok"
0
+ pid, socket_name, using_abstract_namespace = channel.read
0
+ if pid.nil?
0
+ raise IOError, "Connection closed"
0
+ end
0
+ owner_pipe = server.recv_io
0
+ return Application.new(@app_root, pid, socket_name,
0
+ using_abstract_namespace == "true", owner_pipe)
0
+ else
0
+ # ...
0
     end
0
- owner_pipe = server.recv_io
0
- return Application.new(@app_root, pid, socket_name,
0
- using_abstract_namespace == "true", owner_pipe)
0
   end
0
   
0
   # Overrided from AbstractServer#start.
0
@@ -342,32 +333,24 @@ private
0
 
0
   def handle_spawn_application
0
     # Double fork to prevent zombie processes.
0
- pid = fork do
0
- begin
0
- pid = fork do
0
- begin
0
- start_request_handler
0
- rescue SignalException => signal
0
- if e.message != RequestHandler::HARD_TERMINATION_SIGNAL &&
0
- e.message != RequestHandler::SOFT_TERMINATION_SIGNAL
0
- print_exception('application', e)
0
- end
0
- rescue Exception => e
0
- print_exception('application', e)
0
- ensure
0
- exit!
0
+ pid = safe_fork(self.class.to_s) do
0
+ pid = safe_fork('application') do
0
+ begin
0
+ start_request_handler(client)
0
+ rescue SignalException => signal
0
+ if e.message != RequestHandler::HARD_TERMINATION_SIGNAL &&
0
+ e.message != RequestHandler::SOFT_TERMINATION_SIGNAL
0
+ raise
0
           end
0
         end
0
- rescue Exception => e
0
- print_exception(self.class.to_s, e)
0
- ensure
0
- exit!
0
       end
0
     end
0
     Process.waitpid(pid)
0
   end
0
   
0
- def start_request_handler
0
+ # Initialize the request handler and enter its main loop.
0
+ # Spawn information will be sent back via _channel_.
0
+ def start_request_handler(channel)
0
     $0 = "Rails: #{@app_root}"
0
     reader, writer = IO.pipe
0
     begin
0
@@ -379,14 +362,14 @@ private
0
       end
0
       
0
       handler = RequestHandler.new(reader)
0
- client.write(Process.pid, handler.socket_name,
0
+ channel.write(Process.pid, handler.socket_name,
0
         handler.using_abstract_namespace?)
0
- client.send_io(writer)
0
+ channel.send_io(writer)
0
       writer.close
0
- client.close
0
+ channel.close
0
       handler.main_loop
0
     ensure
0
- client.close rescue nil
0
+ channel.close rescue nil
0
       writer.close rescue nil
0
       handler.cleanup rescue nil
0
     end
...
145
146
147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
149
150
...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
0
@@ -145,6 +145,22 @@ protected
0
       STDERR.flush
0
     end
0
   end
0
+
0
+ # Fork a new process and run the given block inside the child process, just like
0
+ # fork(). Unlike fork(), this method is safe, i.e. there's no way for the child
0
+ # process to escape the block. Any uncaught exceptions in the child process will
0
+ # be printed to standard output, citing _current_location_ as the source.
0
+ def safe_fork(current_location)
0
+ return fork do
0
+ begin
0
+ yield
0
+ rescue Exception => e
0
+ print_exception(current_location, e)
0
+ ensure
0
+ exit!
0
+ end
0
+ end
0
+ end
0
 end
0
 
0
 end # module Passenger

Comments

    No one has commented yet.