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 !
Fix worker MPM compatibility issues:
- Fix thread-safety issues in ApplicationPoolServer.
- Fix file descriptor double closing issues.
Hongli Lai (Phusion) (author)
Sun May 11 04:34:32 -0700 2008
commit  a34583acce30584678bf8f1782291d7070d4f695
tree    a073f5d8a4b98e9420454c17b9c5ccfb23cba0ca
parent  2c84e3a42bb45b5a25b183011897134ae67840dd
...
147
148
149
150
 
151
152
153
...
147
148
149
 
150
151
152
153
0
@@ -147,7 +147,7 @@ subdir 'ext/apache2' do
0
   ] do
0
     create_executable "ApplicationPoolServerExecutable",
0
       'ApplicationPoolServerExecutable.cpp Utils.o Logging.o',
0
- "-I.. #{CXXFLAGS} #{LDFLAGS} ../boost/src/libboost_thread.a -lpthread"
0
+ "-I.. #{CXXFLAGS} #{LDFLAGS} -DPASSENGER_DEBUG ../boost/src/libboost_thread.a -lpthread"
0
   end
0
   
0
   desc "Install mod_passenger Apache 2 module"
...
143
144
145
146
147
148
149
150
151
152
...
155
156
157
158
 
 
 
159
160
161
...
177
178
179
 
 
 
 
 
 
180
181
182
...
229
230
231
 
 
 
 
232
233
234
...
143
144
145
 
 
 
 
146
147
148
...
151
152
153
 
154
155
156
157
158
159
...
175
176
177
178
179
180
181
182
183
184
185
186
...
233
234
235
236
237
238
239
240
241
242
0
@@ -143,10 +143,6 @@ public:
0
           "already been closed.");
0
       }
0
       try {
0
- /* fprintf(stderr, "Block: ");
0
- fwrite(block, 1, size, stderr);
0
- fprintf(stderr, "\n");
0
- fflush(stderr); */
0
         MessageChannel(stream).writeRaw(block, size);
0
       } catch (const SystemException &e) {
0
         throw SystemException("An error occured while sending the "
0
@@ -155,7 +151,9 @@ public:
0
     }
0
     
0
     /**
0
- * Get the I/O stream's file descriptor. This steam is full-duplex.
0
+ * Get the I/O stream's file descriptor. This steam is full-duplex,
0
+ * and will be automatically closed upon Session's destruction,
0
+ * unless discardStream() is called.
0
      *
0
      * @pre The stream has not been fully closed.
0
      */
0
@@ -177,6 +175,12 @@ public:
0
     virtual void closeStream() = 0;
0
     
0
     /**
0
+ * Discard the I/O stream's file descriptor, so that Session won't automatically
0
+ * closed it upon Session's destruction.
0
+ */
0
+ virtual void discardStream() = 0;
0
+
0
+ /**
0
      * Get the process ID of the application instance that belongs to this session.
0
      */
0
     virtual pid_t getPid() const = 0;
0
@@ -229,6 +233,10 @@ private:
0
       }
0
     }
0
     
0
+ virtual void discardStream() {
0
+ fd = -1;
0
+ }
0
+
0
     virtual pid_t getPid() const {
0
       return pid;
0
     }
...
19
20
21
 
22
23
24
...
135
136
137
 
 
138
139
140
...
161
162
163
 
164
165
166
...
187
188
189
 
 
 
 
190
191
192
...
199
200
201
202
 
 
 
 
203
204
205
...
208
209
210
211
 
 
212
213
214
215
216
 
217
218
219
220
221
 
222
223
224
225
226
 
227
228
229
230
231
 
232
233
234
...
238
239
240
 
241
242
243
...
247
248
249
 
250
251
252
...
262
263
264
 
265
266
 
267
268
269
...
275
276
277
278
279
 
 
 
 
 
 
 
 
 
280
281
282
283
 
 
284
285
286
287
288
289
 
 
290
291
292
...
295
296
297
298
 
 
299
300
301
...
19
20
21
22
23
24
25
...
136
137
138
139
140
141
142
143
...
164
165
166
167
168
169
170
...
191
192
193
194
195
196
197
198
199
200
...
207
208
209
 
210
211
212
213
214
215
216
...
219
220
221
 
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
...
254
255
256
257
258
259
260
...
264
265
266
267
268
269
270
...
280
281
282
283
284
285
286
287
288
289
...
295
296
297
 
 
298
299
300
301
302
303
304
305
306
307
308
309
 
