public
Description: Phusion Passenger (mod_rails)
Homepage: http://www.modrails.com/
Clone URL: git://github.com/FooBarWidget/passenger.git
Search Repo:
Click here to lend your support to: passenger and make a donation at www.pledgie.com !
- Add status reporting mechanism: the ApplicationPool's state can now be 
inspected by reading /tmp/passenger_status.*.fifo
- Improve ApplicationPoolServer's shutdown mechanism: fix conflicts with 
mod_wsgi.
Hongli Lai (Phusion) (author)
Wed May 14 17:18:54 -0700 2008
commit  19401c6b554eb9bf99676696fc5f23bb74e98ec1
tree    37af3c6facb442b58b53af516f44eed8ba74ef31
parent  341da0db57a51bd04109e849cd68c99ca4585658
...
374
375
376
 
 
 
 
 
 
 
 
 
 
377
378
379
...
412
413
414
415
 
416
417
418
...
554
555
556
557
 
 
 
 
558
559
560
...
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
...
422
423
424
 
425
426
427
428
...
564
565
566
 
567
568
569
570
571
572
573
0
@@ -374,6 +374,16 @@ private:
0
       ret = close(serverSocket);
0
     } while (ret == -1 && errno == EINTR);
0
     
0
+ /*
0
+ * Some Apache modules fork(), but don't close file descriptors.
0
+ * mod_wsgi is one such example. Because of that, closing serverSocket
0
+ * won't cause the ApplicationPool server to exit. So we send it a
0
+ * signal.
0
+ */
0
+ do {
0
+ ret = kill(serverPid, SIGINT);
0
+ } while (ret == -1 && errno == EINTR);
0
+
0
     P_DEBUG("Waiting for existing ApplicationPoolServerExecutable to exit...");
0
     begin = time(NULL);
