passenger 4.0.0.rc4 → 4.0.0.rc6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (83) hide show
  1. data.tar.gz.asc +12 -0
  2. data/.travis.yml +4 -4
  3. data/NEWS +46 -0
  4. data/bin/passenger-config +31 -1
  5. data/bin/passenger-install-apache2-module +1 -1
  6. data/bin/passenger-install-nginx-module +1 -0
  7. data/build/common_library.rb +4 -0
  8. data/build/cplusplus_support.rb +27 -6
  9. data/build/cxx_tests.rb +1 -1
  10. data/build/misc.rb +28 -6
  11. data/build/packaging.rb +72 -65
  12. data/build/test_basics.rb +1 -1
  13. data/dev/googlecode_upload.py +265 -0
  14. data/dev/run_travis.sh +9 -0
  15. data/doc/Users guide Apache.html +376 -193
  16. data/doc/Users guide Apache.idmap.txt +80 -62
  17. data/doc/Users guide Apache.txt +61 -35
  18. data/doc/Users guide Nginx.html +278 -83
  19. data/doc/Users guide Nginx.idmap.txt +26 -10
  20. data/doc/Users guide Nginx.txt +59 -31
  21. data/doc/Users guide Standalone.html +1 -1
  22. data/doc/users_guide_snippets/installation.txt +121 -11
  23. data/doc/users_guide_snippets/rvm_helper_tool.txt +56 -0
  24. data/ext/apache2/Bucket.cpp +1 -1
  25. data/ext/apache2/Configuration.cpp +7 -1
  26. data/ext/apache2/Configuration.hpp +4 -0
  27. data/ext/apache2/Hooks.cpp +2 -2
  28. data/ext/common/AgentsStarter.cpp +2 -2
  29. data/ext/common/AgentsStarter.h +1 -1
  30. data/ext/common/AgentsStarter.hpp +2 -2
  31. data/ext/common/ApplicationPool2/DirectSpawner.h +4 -8
  32. data/ext/common/ApplicationPool2/Group.h +17 -11
  33. data/ext/common/ApplicationPool2/Implementation.cpp +39 -11
  34. data/ext/common/ApplicationPool2/Pool.h +23 -4
  35. data/ext/common/ApplicationPool2/Process.h +30 -11
  36. data/ext/common/ApplicationPool2/SmartSpawner.h +3 -1
  37. data/ext/common/Constants.h +1 -1
  38. data/ext/common/EventedBufferedInput.h +4 -0
  39. data/ext/common/Utils.cpp +21 -3
  40. data/ext/common/Utils.h +8 -1
  41. data/ext/common/Utils/HttpHeaderBufferer.h +1 -1
  42. data/ext/common/Utils/IOUtils.cpp +5 -4
  43. data/ext/common/Utils/IOUtils.h +32 -14
  44. data/ext/common/Utils/MessagePassing.h +2 -2
  45. data/ext/common/Utils/ProcessMetricsCollector.h +47 -15
  46. data/ext/common/Utils/ScopeGuard.h +20 -3
  47. data/ext/common/Utils/StrIntUtils.h +14 -5
  48. data/ext/common/agents/Base.cpp +161 -50
  49. data/ext/common/agents/HelperAgent/AgentOptions.h +2 -2
  50. data/ext/common/agents/HelperAgent/Main.cpp +1 -0
  51. data/ext/common/agents/HelperAgent/RequestHandler.h +166 -52
  52. data/ext/common/agents/LoggingAgent/Main.cpp +1 -1
  53. data/ext/common/agents/Watchdog/Main.cpp +2 -2
  54. data/ext/nginx/Configuration.c +31 -4
  55. data/ext/nginx/Configuration.h +1 -0
  56. data/ext/nginx/ContentHandler.c +148 -34
  57. data/ext/nginx/ngx_http_passenger_module.c +4 -1
  58. data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
  59. data/ext/oxt/macros.hpp +30 -8
  60. data/lib/phusion_passenger.rb +2 -2
  61. data/lib/phusion_passenger/classic_rails/thread_handler_extension.rb +1 -1
  62. data/lib/phusion_passenger/native_support.rb +19 -1
  63. data/lib/phusion_passenger/platform_info/compiler.rb +6 -0
  64. data/lib/phusion_passenger/platform_info/ruby.rb +54 -5
  65. data/lib/phusion_passenger/preloader_shared_helpers.rb +8 -1
  66. data/lib/phusion_passenger/rack/out_of_band_gc.rb +3 -1
  67. data/lib/phusion_passenger/rack/thread_handler_extension.rb +32 -5
  68. data/lib/phusion_passenger/request_handler/thread_handler.rb +28 -8
  69. data/lib/phusion_passenger/ruby_core_enhancements.rb +9 -1
  70. data/lib/phusion_passenger/standalone/runtime_installer.rb +1 -0
  71. data/lib/phusion_passenger/utils/unseekable_socket.rb +50 -5
  72. data/passenger.gemspec +1 -1
  73. data/resources/templates/apache2/config_snippets.txt.erb +1 -1
  74. data/test/cxx/ApplicationPool2/PoolTest.cpp +4 -9
  75. data/test/cxx/RequestHandlerTest.cpp +5 -5
  76. data/test/ruby/classic_rails/loader_spec.rb +1 -1
  77. data/test/ruby/classic_rails/preloader_spec.rb +1 -1
  78. data/test/ruby/request_handler_spec.rb +207 -1
  79. data/test/ruby/shared/loader_sharedspec.rb +1 -0
  80. data/test/ruby/spec_helper.rb +11 -1
  81. data/test/stub/apache2/httpd.conf.erb +1 -1
  82. metadata +5 -3
  83. metadata.gz.asc +12 -0