310
311
312
313
314
315
316
 
317
318
319
320
321
...
324
325
326
 
327
328
329
330
331
0
@@ -19,6 +19,7 @@
0
 #define _PASSENGER_APPLICATION_POOL_SERVER_H_
0
 
0
 #include <boost/shared_ptr.hpp>
0
+#include <boost/thread/mutex.hpp>
0
 
0
 #include <sys/types.h>
0
 #include <sys/wait.h>
0
@@ -135,6 +136,8 @@ private:
0
      */
0
     int server;
0
     
0
+ mutex lock;
0
+
0
     ~SharedData() {
0
       close(server);
0
     }
0
@@ -161,6 +164,7 @@ private:
0
     
0
     virtual ~RemoteSession() {
0
       closeStream();
0
+ mutex::scoped_lock(data->lock);
0
       MessageChannel(data->server).write("close", toString(id).c_str(), NULL);
0
     }
0
     
0
@@ -187,6 +191,10 @@ private:
0
       }
0
     }
0
     
0
+ virtual void discardStream() {
0
+ fd = -1;
0
+ }
0
+
0
     virtual pid_t getPid() const {
0
       return pid;
0
     }
0
@@ -199,7 +207,10 @@ private:
0
    */
0
   class Client: public ApplicationPool {
0
   private:
0
- SharedDataPtr data;
0
+ // The smart pointer only serves to keep the shared data alive.
0
+ // We access the shared data via a normal pointer, for performance.
0
+ SharedDataPtr dataSmartPointer;
0
+ SharedData *data;
0
     
0
   public:
0
     /**
0
@@ -208,27 +219,32 @@ private:
0
      * @param sock The newly established socket connection with the ApplicationPoolServer.
0
      */
0
     Client(int sock) {
0
- data = ptr(new SharedData());
0
+ dataSmartPointer = ptr(new SharedData());
0
+ data = dataSmartPointer.get();
0
       data->server = sock;
0
     }
0
     
0
     virtual void clear() {
0
       MessageChannel channel(data->server);
0
+ mutex::scoped_lock l(data->lock);
0
       channel.write("clear", NULL);
0
     }
0
     
0
     virtual void setMaxIdleTime(unsigned int seconds) {
0
       MessageChannel channel(data->server);
0
+ mutex::scoped_lock l(data->lock);
0
       channel.write("setMaxIdleTime", toString(seconds).c_str(), NULL);
0
     }
0
     
0
     virtual void setMax(unsigned int max) {
0
       MessageChannel channel(data->server);
0
+ mutex::scoped_lock l(data->lock);
0
       channel.write("setMax", toString(max).c_str(), NULL);
0
     }
0
     
0
     virtual unsigned int getActive() const {
0
       MessageChannel channel(data->server);
0
+ mutex::scoped_lock l(data->lock);
0
       vector<string> args;
0
       
0
       channel.write("getActive", NULL);
0
@@ -238,6 +254,7 @@ private:
0
     
0
     virtual unsigned int getCount() const {
0
       MessageChannel channel(data->server);
0
+ mutex::scoped_lock l(data->lock);
0
       vector<string> args;
0
       
0
       channel.write("getCount", NULL);
0
@@ -247,6 +264,7 @@ private:
0
     
0
     virtual pid_t getSpawnServerPid() const {
0
       MessageChannel channel(data->server);
0
+ mutex::scoped_lock l(data->lock);
0
       vector<string> args;
0
       
0
       channel.write("getSpawnServerPid", NULL);
0
@@ -262,8 +280,10 @@ private:
0
       const string &spawnMethod = "smart"
0
     ) {
0
       MessageChannel channel(data->server);
0
+ mutex::scoped_lock l(data->lock);
0
       vector<string> args;
0
       int stream;
0
+ bool result;
0
       
0
       try {
0
         channel.write("get", appRoot.c_str(),
0
@@ -275,18 +295,27 @@ private:
0
       } catch (const SystemException &) {
0
         throw IOException("The ApplicationPool server exited unexpectedly.");
0
       }
0
- if (!channel.read(args)) {
0
- throw IOException("The ApplicationPool server unexpectedly closed the connection.");
0
+ try {
0
+ result = channel.read(args);
0
+ } catch (const SystemException &e) {
0
+ throw SystemException("Could not read a message from "
0
+ "the ApplicationPool server", e.code());
0
+ }
0
+ if (!result) {
0
+ throw IOException("The ApplicationPool server unexpectedly "
0
+ "closed the connection.");
0
       }
0
       if (args[0] == "ok") {
0
         stream = channel.readFileDescriptor();
0
- return ptr(new RemoteSession(data, atoi(args[1]), atoi(args[2]), stream));
0
+ return ptr(new RemoteSession(dataSmartPointer,
0
+ atoi(args[1]), atoi(args[2]), stream));
0
       } else if (args[0] == "SpawnException") {
0
         if (args[2] == "true") {
0
           string errorPage;
0
           
0
           if (!channel.readScalar(errorPage)) {
0
- throw IOException("The ApplicationPool server unexpectedly closed the connection.");
0
+ throw IOException("The ApplicationPool server "
0
+ "unexpectedly closed the connection.");
0
           }
0
           throw SpawnException(args[1], errorPage);
0
         } else {
0
@@ -295,7 +324,8 @@ private:
0
       } else if (args[0] == "IOException") {
0
         throw IOException(args[1]);
0
       } else {
0
- throw IOException("The ApplicationPool server returned an unknown message.");
0
+ throw IOException("The ApplicationPool server returned "
0
+ "an unknown message: " + toString(args));
0
       }
0
     }
0
   };
...
224
225
226
227
228
229
 
 
 
230
231
232
233
234
235
236
 
 
 
 
 
 
 
 
 
237
238
239
...
254
255
256
 
 
 
 
 
257
258
259
260
261
262
263
...
224
225
226
 
 
 
227
228
229
230
231
232
233
 
 
 
234
235
236
237
238
239
240
241
242
243
244
245
...
260
261
262
263
264
265
266
267
268
 
 
 
269
270
271
0
@@ -224,16 +224,22 @@ private:
0
    * The entry point of the thread that handles the client connection.
0
    */
0
   void threadMain(const weak_ptr<Client> self) {
0
- try {
0
- vector<string> args;
0
- while (true) {
0
+ vector<string> args;
0
+ while (true) {
0
+ try {
0
         if (!channel.read(args)) {
0
           // Client closed connection.
0
           break;
0
         }
0
-
0
- P_TRACE(3, "Client " << this << ": received message: " <<
0
- toString(args));
0
+ } catch (const SystemException &e) {
0
+ P_WARN("Exception in ApplicationPoolServer client thread during "
0
+ "reading of a message: " << e.what());
0
+ break;
0
+ }
0
+
0
+ P_TRACE(4, "Client " << this << ": received message: " <<
0
+ toString(args));
0
+ try {
0
         if (args[0] == "get" && args.size() == 6) {
0
           processGet(args);
0
         } else if (args[0] == "close" && args.size() == 2) {
0
@@ -254,10 +260,12 @@ private:
0
           processUnknownMessage(args);
0
           break;
0
         }
0
+ } catch (const exception &e) {
0
+ P_WARN("Uncaught exception in ApplicationPoolServer client thread:\n"
0
+ << " message: " << toString(args) << "\n"
0
+ << " exception: " << e.what());
0
+ break;
0
       }
0
- } catch (const exception &e) {
0
- P_WARN("Uncaught exception in ApplicationPoolServer client thread: " <<
0
- e.what());
0
     }
0
     
0
     mutex::scoped_lock l(server.lock);
...
407
408
409
410
411
412
413
...
462
463
464
 
 
 
 
465
466
467
...
407
408
409
 
410
411
412
...
461
462
463
464
465
466
467
468
469
470
0
@@ -407,7 +407,6 @@ public:
0
       apr_bucket *b;
0
       Application::SessionPtr session;
0
       
0
- P_DEBUG("Processing HTTP request: " << r->uri);
0
       try {
0
         const char *defaultUser, *environment, *spawnMethod;
0
         ServerConfig *sconfig;
0
@@ -462,6 +461,10 @@ public:
0
       Container *container = new Container();
0
       container->session = session;
0
       apr_pool_cleanup_register(r->pool, container, Container::cleanup, apr_pool_cleanup_null);
0
+
0
+ // Apparently apr_bucket_pipe or apr_brigade closes the
0
+ // file descriptor for us.
0
+ session->discardStream();
0
 
0
       return OK;
0
     } catch (const exception &e) {

Comments

    No one has commented yet.