0
     while (!done && time(NULL) < begin + 5) {
0
@@ -412,7 +422,7 @@ private:
0
     
0
     pid = fork();
0
     if (pid == 0) { // Child process.
0
- dup2(fds[0], 3);
0
+ dup2(fds[0], SERVER_SOCKET_FD);
0
       
0
       // Close all unnecessary file descriptors
0
       for (long i = sysconf(_SC_OPEN_MAX) - 1; i > SERVER_SOCKET_FD; i--) {
0
@@ -554,7 +564,10 @@ public:
0
    * before calling detach().
0
    */
0
   void detach() {
0
- close(serverSocket);
0
+ int ret;
0
+ do {
0
+ ret = close(serverSocket);
0
+ } while (ret == -1 && errno == EINTR);
0
     serverSocket = -1;
0
   }
0
 };
...
34
35
36
 
 
37
38
 
 
 
39
40
41
...
58
59
60
 
 
61
62
63
...
71
72
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
75
76
...
79
80
81
 
82
 
 
 
 
 
 
 
 
 
 
 
 
 
83
84
85
...
101
102
103
 
 
104
105
106
...
318
319
320
 
 
 
 
 
321
322
323
 
 
 
 
 
 
 
 
 
 
 
 
324
325
326
...
328
329
330
331
332
 
 
333
334
335
...
339
340
341
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
...
386
387
388
389
390
391
392
...
34
35
36
37
38
39
40
41
42
43
44
45
46
...
63
64
65
66
67
68
69
70
...
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
...
155
156
157
158
159
160
161
162
...
374
375
376
377
378
379
380
381
382
383
 
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
...
400
401
402
 
 
403
404
405
406
407
...
411
412
413
 
 
 
 
 
 
 
 
 
414
415
416
417
418
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
420
421
422
423
424
425
...
442
443
444
 
445
446
447
0
@@ -34,8 +34,13 @@
0
 #include <boost/bind.hpp>
0
 #include <boost/thread/thread.hpp>
0
 
0
+#include <sys/types.h>
0
+#include <sys/stat.h>
0
 #include <sys/time.h>
0
 #include <sys/resource.h>
0
+#include <limits.h>
0
+#include <unistd.h>
0
+#include <signal.h>
0
 #include <string>
0
 #include <vector>
0
 #include <set>
0
@@ -58,6 +63,8 @@ typedef shared_ptr<Client> ClientPtr;
0
 
0
 #define SERVER_SOCKET_FD 3
0
 
0
+static bool serverDone = false;
0
+
0
 
0
 /*****************************************
0
  * Server
0
@@ -71,6 +78,39 @@ private:
0
   StandardApplicationPool pool;
0
   set<ClientPtr> clients;
0
   mutex lock;
0
+ string statusReportFIFO;
0
+
0
+ void statusReportThread() {
0
+ while (true) {
0
+ struct stat buf;
0
+ int ret;
0
+
0
+ do {
0
+ ret = stat(statusReportFIFO.c_str(), &buf);
0
+ } while (ret == -1 && errno == EINTR);
0
+ if (ret == -1 || !S_ISFIFO(buf.st_mode)) {
0
+ // Something bad happened with the status
0
+ // report FIFO, so we bail out.
0
+ return;
0
+ }
0
+
0
+ FILE *f;
0
+
0
+ do {
0
+ f = fopen(statusReportFIFO.c_str(), "w");
0
+ } while (f == NULL && errno == EINTR);
0
+ if (f == NULL) {
0
+ return;
0
+ }
0
+
0
+ string report(pool.toString());
0
+ fwrite(report.c_str(), 1, report.size(), f);
0
+ fclose(f);
0
+
0
+ // Prevent sending too much data at once.
0
+ sleep(1);
0
+ }
0
+ }
0
 
0
 public:
0
   Server(int serverSocket,
0
@@ -79,7 +119,21 @@ public:
0
    const string &rubyCommand,
0
    const string &user)
0
     : pool(spawnServerCommand, logFile, rubyCommand, user) {
0
+
0
     this->serverSocket = serverSocket;
0
+
0
+ char filename[PATH_MAX];
0
+ snprintf(filename, sizeof(filename), "/tmp/passenger_status.%d.fifo",
0
+ getpid());
0
+ filename[PATH_MAX - 1] = '\0';
0
+ if (mkfifo(filename, S_IRUSR | S_IWUSR) == -1 && errno != EEXIST) {
0
+ fprintf(stderr, "*** WARNING: Could not create FIFO '%s'; "
0
+ "disabling Passenger ApplicationPool status reporting.\n",
0
+ filename);
0
+ fflush(stderr);
0
+ } else {
0
+ statusReportFIFO = filename;
0
+ }
0
   }
0
   
0
   ~Server() {
0
@@ -101,6 +155,8 @@ public:
0
       clients.clear();
0
     }
0
     clientsCopy.clear();
0
+
0
+ unlink(statusReportFIFO.c_str());
0
   }
0
   
0
   int start(); // Will be defined later, because Client depends on Server's interface.
0
@@ -318,9 +374,25 @@ public:
0
 };
0
 
0
 
0
+static void
0
+gracefulShutdown(int sig) {
0
+ serverDone = true;
0
+}
0
+
0
 int
0
 Server::start() {
0
- while (true) {
0
+ if (!statusReportFIFO.empty()) {
0
+ new thread(
0
+ bind(&Server::statusReportThread, this),
0
+ 1024 * 128
0
+ );
0
+ }
0
+
0
+ serverDone = false;
0
+ signal(SIGINT, gracefulShutdown);
0
+ siginterrupt(SIGINT, 1);
0
+
0
+ while (!serverDone) {
0
     int fds[2], ret;
0
     char x;
0
     
0
@@ -328,8 +400,8 @@ Server::start() {
0
     // and is not important.
0
     do {
0
       ret = read(serverSocket, &x, 1);
0
- } while (ret == -1 && errno == EINTR);
0
- if (ret == 0) {
0
+ } while (ret == -1 && errno == EINTR && !serverDone);
0
+ if (ret == 0 || serverDone) {
0
       // All web server processes disconnected from this server.
0
       // So we can safely quit.
0
       break;
0
@@ -339,31 +411,15 @@ Server::start() {
0
     // ApplicationPool client.
0
     do {
0
       ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
0
- } while (ret == -1 && errno == EINTR);
0
- if (ret == -1) {
0
- int e = errno;
0
- P_ERROR("Cannot create an anonymous Unix socket: " <<
0
- strerror(e) << " (" << e << ") --- aborting!");
0
- abort();
0
-
0
- // Shut up compiler warning.
0
- printf("%d", e);
0
+ } while (ret == -1 && errno == EINTR && !serverDone);
0
+ if (ret == -1 || serverDone) {
0
+ throw SystemException("Cannot create an anonymous Unix socket", errno);
0
     }
0
     
0
- try {
0
- MessageChannel(serverSocket).writeFileDescriptor(fds[1]);
0
- do {
0
- ret = close(fds[1]);
0
- } while (ret == -1 && errno == EINTR);
0
- } catch (SystemException &e) {
0
- P_ERROR("Cannot send a file descriptor: " << e.sys() <<
0
- " --- aborting!");
0
- abort();
0
- } catch (const exception &e) {
0
- P_ERROR("Cannot send a file descriptor: " << e.what() <<
0
- " --- aborting!");
0
- abort();
0
- }
0
+ MessageChannel(serverSocket).writeFileDescriptor(fds[1]);
0
+ do {
0
+ ret = close(fds[1]);
0
+ } while (ret == -1 && errno == EINTR);
0
     
0
     ClientPtr client(new Client(*this, fds[0]));
0
     pair<set<ClientPtr>::iterator, bool> p;
0
@@ -386,7 +442,6 @@ main(int argc, char *argv[]) {
0
       "ApplicationPool server:\n%s\n",
0
       e.what());
0
     fflush(stderr);
0
- abort();
0
     return 1;
0
   }
0
 }
...
26
27
28
 
29
30
31
32
33
 
34
35
36
...
530
531
532
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
533
534
535
...
26
27
28
29
30
31
32
33
34
35
36
37
38
...
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
0
@@ -26,11 +26,13 @@
0
 #include <boost/bind.hpp>
0
 
0
 #include <string>
0
+#include <sstream>
0
 #include <map>
0
 #include <list>
0
 
0
 #include <sys/types.h>
0
 #include <sys/stat.h>
0
+#include <stdio.h>
0
 #include <unistd.h>
0
 #include <ctime>
0
 #include <cerrno>
0
@@ -530,6 +532,40 @@ public:
0
   virtual pid_t getSpawnServerPid() const {
0
     return spawnManager.getServerPid();
0
   }
0
+
0
+ /**
0
+ * Returns a textual description of the internal state of
0
+ * the application pool.
0
+ */
0
+ virtual string toString() const {
0
+ mutex::scoped_lock l(lock);
0
+ stringstream result;
0
+
0
+ result << "----------- General information -----------" << endl;
0
+ result << "max = " << max << endl;
0
+ result << "count = " << count << endl;
0
+ result << "active = " << active << endl;
0
+ result << endl;
0
+
0
+ result << "----------- Applications -----------" << endl;
0
+ ApplicationMap::const_iterator it;
0
+ for (it = apps.begin(); it != apps.end(); it++) {
0
+ AppContainerList *list = it->second.get();
0
+ AppContainerList::const_iterator lit;
0
+
0
+ result << it->first << ": " << endl;
0
+ for (lit = list->begin(); lit != list->end(); lit++) {
0
+ AppContainer *container = lit->get();
0
+ char buf[128];
0
+
0
+ snprintf(buf, sizeof(buf), "PID: %-8d Sessions: %d",
0
+ container->app->getPid(), container->sessions);
0
+ result << " " << buf << endl;
0
+ }
0
+ result << endl;
0
+ }
0
+ return result.str();
0
+ }
0
 };
0
 
0
 } // namespace Passenger

Comments

    No one has commented yet.