@@ -252,10 +252,17 @@ public:
252
252
  */
253
253
  DISABLED
254
254
  } enabled;
255
- /** Marks whether the process requested out-of-band work. If so, we need to
256
- * wait until all sessions have ended and the process has been disabled.
257
- */
258
- bool oobwRequested;
255
+ enum OobwStatus {
256
+ /** Process is not using out-of-band work. */
257
+ OOBW_NOT_ACTIVE,
258
+ /** The process has requested out-of-band work. At some point, the code
259
+ * will see this and set the status to OOBW_IN_PROGRESS. */
260
+ OOBW_REQUESTED,
261
+ /** An out-of-band work is in progress. We need to wait until all
262
+ * sessions have ended and the process has been disabled before the
263
+ * out-of-band work can be performed. */
264
+ OOBW_IN_PROGRESS,
265
+ } oobwStatus;
259
266
  /** Caches whether or not the OS process still exists. */
260
267
  mutable bool m_osProcessExists;
261
268
  /** Collected by Pool::collectAnalytics(). */
@@ -291,7 +298,7 @@ public:
291
298
  processed(0),
292
299
  lifeStatus(ALIVE),
293
300
  enabled(ENABLED),
294
- oobwRequested(false),
301
+ oobwStatus(OOBW_NOT_ACTIVE),
295
302
  m_osProcessExists(true)
