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.
- data.tar.gz.asc +12 -0
- data/.travis.yml +4 -4
- data/NEWS +46 -0
- data/bin/passenger-config +31 -1
- data/bin/passenger-install-apache2-module +1 -1
- data/bin/passenger-install-nginx-module +1 -0
- data/build/common_library.rb +4 -0
- data/build/cplusplus_support.rb +27 -6
- data/build/cxx_tests.rb +1 -1
- data/build/misc.rb +28 -6
- data/build/packaging.rb +72 -65
- data/build/test_basics.rb +1 -1
- data/dev/googlecode_upload.py +265 -0
- data/dev/run_travis.sh +9 -0
- data/doc/Users guide Apache.html +376 -193
- data/doc/Users guide Apache.idmap.txt +80 -62
- data/doc/Users guide Apache.txt +61 -35
- data/doc/Users guide Nginx.html +278 -83
- data/doc/Users guide Nginx.idmap.txt +26 -10
- data/doc/Users guide Nginx.txt +59 -31
- data/doc/Users guide Standalone.html +1 -1
- data/doc/users_guide_snippets/installation.txt +121 -11
- data/doc/users_guide_snippets/rvm_helper_tool.txt +56 -0
- data/ext/apache2/Bucket.cpp +1 -1
- data/ext/apache2/Configuration.cpp +7 -1
- data/ext/apache2/Configuration.hpp +4 -0
- data/ext/apache2/Hooks.cpp +2 -2
- data/ext/common/AgentsStarter.cpp +2 -2
- data/ext/common/AgentsStarter.h +1 -1
- data/ext/common/AgentsStarter.hpp +2 -2
- data/ext/common/ApplicationPool2/DirectSpawner.h +4 -8
- data/ext/common/ApplicationPool2/Group.h +17 -11
- data/ext/common/ApplicationPool2/Implementation.cpp +39 -11
- data/ext/common/ApplicationPool2/Pool.h +23 -4
- data/ext/common/ApplicationPool2/Process.h +30 -11
- data/ext/common/ApplicationPool2/SmartSpawner.h +3 -1
- data/ext/common/Constants.h +1 -1
- data/ext/common/EventedBufferedInput.h +4 -0
- data/ext/common/Utils.cpp +21 -3
- data/ext/common/Utils.h +8 -1
- data/ext/common/Utils/HttpHeaderBufferer.h +1 -1
- data/ext/common/Utils/IOUtils.cpp +5 -4
- data/ext/common/Utils/IOUtils.h +32 -14
- data/ext/common/Utils/MessagePassing.h +2 -2
- data/ext/common/Utils/ProcessMetricsCollector.h +47 -15
- data/ext/common/Utils/ScopeGuard.h +20 -3
- data/ext/common/Utils/StrIntUtils.h +14 -5
- data/ext/common/agents/Base.cpp +161 -50
- data/ext/common/agents/HelperAgent/AgentOptions.h +2 -2
- data/ext/common/agents/HelperAgent/Main.cpp +1 -0
- data/ext/common/agents/HelperAgent/RequestHandler.h +166 -52
- data/ext/common/agents/LoggingAgent/Main.cpp +1 -1
- data/ext/common/agents/Watchdog/Main.cpp +2 -2
- data/ext/nginx/Configuration.c +31 -4
- data/ext/nginx/Configuration.h +1 -0
- data/ext/nginx/ContentHandler.c +148 -34
- data/ext/nginx/ngx_http_passenger_module.c +4 -1
- data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
- data/ext/oxt/macros.hpp +30 -8
- data/lib/phusion_passenger.rb +2 -2
- data/lib/phusion_passenger/classic_rails/thread_handler_extension.rb +1 -1
- data/lib/phusion_passenger/native_support.rb +19 -1
- data/lib/phusion_passenger/platform_info/compiler.rb +6 -0
- data/lib/phusion_passenger/platform_info/ruby.rb +54 -5
- data/lib/phusion_passenger/preloader_shared_helpers.rb +8 -1
- data/lib/phusion_passenger/rack/out_of_band_gc.rb +3 -1
- data/lib/phusion_passenger/rack/thread_handler_extension.rb +32 -5
- data/lib/phusion_passenger/request_handler/thread_handler.rb +28 -8
- data/lib/phusion_passenger/ruby_core_enhancements.rb +9 -1
- data/lib/phusion_passenger/standalone/runtime_installer.rb +1 -0
- data/lib/phusion_passenger/utils/unseekable_socket.rb +50 -5
- data/passenger.gemspec +1 -1
- data/resources/templates/apache2/config_snippets.txt.erb +1 -1
- data/test/cxx/ApplicationPool2/PoolTest.cpp +4 -9
- data/test/cxx/RequestHandlerTest.cpp +5 -5
- data/test/ruby/classic_rails/loader_spec.rb +1 -1
- data/test/ruby/classic_rails/preloader_spec.rb +1 -1
- data/test/ruby/request_handler_spec.rb +207 -1
- data/test/ruby/shared/loader_sharedspec.rb +1 -0
- data/test/ruby/spec_helper.rb +11 -1
- data/test/stub/apache2/httpd.conf.erb +1 -1
- metadata +5 -3
- metadata.gz.asc +12 -0
@@ -252,10 +252,17 @@ public:
|
|
252
252
|
*/
|
253
253
|
DISABLED
|
254
254
|
} enabled;
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
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>
|
536
|
+
stream << "<life_status>ALIVE</life_status>";
|
530
537
|
break;
|
531
538
|
case SHUTTING_DOWN:
|
532
|
-
stream << "<life_status>
|
539
|
+
stream << "<life_status>SHUTTING_DOWN</life_status>";
|
533
540
|
break;
|
534
541
|
case SHUT_DOWN:
|
535
|
-
stream << "<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>
|
549
|
+
stream << "<enabled>ENABLED</enabled>";
|
543
550
|
break;
|
544
551
|
case DISABLING:
|
545
|
-
stream << "<enabled>
|
552
|
+
stream << "<enabled>DISABLING</enabled>";
|
546
553
|
break;
|
547
554
|
case DISABLED:
|
548
|
-
stream << "<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
|
-
|
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
|
}
|
data/ext/common/Constants.h
CHANGED
data/ext/common/Utils.cpp
CHANGED
@@ -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 &
|
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(
|
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 =
|
1057
|
+
pid = asyncFork();
|
1040
1058
|
} while (pid == -1 && errno == EINTR);
|
1041
1059
|
|
1042
1060
|
if (pid == 0) {
|
data/ext/common/Utils.h
CHANGED
@@ -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 &
|
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
|
@@ -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
|
-
|
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
|
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
|
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;
|
data/ext/common/Utils/IOUtils.h
CHANGED
@@ -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 &
|
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,
|
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,
|
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,
|
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,
|
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",
|
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,
|
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 &
|
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,
|
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
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
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
|
-
|
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;
|