296
303
  {
297
304
  SpawnerConfigPtr config;
@@ -526,30 +533,42 @@ public:
526
533
  stream << "<uptime>" << uptime() << "</uptime>";
527
534
  switch (lifeStatus) {
528
535
  case ALIVE:
529
- stream << "<life_status>alive</life_status>";
536
+ stream << "<life_status>ALIVE</life_status>";
530
537
  break;
531
538
  case SHUTTING_DOWN:
532
- stream << "<life_status>shutting_down</life_status>";
539
+ stream << "<life_status>SHUTTING_DOWN</life_status>";
533
540
  break;
534
541
  case SHUT_DOWN:
535
- stream << "<life_status>shut_down</life_status>";
542
+ stream << "<life_status>SHUT_DOWN</life_status>";
536
543
  break;
537
544
  default:
538
545
  P_BUG("Unknown 'lifeStatus' state " << (int) lifeStatus);
539
546
  }
540
547
  switch (enabled) {
541
548
  case ENABLED:
542
- stream << "<enabled>enabled</enabled>";
549
+ stream << "<enabled>ENABLED</enabled>";
543
550
  break;
544
551
  case DISABLING:
545
- stream << "<enabled>disabling</enabled>";
552
+ stream << "<enabled>DISABLING</enabled>";
546
553
  break;
547
554
  case DISABLED:
548
- stream << "<enabled>disabled</enabled>";
555
+ stream << "<enabled>DISABLED</enabled>";
549
556
  break;
550
557
  default:
551
558
  P_BUG("Unknown 'enabled' state " << (int) enabled);
552
559
  }
560
+ if (metrics.isValid()) {
561
+ stream << "<has_metrics>true</has_metrics>";
562
+ stream << "<cpu>" << (int) metrics.cpu << "</cpu>";
563
+ stream << "<rss>" << metrics.rss << "</rss>";
564
+ stream << "<pss>" << metrics.pss << "</pss>";
565
+ stream << "<private_dirty>" << metrics.privateDirty << "</private_dirty>";
566
+ stream << "<swap>" << metrics.swap << "</swap>";
567
+ stream << "<real_memory>" << metrics.realMemory() << "</real_memory>";
568
+ stream << "<vmsize>" << metrics.vmsize << "</vmsize>";
569
+ stream << "<process_group_id>" << metrics.processGroupId << "</process_group_id>";
570
+ stream << "<command>" << escapeForXml(metrics.command) << "</command>";
571
+ }
553
572
  if (includeSockets) {
554
573
  SocketList::const_iterator it;
555
574
 
@@ -122,7 +122,9 @@ private:
122
122
  command.push_back(agentsDir + "/SpawnPreparer");
123
123
  command.push_back(serializeEnvvarsFromPoolOptions(options));
124
124
  command.push_back(preloaderCommand[0]);
125
- command.push_back("Passenger AppPreloader: " + options.appRoot);
125
+ // Note: do not try to set a process title here.
126
+ // https://code.google.com/p/phusion-passenger/issues/detail?id=855
127
+ command.push_back(preloaderCommand[0]);
126
128
  for (unsigned int i = 1; i < preloaderCommand.size(); i++) {
127
129
  command.push_back(preloaderCommand[i]);
128
130
  }
@@ -26,7 +26,7 @@
26
26
  #define _PASSENGER_CONSTANTS_H_
27
27
 
28
28
  /* Don't forget to update lib/phusion_passenger.rb too. */
29
- #define PASSENGER_VERSION "4.0.0.rc4"
29
+ #define PASSENGER_VERSION "4.0.0.rc6"
30
30
 
31
31
  #define FEEDBACK_FD 3
32
32
 
@@ -285,6 +285,10 @@ public:
285
285
  return state == END_OF_STREAM;
286
286
  }
287
287
 
288
+ void readNow() {
289
+ onReadable(watcher, 0);
290
+ }
291
+
288
292
  const FileDescriptor &getFd() const {
289
293
  return fd;
290
294
  }
@@ -41,6 +41,10 @@
41
41
  #include <limits.h>
42
42
  #include <unistd.h>
43
43
  #include <signal.h>
44
+ #ifdef __linux__
45
+ #include <sys/syscall.h>
46
+ #include <features.h>
47
+ #endif
44
48
  #include <vector>
45
49
  #include <FileDescriptor.h>
46
50
  #include <MessageServer.h>
@@ -707,7 +711,9 @@ verifyWSGIDir(const string &dir, CachedFileStat *cstat, unsigned int throttleRat
707
711
  }
708
712
 
709
713
  void
710
- prestartWebApps(const ResourceLocator &locator, const string &serializedprestartURLs) {
714
+ prestartWebApps(const ResourceLocator &locator, const string &ruby,
715
+ const string &serializedprestartURLs)
716
+ {
711
717
  /* Apache calls the initialization routines twice during startup, and
712
718
  * as a result it starts two helper servers, where the first one exits
713
719
  * after a short idle period. We want any prespawning requests to reach
@@ -743,7 +749,8 @@ prestartWebApps(const ResourceLocator &locator, const string &serializedprestart
743
749
  syscalls::close(i);
744
750
  }
745
751
 
746
- execlp(prespawnScript.c_str(),
752
+ execlp(ruby.c_str(),
753
+ ruby.c_str(),
747
754
  prespawnScript.c_str(),
748
755
  it->c_str(),
749
756
  (char *) 0);
@@ -957,6 +964,17 @@ runShellCommand(const StaticString &command) {
957
964
  }
958
965
  }
959
966
 
967
+ // Async-signal safe way to fork().
968
+ // http://sourceware.org/bugzilla/show_bug.cgi?id=4737
969
+ pid_t
970
+ asyncFork() {
971
+ #if defined(__linux__)
972
+ return (pid_t) syscall(SYS_fork);
973
+ #else
974
+ return fork();
975
+ #endif
976
+ }
977
+
960
978
  // Async-signal safe way to get the current process's hard file descriptor limit.
961
979
  static int
962
980
  getFileDescriptorLimit() {
@@ -1036,7 +1054,7 @@ getHighestFileDescriptor() {
1036
1054
  }
1037
1055
 
1038
1056
  do {
1039
- pid = fork();
1057
+ pid = asyncFork();
1040
1058
  } while (pid == -1 && errno == EINTR);
1041
1059
 
1042
1060
  if (pid == 0) {
@@ -365,7 +365,8 @@ bool verifyRackDir(const string &dir, CachedFileStat *cstat = 0,
365
365
  bool verifyWSGIDir(const string &dir, CachedFileStat *cstat = 0,
366
366
  unsigned int throttleRate = 0);
367
367
 
368
- void prestartWebApps(const ResourceLocator &locator, const string &serializedprestartURLs);
368
+ void prestartWebApps(const ResourceLocator &locator, const string &ruby,
369
+ const string &serializedprestartURLs);
369
370
 
370
371
  /**
371
372
  * Runs the given function and catches any tracable_exceptions. Upon catching such an exception,
@@ -410,6 +411,12 @@ void disableMallocDebugging();
410
411
  */
411
412
  int runShellCommand(const StaticString &command);
412
413
 
414
+ /**
415
+ * Async-signal safe way to fork().
416
+ * http://sourceware.org/bugzilla/show_bug.cgi?id=4737
417
+ */
418
+ pid_t asyncFork();
419
+
413
420
  /**
414
421
  * Close all file descriptors that are higher than <em>lastToKeepOpen</em>.
415
422
  * This function is async-signal safe. But make sure there are no other
@@ -80,7 +80,7 @@ private:
80
80
  public:
81
81
  HttpHeaderBufferer() {
82
82
  sbmh_init(&u.terminatorFinder,
83
- &staticData.occ,
83
+ NULL,
84
84
  (const unsigned char *) "\r\n\r\n",
85
85
  4);
86
86
  max = 1024 * 128;
@@ -744,7 +744,8 @@ writeExact(int fd, const void *data, unsigned int size, unsigned long long *time
744
744
 
745
745
  void
746
746
  writeExact(int fd, const StaticString &data, unsigned long long *timeout) {
747
- writeExact(fd, data.c_str(), data.size(), timeout);
747
+ const char * restrict data_ptr = data.data();
748
+ writeExact(fd, data_ptr, data.size(), timeout);
748
749
  }
749
750
 
750
751
  /**
@@ -792,7 +793,7 @@ staticStringArrayToIoVec(const StaticString ary[], size_t count, struct iovec *v
792
793
  */
793
794
  static void
794
795
  findDataPositionIndexAndOffset(struct iovec data[], size_t count,
795
- size_t position, size_t *index, size_t *offset)
796
+ size_t position, size_t * restrict index, size_t * restrict offset)
796
797
  {
797
798
  size_t i;
798
799
  size_t begin = 0;
@@ -817,7 +818,7 @@ findDataPositionIndexAndOffset(struct iovec data[], size_t count,
817
818
  }
818
819
 
819
820
  ssize_t
820
- gatheredWrite(int fd, const StaticString data[], unsigned int dataCount, string &restBuffer) {
821
+ gatheredWrite(int fd, const StaticString *data, unsigned int dataCount, string &restBuffer) {
821
822
  size_t totalSize, iovCount, i;
822
823
  ssize_t ret;
823
824
 
@@ -961,7 +962,7 @@ eraseBeginningOfIoVec(struct iovec *iov, size_t count, size_t index, size_t offs
961
962
  }
962
963
 
963
964
  void
964
- gatheredWrite(int fd, const StaticString data[], unsigned int count, unsigned long long *timeout) {
965
+ gatheredWrite(int fd, const StaticString *data, unsigned int count, unsigned long long *timeout) {
965
966
  struct iovec iov[count];
966
967
  size_t total, iovCount;
967
968
  size_t written = 0;
@@ -34,6 +34,7 @@
34
34
  #include <netdb.h>
35
35
  #include <string>
36
36
  #include <vector>
37
+ #include <oxt/macros.hpp>
37
38
  #include <StaticString.h>
38
39
  #include <FileDescriptor.h>
39
40
 
@@ -81,7 +82,9 @@ string parseUnixSocketAddress(const StaticString &address);
81
82
  *
82
83
  * @throw ArgumentException <tt>address</tt> is not a valid TCP socket address.
83
84
  */
84
- void parseTcpSocketAddress(const StaticString &address, string &host, unsigned short &port);
85
+ void parseTcpSocketAddress(const StaticString & restrict_ref address,
86
+ string & restrict_ref host,
87
+ unsigned short & restrict_ref port);
85
88
 
86
89
  /**
87
90
  * Returns whether the given socket address (as accepted by getSocketAddressType())
@@ -103,7 +106,10 @@ void setNonBlocking(int fd);
103
106
  * Try to call the Linux accept4() system call. If the system call is
104
107
  * not available, then -1 is returned and errno is set to ENOSYS.
105
108
  */
106
- int callAccept4(int sock, struct sockaddr *addr, socklen_t *addr_len, int options);
109
+ int callAccept4(int sock,
110
+ struct sockaddr * restrict addr,
111
+ socklen_t * restrict addr_len,
112
+ int options);
107
113
 
108
114
  /**
109
115
  * Resolves the given host name and returns a list of IP addresses.
@@ -116,7 +122,9 @@ int callAccept4(int sock, struct sockaddr *addr, socklen_t *addr_len, int option
116
122
  * IP addresses, then these addresses will be shuffled before they are
117
123
  * returned in order to improve load balancing.
118
124
  */
119
- vector<string> resolveHostname(const string &hostname, unsigned int port = 0, bool shuffle = true);
125
+ vector<string> resolveHostname(const string &hostname,
126
+ unsigned int port = 0,
127
+ bool shuffle = true);
120
128
 
121
129
  /**
122
130
  * Create a new Unix or TCP server socket, depending on the address type.
@@ -134,7 +142,9 @@ vector<string> resolveHostname(const string &hostname, unsigned int port = 0, bo
134
142
  * @throws boost::thread_interrupted A system call has been interrupted.
135
143
  * @ingroup Support
136
144
  */
137
- int createServer(const StaticString &address, unsigned int backlogSize = 0, bool autoDelete = true);
145
+ int createServer(const StaticString &address,
146
+ unsigned int backlogSize = 0,
147
+ bool autoDelete = true);
138
148
 
139
149
  /**
140
150
  * Create a new Unix server socket which is bounded to <tt>filename</tt>.
@@ -149,7 +159,9 @@ int createServer(const StaticString &address, unsigned int backlogSize = 0, bool
149
159
  * @throws boost::thread_interrupted A system call has been interrupted.
150
160
  * @ingroup Support
151
161
  */
152
- int createUnixServer(const StaticString &filename, unsigned int backlogSize = 0, bool autoDelete = true);
162
+ int createUnixServer(const StaticString &filename,
163
+ unsigned int backlogSize = 0,
164
+ bool autoDelete = true);
153
165
 
154
166
  /**
155
167
  * Create a new TCP server socket which is bounded to the given address and port.
@@ -166,7 +178,9 @@ int createUnixServer(const StaticString &filename, unsigned int backlogSize = 0,
166
178
  * @throws boost::thread_interrupted A system call has been interrupted.
167
179
  * @ingroup Support
168
180
  */
169
- int createTcpServer(const char *address = "0.0.0.0", unsigned short port = 0, unsigned int backlogSize = 0);
181
+ int createTcpServer(const char *address = "0.0.0.0",
182
+ unsigned short port = 0,
183
+ unsigned int backlogSize = 0);
170
184
 
171
185
  /**
172
186
  * Connect to a server at the given address in a blocking manner.
@@ -223,7 +237,8 @@ struct NUnix_State {
223
237
  * @throws boost::thread_interrupted A system call has been interrupted.
224
238
  * @ingroup Support
225
239
  */
226
- void setupNonBlockingUnixSocket(NUnix_State &state, const StaticString &filename);
240
+ void setupNonBlockingUnixSocket(NUnix_State & restrict_ref state,
241
+ const StaticString & restrict_ref filename);
227
242
 
228
243
  /**
229
244
  * Connect a Unix domain socket in non-blocking mode.
@@ -270,7 +285,9 @@ struct NTCP_State {
270
285
  * @throws boost::thread_interrupted A system call has been interrupted.
271
286
  * @ingroup Support
272
287
  */
273
- void setupNonBlockingTcpSocket(NTCP_State &state, const StaticString &hostname, int port);
288
+ void setupNonBlockingTcpSocket(NTCP_State & restrict_ref state,
289
+ const StaticString & restrict_ref hostname,
290
+ int port);
274
291
 
275
292
  /**
276
293
  * Connect a TCP socket in non-blocking mode.
@@ -302,7 +319,8 @@ struct NConnect_State {
302
319
  * @throws boost::thread_interrupted A system call has been interrupted.
303
320
  * @ingroup Support
304
321
  */
305
- void setupNonBlockingSocket(NConnect_State &state, const StaticString &address);
322
+ void setupNonBlockingSocket(NConnect_State & restrict_ref state,
323
+ const StaticString & restrict_ref address);
306
324
 
307
325
  /**
308
326
  * Connect a socket in non-blocking mode.
@@ -387,7 +405,7 @@ bool waitUntilWritable(int fd, unsigned long long *timeout);
387
405
  * <tt>timeout</tt> microseconds.
388
406
  * @throws boost::thread_interrupted
389
407
  */
390
- unsigned int readExact(int fd, void *buf, unsigned int size, unsigned long long *timeout = NULL);
408
+ unsigned int readExact(int fd, void * restrict buf, unsigned int size, unsigned long long * restrict timeout = NULL);
391
409
 
392
410
  /**
393
411
  * Writes a block of data to the given file descriptor and blocks until everything
@@ -415,8 +433,8 @@ unsigned int readExact(int fd, void *buf, unsigned int size, unsigned long long
415
433
  * <tt>timeout</tt> microseconds.
416
434
  * @throws boost::thread_interrupted
417
435
  */
418
- void writeExact(int fd, const void *data, unsigned int size, unsigned long long *timeout = NULL);
419
- void writeExact(int fd, const StaticString &data, unsigned long long *timeout = NULL);
436
+ void writeExact(int fd, const void * restrict data, unsigned int size, unsigned long long * restrict timeout = NULL);
437
+ void writeExact(int fd, const StaticString & restrict_ref data, unsigned long long * restrict timeout = NULL);
420
438
 
421
439
  /**
422
440
  * Writes a bunch of data to the given file descriptor using a gathering I/O interface.
@@ -446,7 +464,7 @@ void writeExact(int fd, const StaticString &data, unsigned long long *timeout =
446
464
  * isn't related to non-blocking writes.
447
465
  * @throws boost::thread_interrupted
448
466
  */
449
- ssize_t gatheredWrite(int fd, const StaticString data[], unsigned int dataCount, string &restBuffer);
467
+ ssize_t gatheredWrite(int fd, const StaticString * restrict data, unsigned int dataCount, string & restrict_ref restBuffer);
450
468
 
451
469
  /**
452
470
  * Writes a bunch of data to the given file descriptor using a gathering I/O interface.
@@ -474,7 +492,7 @@ ssize_t gatheredWrite(int fd, const StaticString data[], unsigned int dataCount,
474
492
  * <tt>timeout</tt> microseconds.
475
493
  * @throws boost::thread_interrupted
476
494
  */
477
- void gatheredWrite(int fd, const StaticString data[], unsigned int dataCount, unsigned long long *timeout = NULL);
495
+ void gatheredWrite(int fd, const StaticString * restrict data, unsigned int dataCount, unsigned long long * restrict timeout = NULL);
478
496
 
479
497
  /**
480
498
  * Sets a writev-emulating function that gatheredWrite() should call instead of the real writev().
@@ -221,7 +221,7 @@ public:
221
221
  MessagePtr recv(const string &name, unsigned long long *timeout = NULL) {
222
222
  unique_lock<boost::mutex> l(syncher);
223
223
  posix_time::ptime deadline;
224
- unsigned long long beginTime;
224
+ unsigned long long beginTime = 0; // Shut up compiler warning.
225
225
  if (timeout != NULL) {
226
226
  beginTime = SystemTime::getUsec();
227
227
  deadline = posix_time::microsec_clock::local_time() +
@@ -260,7 +260,7 @@ public:
260
260
  MessagePtr recvAny(const StringCollection &names, unsigned long long *timeout = NULL) {
261
261
  unique_lock<boost::mutex> l(syncher);
262
262
  posix_time::ptime deadline;
263
- unsigned long long beginTime;
263
+ unsigned long long beginTime = 0; // Shut up compiler warning.
264
264
  if (timeout != NULL) {
265
265
  beginTime = SystemTime::getUsec();
266
266
  deadline = posix_time::microsec_clock::local_time() +
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2010, 2011, 2012 Phusion
3
+ * Copyright (c) 2010-2013 Phusion
4
4
  *
5
5
  * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
6
  *
@@ -39,6 +39,12 @@
39
39
  #include <mach/mach_vm.h>
40
40
  #include <mach/mach_port.h>
41
41
  #endif
42
+ #ifndef __NetBSD__
43
+ // NetBSD does not support -p with multiple PIDs.
44
+ // https://code.google.com/p/phusion-passenger/issues/detail?id=736
45
+ #define PS_SUPPORTS_MULTIPLE_PIDS
46
+ #include <set>
47
+ #endif
42
48
 
43
49
  #include <sys/types.h>
44
50
  #include <sys/wait.h>
@@ -68,9 +74,9 @@ struct ProcessMetrics {
68
74
  pid_t ppid;
69
75
  uint8_t cpu;
70
76
  /** Resident Set Size, amount of memory in RAM. Does not include swap.
71
- * 0 if completely swapped out.
77
+ * -1 if not yet known, 0 if completely swapped out.
72
78
  */
73
- size_t rss;
79
+ ssize_t rss;
74
80
  /** Proportional Set Size, see measureRealMemory(). Does not include swap.
75
81
  * -1 if unknown, 0 if completely swapped out.
76
82
  */
@@ -90,9 +96,11 @@ struct ProcessMetrics {
90
96
 
91
97
  ProcessMetrics() {
92
98
  pid = (pid_t) -1;
99
+ rss = -1;
93
100
  pss = -1;
94
101
  privateDirty = -1;
95
102
  swap = -1;
103
+ vmsize = -1;
96
104
  }
97
105
 
98
106
  bool isValid() const {
@@ -114,8 +122,10 @@ struct ProcessMetrics {
114
122
  }
115
123
  if (privateDirty != -1) {
116
124
  return privateDirty + swap;
117
- } else {
125
+ } else if (rss != -1) {
118
126
  return rss + swap;
127
+ } else {
128
+ return 0;
119
129
  }
120
130
  }
121
131
  };
@@ -321,7 +331,8 @@ private:
321
331
  return string(data, endOfLine - data);
322
332
  }
323
333
 
324
- ProcessMetricMap parsePsOutput(const string &output) const {
334
+ template<typename Collection, typename ConstIterator>
335
+ ProcessMetricMap parsePsOutput(const string &output, const Collection &allowedPids) const {
325
336
  ProcessMetricMap result;
326
337
  // Ignore first line, it contains the column names.
327
338
  const char *start = strchr(output.c_str(), '\n');
@@ -332,6 +343,14 @@ private:
332
343
  start = NULL;
333
344
  }
334
345
  }
346
+
347
+ #ifndef PS_SUPPORTS_MULTIPLE_PIDS
348
+ set<pid_t> pids;
349
+ ConstIterator it, end = allowedPids.end();
350
+ for (it = allowedPids.begin(); it != allowedPids.end(); it++) {
351
+ pids.insert(*it);
352
+ }
353
+ #endif
335
354
 
336
355
  // Parse each line.
337
356
  while (start != NULL) {
@@ -344,14 +363,24 @@ private:
344
363
  metrics.vmsize = (size_t) readNextWordAsLongLong(&start);
345
364
  metrics.processGroupId = (pid_t) readNextWordAsLongLong(&start);
346
365
  metrics.command = readRestOfLine(start);
347
- result[metrics.pid] = metrics;
348
-
349
- start = strchr(start, '\n');
350
- if (start != NULL) {
351
- // Skip to beginning of next line.
352
- start++;
353
- if (*start == '\0') {
354
- start = NULL;
366
+
367
+ bool pidAllowed;
368
+ #ifdef PS_SUPPORTS_MULTIPLE_PIDS
369
+ pidAllowed = true;
370
+ #else
371
+ pidAllowed = pids.find(metrics.pid) != pids.end();
372
+ #endif
373
+
374
+ if (pidAllowed) {
375
+ result[metrics.pid] = metrics;
376
+
377
+ start = strchr(start, '\n');
378
+ if (start != NULL) {
379
+ // Skip to beginning of next line.
380
+ start++;
381
+ if (*start == '\0') {
382
+ start = NULL;
383
+ }
355
384
  }
356
385
  }
357
386
  }
@@ -406,7 +435,10 @@ public:
406
435
  #else
407
436
  "pid,ppid,%cpu,rss,vsize,pgid,command",
408
437
  #endif
409
- "-p", pidsArg.c_str(), NULL
438
+ #ifdef PS_SUPPORTS_MULTIPLE_PIDS
439
+ "-p", pidsArg.c_str(),
440
+ #endif
441
+ NULL
410
442
  };
411
443
 
412
444
  string psOutput = this->psOutput;
@@ -414,7 +446,7 @@ public:
414
446
  psOutput = runCommandAndCaptureOutput(command);
415
447
  }
416
448
  pidsArg.resize(0);
417
- ProcessMetricMap result = parsePsOutput(psOutput);
449
+ ProcessMetricMap result = parsePsOutput<Collection, ConstIterator>(psOutput, pids);
418
450
  psOutput.resize(0);
419
451
  if (canMeasureRealMemory) {
420
452
  ProcessMetricMap::iterator it;