passenger 5.0.9 → 5.0.10

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 (106) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/CHANGELOG +15 -0
  5. data/CONTRIBUTORS +6 -0
  6. data/README.md +1 -1
  7. data/bin/passenger-install-apache2-module +24 -11
  8. data/bin/passenger-status +29 -14
  9. data/build/agents.rb +12 -10
  10. data/build/cxx_tests.rb +30 -30
  11. data/doc/Design and Architecture.html +1 -10
  12. data/doc/Design and Architecture.txt +1 -6
  13. data/doc/Users guide Apache.html +1 -19
  14. data/doc/Users guide Apache.txt +1 -1
  15. data/doc/Users guide Nginx.html +2 -20
  16. data/doc/Users guide Nginx.txt +2 -2
  17. data/doc/users_guide_snippets/tips.txt +0 -9
  18. data/ext/common/ApplicationPool2/ApiKey.h +158 -0
  19. data/ext/common/ApplicationPool2/BasicGroupInfo.h +81 -0
  20. data/ext/common/ApplicationPool2/BasicProcessInfo.h +106 -0
  21. data/ext/common/ApplicationPool2/Common.h +5 -44
  22. data/ext/common/ApplicationPool2/Context.h +94 -0
  23. data/ext/common/ApplicationPool2/Group.h +130 -1205
  24. data/ext/common/ApplicationPool2/Group/InitializationAndShutdown.cpp +190 -0
  25. data/ext/common/ApplicationPool2/Group/InternalUtils.cpp +329 -0
  26. data/ext/common/ApplicationPool2/Group/LifetimeAndBasics.cpp +103 -0
  27. data/ext/common/ApplicationPool2/{Pool/Debug.h → Group/Miscellaneous.cpp} +40 -38
  28. data/ext/common/ApplicationPool2/Group/OutOfBandWork.cpp +323 -0
  29. data/ext/common/ApplicationPool2/Group/ProcessListManagement.cpp +606 -0
  30. data/ext/common/ApplicationPool2/Group/SessionManagement.cpp +337 -0
  31. data/ext/common/ApplicationPool2/Group/SpawningAndRestarting.cpp +478 -0
  32. data/ext/common/ApplicationPool2/Group/StateInspection.cpp +197 -0
  33. data/ext/common/ApplicationPool2/Group/Verification.cpp +159 -0
  34. data/ext/common/ApplicationPool2/Implementation.cpp +19 -1401
  35. data/ext/common/ApplicationPool2/Options.h +5 -5
  36. data/ext/common/ApplicationPool2/Pool.h +260 -815
  37. data/ext/common/ApplicationPool2/Pool/{AnalyticsCollection.h → AnalyticsCollection.cpp} +55 -56
  38. data/ext/common/ApplicationPool2/Pool/{GarbageCollection.h → GarbageCollection.cpp} +49 -49
  39. data/ext/common/ApplicationPool2/Pool/GeneralUtils.cpp +241 -0
  40. data/ext/common/ApplicationPool2/Pool/GroupUtils.cpp +276 -0
  41. data/ext/common/ApplicationPool2/Pool/InitializationAndShutdown.cpp +145 -0
  42. data/ext/common/ApplicationPool2/Pool/Miscellaneous.cpp +244 -0
  43. data/ext/common/ApplicationPool2/Pool/ProcessUtils.cpp +330 -0
  44. data/ext/common/ApplicationPool2/Pool/StateInspection.cpp +299 -0
  45. data/ext/common/ApplicationPool2/Process.h +399 -205
  46. data/ext/common/ApplicationPool2/Session.h +70 -28
  47. data/ext/common/ApplicationPool2/Socket.h +1 -0
  48. data/ext/common/Constants.h +11 -3
  49. data/ext/common/Exceptions.h +1 -1
  50. data/ext/common/Logging.cpp +9 -4
  51. data/ext/common/Logging.h +6 -0
  52. data/ext/common/ServerKit/HttpServer.h +225 -215
  53. data/ext/common/ServerKit/Server.h +57 -57
  54. data/ext/common/SpawningKit/BackgroundIOCapturer.h +160 -0
  55. data/ext/common/SpawningKit/Config.h +107 -0
  56. data/ext/common/{ApplicationPool2 → SpawningKit}/DirectSpawner.h +17 -16
  57. data/ext/common/{ApplicationPool2 → SpawningKit}/DummySpawner.h +33 -33
  58. data/ext/common/{ApplicationPool2/SpawnerFactory.h → SpawningKit/Factory.h} +17 -17
  59. data/ext/common/{ApplicationPool2/ComponentInfo.h → SpawningKit/Options.h} +8 -21
  60. data/ext/common/SpawningKit/PipeWatcher.h +148 -0
  61. data/ext/common/{ApplicationPool2/PipeWatcher.h → SpawningKit/Result.h} +15 -33
  62. data/ext/common/{ApplicationPool2 → SpawningKit}/SmartSpawner.h +52 -57
  63. data/ext/common/{ApplicationPool2 → SpawningKit}/Spawner.h +83 -371
  64. data/ext/common/SpawningKit/UserSwitchingRules.h +265 -0
  65. data/ext/common/Utils/BufferedIO.h +24 -0
  66. data/ext/common/{ApplicationPool2/SpawnObject.h → Utils/ClassUtils.h} +24 -51
  67. data/ext/common/Utils/IOUtils.cpp +70 -0
  68. data/ext/common/Utils/IOUtils.h +19 -0
  69. data/ext/common/Utils/JsonUtils.h +113 -0
  70. data/ext/common/Utils/StrIntUtils.h +29 -0
  71. data/ext/common/Utils/json.h +1 -1
  72. data/ext/common/agents/ApiServerUtils.h +941 -0
  73. data/ext/common/agents/HelperAgent/{AdminServer.h → ApiServer.h} +163 -365
  74. data/ext/common/agents/HelperAgent/Main.cpp +86 -88
  75. data/ext/common/agents/HelperAgent/OptionParser.h +9 -10
  76. data/ext/common/agents/HelperAgent/RequestHandler/BufferBody.cpp +3 -0
  77. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +2 -0
  78. data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +1 -1
  79. data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +2 -2
  80. data/ext/common/agents/LoggingAgent/ApiServer.h +279 -0
  81. data/ext/common/agents/LoggingAgent/Main.cpp +41 -51
  82. data/ext/common/agents/LoggingAgent/OptionParser.h +11 -11
  83. data/ext/common/agents/Watchdog/ApiServer.h +311 -0
  84. data/ext/common/agents/Watchdog/Main.cpp +91 -65
  85. data/helper-scripts/prespawn +2 -0
  86. data/lib/phusion_passenger.rb +1 -1
  87. data/lib/phusion_passenger/admin_tools/instance.rb +1 -1
  88. data/lib/phusion_passenger/common_library.rb +27 -14
  89. data/lib/phusion_passenger/config/{admin_command_command.rb → api_call_command.rb} +19 -16
  90. data/lib/phusion_passenger/config/detach_process_command.rb +6 -3
  91. data/lib/phusion_passenger/config/main.rb +3 -5
  92. data/lib/phusion_passenger/config/reopen_logs_command.rb +29 -7
  93. data/lib/phusion_passenger/config/restart_app_command.rb +13 -4
  94. data/lib/phusion_passenger/config/utils.rb +15 -8
  95. data/lib/phusion_passenger/constants.rb +6 -2
  96. data/lib/phusion_passenger/platform_info/apache.rb +4 -0
  97. data/lib/phusion_passenger/platform_info/apache_detector.rb +18 -3
  98. data/resources/templates/apache2/mpm_unknown.txt.erb +20 -0
  99. metadata +42 -21
  100. metadata.gz.asc +7 -7
  101. data/ext/common/ApplicationPool2/Pool/GeneralUtils.h +0 -127
  102. data/ext/common/ApplicationPool2/Pool/Inspection.h +0 -219
  103. data/ext/common/ApplicationPool2/Pool/ProcessUtils.h +0 -85
  104. data/ext/common/ApplicationPool2/SuperGroup.h +0 -706
  105. data/ext/common/agents/LoggingAgent/AdminServer.h +0 -435
  106. data/ext/common/agents/Watchdog/AdminServer.h +0 -432
@@ -28,8 +28,8 @@
28
28
  #include <string>
29
29
  #include <vector>
30
30
  #include <algorithm>
31
- #include <boost/shared_ptr.hpp>
32
- #include <boost/make_shared.hpp>
31
+ #include <boost/intrusive_ptr.hpp>
32
+ #include <boost/move/core.hpp>
33
33
  #include <boost/container/vector.hpp>
34
34
  #include <oxt/system_calls.hpp>
35
35
  #include <oxt/spin_lock.hpp>
@@ -42,12 +42,14 @@
42
42
  #include <ApplicationPool2/Common.h>
43
43
  #include <ApplicationPool2/Socket.h>
44
44
  #include <ApplicationPool2/Session.h>
45
- #include <ApplicationPool2/PipeWatcher.h>
45
+ #include <SpawningKit/PipeWatcher.h>
46
+ #include <SpawningKit/Result.h>
46
47
  #include <Constants.h>
47
48
  #include <FileDescriptor.h>
48
49
  #include <Logging.h>
49
50
  #include <Utils/SystemTime.h>
50
51
  #include <Utils/StrIntUtils.h>
52
+ #include <Utils/Lock.h>
51
53
  #include <Utils/ProcessMetricsCollector.h>
52
54
 
53
55
  namespace Passenger {
@@ -60,9 +62,9 @@ using namespace boost;
60
62
  typedef boost::container::vector<ProcessPtr> ProcessList;
61
63
 
62
64
  /**
63
- * Represents an application process, as spawned by a Spawner. Every Process has
64
- * a PID, an admin socket and a list of sockets on which it listens for
65
- * connections. A Process is usually contained inside a Group.
65
+ * Represents an application process, as spawned by a SpawningKit::Spawner. Every
66
+ * Process has a PID, an admin socket and a list of sockets on which it listens for
67
+ * connections. A Process object is contained inside a Group.
66
68
  *
67
69
  * The admin socket, an anonymous Unix domain socket, is mapped to the process's
68
70
  * STDIN and STDOUT and has two functions.
@@ -96,14 +98,86 @@ typedef boost::container::vector<ProcessPtr> ProcessList;
96
98
  * This means that a Group outlives all its Processes, a Process outlives all
97
99
  * its Sessions, and a Process also outlives the OS process.
98
100
  */
99
- class Process: public boost::enable_shared_from_this<Process> {
101
+ class Process {
100
102
  public:
101
103
  static const unsigned int MAX_SESSION_SOCKETS = 3;
102
- static const unsigned int GUPID_MAX_SIZE = 20;
103
104
 
104
- // Actually private, but marked public so that unit tests can access the fields.
105
- public:
106
- friend class Group;
105
+ private:
106
+ /*************************************************************
107
+ * Read-only fields, set once during initialization and never
108
+ * written to again. Reading is thread-safe.
109
+ *************************************************************/
110
+
111
+ BasicProcessInfo info;
112
+ DynamicBuffer stringBuffer;
113
+ SocketList sockets;
114
+
115
+ /**
116
+ * The maximum amount of concurrent sessions this process can handle.
117
+ * 0 means unlimited. Automatically inferred from the sockets.
118
+ */
119
+ int concurrency;
120
+
121
+ /**
122
+ * A subset of 'sockets': all sockets that speak the
123
+ * "session" or "http_session" protocol.
124
+ */
125
+ unsigned int sessionSocketCount;
126
+ Socket *sessionSockets[MAX_SESSION_SOCKETS];
127
+
128
+ /** Admin socket. See Process class description. */
129
+ FileDescriptor adminSocket;
130
+
131
+ /**
132
+ * Pipe on which this process outputs errors. Mapped to the process's STDERR.
133
+ * Only Processes spawned by DirectSpawner have this set.
134
+ * SmartSpawner-spawned Processes use the same STDERR as their parent preloader processes.
135
+ */
136
+ FileDescriptor errorPipe;
137
+
138
+ /**
139
+ * The code revision of the application, inferred through various means.
140
+ * See Spawner::prepareSpawn() to learn how this is determined.
141
+ * May be an empty string if no code revision has been inferred.
142
+ */
143
+ StaticString codeRevision;
144
+
145
+ /**
146
+ * Time at which the Spawner that created this process was created.
147
+ * Microseconds resolution.
148
+ */
149
+ unsigned long long spawnerCreationTime;
150
+
151
+ /** Time at which we started spawning this process. Microseconds resolution. */
152
+ unsigned long long spawnStartTime;
153
+
154
+ /**
155
+ * Time at which we finished spawning this process, i.e. when this
156
+ * process was finished initializing. Microseconds resolution.
157
+ */
158
+ unsigned long long spawnEndTime;
159
+
160
+ /**
161
+ * If true, then indicates that this Process does not refer to a real OS
162
+ * process. The sockets in the socket list are fake and need not be deleted,
163
+ * the admin socket need not be closed, etc.
164
+ */
165
+ bool dummy;
166
+
167
+ /**
168
+ * Whether it is required that triggerShutdown() and cleanup() must be called
169
+ * before destroying this Process. Normally true, except for dummy Process
170
+ * objects created by Pool::asyncGet() with options.noop == true, because those
171
+ * processes are never added to Group.enabledProcesses.
172
+ */
173
+ bool requiresShutdown;
174
+
175
+
176
+ /*************************************************************
177
+ * Read-write fields.
178
+ *************************************************************/
179
+
180
+ mutable boost::atomic<int> refcount;
107
181
 
108
182
  /** A mutex to protect access to `lifeStatus`. */
109
183
  mutable oxt::spin_lock lifetimeSyncher;
@@ -111,42 +185,100 @@ public:
111
185
  /** The index inside the associated Group's process list. */
112
186
  unsigned int index;
113
187
 
114
- /** Group inside the Pool that this Process belongs to.
115
- * Should never be NULL because a Group should outlive all of its Processes.
116
- * Read-only; only set once during initialization.
117
- */
118
- Group *group;
119
188
 
120
- /** A subset of 'sockets': all sockets that speak the
121
- * "session" or "http_session" protocol. */
122
- Socket *sessionSockets[MAX_SESSION_SOCKETS];
189
+ /*************************************************************
190
+ * Methods
191
+ *************************************************************/
123
192
 
124
- static bool
125
- isZombie(pid_t pid) {
126
- string filename = "/proc/" + toString(pid) + "/status";
127
- FILE *f = fopen(filename.c_str(), "r");
128
- if (f == NULL) {
129
- // Don't know.
130
- return false;
193
+ /****** Initialization and destruction ******/
194
+
195
+ struct InitializationLog {
196
+ struct String {
197
+ unsigned int offset;
198
+ unsigned int size;
199
+ };
200
+
201
+ struct SocketStringOffsets {
202
+ String name;
203
+ String address;
204
+ String protocol;
205
+ };
206
+
207
+ vector<SocketStringOffsets> socketStringOffsets;
208
+ String codeRevision;
209
+ };
210
+
211
+ void appendJsonFieldToBuffer(std::string &buffer, const Json::Value &json,
212
+ const char *key, InitializationLog::String &str) const
213
+ {
214
+ StaticString value = getJsonStaticStringField(json, key);
215
+ str.offset = buffer.size();
216
+ str.size = value.size();
217
+ buffer.append(value.data(), value.size());
218
+ buffer.append(1, '\0');
219
+ }
220
+
221
+ void initializeSocketsAndStringFields(const Json::Value &json) {
222
+ InitializationLog log;
223
+ string buffer;
224
+
225
+
226
+ // Step 1: append strings to temporary buffer and take note of their
227
+ // offsets within the temporary buffer.
228
+
229
+ Json::Value sockets = getJsonField(json, "sockets");
230
+ // The const_cast here works around a jsoncpp bug.
231
+ Json::Value::const_iterator it = const_cast<const Json::Value &>(sockets).begin();
232
+ Json::Value::const_iterator end = const_cast<const Json::Value &>(sockets).end();
233
+ buffer.reserve(1024);
234
+
235
+ for (it = sockets.begin(); it != end; it++) {
236
+ const Json::Value &socket = *it;
237
+ InitializationLog::SocketStringOffsets offsets;
238
+
239
+ appendJsonFieldToBuffer(buffer, socket, "name", offsets.name);
240
+ appendJsonFieldToBuffer(buffer, socket, "address", offsets.address);
241
+ appendJsonFieldToBuffer(buffer, socket, "protocol", offsets.protocol);
242
+
243
+ log.socketStringOffsets.push_back(offsets);
131
244
  }
132
245
 
133
- bool result = false;
134
- while (!feof(f)) {
135
- char buf[512];
136
- const char *line;
246
+ if (json.isMember("code_revision")) {
247
+ appendJsonFieldToBuffer(buffer, json, "code_revision", log.codeRevision);
248
+ }
137
249
 
138
- line = fgets(buf, sizeof(buf), f);
139
- if (line == NULL) {
140
- break;
141
- }
142
- if (strcmp(line, "State: Z (zombie)\n") == 0) {
143
- // Is a zombie.
144
- result = true;
145
- break;
146
- }
250
+
251
+ // Step 2: allocate the real buffer.
252
+
253
+ this->stringBuffer = DynamicBuffer(buffer.size());
254
+ memcpy(this->stringBuffer.data, buffer.data(), buffer.size());
255
+
256
+
257
+ // Step 3: initialize the string fields and point them to
258
+ // addresses within the real buffer.
259
+
260
+ unsigned int i;
261
+ const char *base = this->stringBuffer.data;
262
+
263
+ it = const_cast<const Json::Value &>(sockets).begin();
264
+ for (i = 0; it != end; it++, i++) {
265
+ const Json::Value &socket = *it;
266
+ this->sockets.add(
267
+ info.pid,
268
+ StaticString(base + log.socketStringOffsets[i].name.offset,
269
+ log.socketStringOffsets[i].name.size),
270
+ StaticString(base + log.socketStringOffsets[i].address.offset,
271
+ log.socketStringOffsets[i].address.size),
272
+ StaticString(base + log.socketStringOffsets[i].protocol.offset,
273
+ log.socketStringOffsets[i].protocol.size),
274
+ getJsonIntField(socket, "concurrency")
275
+ );
276
+ }
277
+
278
+ if (json.isMember("code_revision")) {
279
+ codeRevision = StaticString(base + log.codeRevision.offset,
280
+ log.codeRevision.size);
147
281
  }
148
- fclose(f);
149
- return result;
150
282
  }
151
283
 
152
284
  void indexSessionSockets() {
@@ -183,60 +315,49 @@ public:
183
315
  }
184
316
  }
185
317
 
186
- public:
187
- /*************************************************************
188
- * Read-only fields, set once during initialization and never
189
- * written to again. Reading is thread-safe.
190
- *************************************************************/
318
+ void destroySelf() const {
319
+ this->~Process();
320
+ LockGuard l(getContext()->getMmSyncher());
321
+ getContext()->getProcessObjectPool().free(const_cast<Process *>(this));
322
+ }
191
323
 
192
- /** Process PID. */
193
- pid_t pid;
194
- /** An ID that uniquely identifies this Process in the Group, for
195
- * use in implementing sticky sessions. Set by Group::attach(). */
196
- unsigned int stickySessionId;
197
- /** UUID for this process, randomly generated and extremely unlikely to ever
198
- * appear again in this universe. */
199
- char gupid[GUPID_MAX_SIZE];
200
- unsigned int gupidSize;
201
- /** Admin socket, see class description. */
202
- FileDescriptor adminSocket;
203
- /** The sockets that this Process listens on for connections. */
204
- SocketList sockets;
205
- /** The code revision of the application, inferred through various means.
206
- * See Spawner::prepareSpawn() to learn how this is determined.
207
- * May be an empty string.
208
- */
209
- StaticString codeRevision;
210
- /** Time at which the Spawner that created this process was created.
211
- * Microseconds resolution. */
212
- unsigned long long spawnerCreationTime;
213
- /** Time at which we started spawning this process. Microseconds resolution. */
214
- unsigned long long spawnStartTime;
215
- /** The maximum amount of concurrent sessions this process can handle.
216
- * 0 means unlimited. */
217
- int concurrency;
218
- /** If true, then indicates that this Process does not refer to a real OS
219
- * process. The sockets in the socket list are fake and need not be deleted,
220
- * the admin socket need not be closed, etc.
221
- */
222
- bool dummy;
223
- /** Whether it is required that triggerShutdown() and cleanup() must be called
224
- * before destroying this Process. Normally true, except for dummy Process
225
- * objects created by Pool::asyncGet() with options.noop == true, because those
226
- * processes are never added to Group.enabledProcesses.
227
- */
228
- bool requiresShutdown;
229
324
 
325
+ /****** Miscellaneous ******/
326
+
327
+ static bool isZombie(pid_t pid) {
328
+ string filename = "/proc/" + toString(pid) + "/status";
329
+ FILE *f = fopen(filename.c_str(), "r");
330
+ if (f == NULL) {
331
+ // Don't know.
332
+ return false;
333
+ }
334
+
335
+ bool result = false;
336
+ while (!feof(f)) {
337
+ char buf[512];
338
+ const char *line;
339
+
340
+ line = fgets(buf, sizeof(buf), f);
341
+ if (line == NULL) {
342
+ break;
343
+ }
344
+ if (strcmp(line, "State: Z (zombie)\n") == 0) {
345
+ // Is a zombie.
346
+ result = true;
347
+ break;
348
+ }
349
+ }
350
+ fclose(f);
351
+ return result;
352
+ }
353
+
354
+ public:
230
355
  /*************************************************************
231
356
  * Information used by Pool. Do not write to these from
232
357
  * outside the Pool. If you read these make sure the Pool
233
358
  * isn't concurrently modifying.
234
359
  *************************************************************/
235
360
 
236
- /** Time at which we finished spawning this process, i.e. when this
237
- * process was finished initializing. Microseconds resolution.
238
- */
239
- unsigned long long spawnEndTime;
240
361
  /** Last time when a session was opened for this Process. */
241
362
  unsigned long long lastUsed;
242
363
  /** Number of sessions currently open.
@@ -260,7 +381,7 @@ public:
260
381
  * this object is no longer usable.
261
382
  */
262
383
  DEAD
263
- } lifeStatus: 2;
384
+ } lifeStatus;
264
385
  enum EnabledStatus {
265
386
  /** Up and operational. */
266
387
  ENABLED,
@@ -281,7 +402,7 @@ public:
281
402
  * eligible for new requests.
282
403
  */
283
404
  DETACHED
284
- } enabled: 2;
405
+ } enabled;
285
406
  enum OobwStatus {
286
407
  /** Process is not using out-of-band work. */
287
408
  OOBW_NOT_ACTIVE,
@@ -292,41 +413,27 @@ public:
292
413
  * sessions have ended and the process has been disabled before the
293
414
  * out-of-band work can be performed. */
294
415
  OOBW_IN_PROGRESS,
295
- } oobwStatus: 2;
416
+ } oobwStatus;
296
417
  /** Caches whether or not the OS process still exists. */
297
418
  mutable bool m_osProcessExists: 1;
298
419
  bool longRunningConnectionsAborted: 1;
299
- /** Number of items in `sessionSockets`. Private field, but put here
300
- * for alignment optimization.
301
- */
302
- unsigned int sessionSocketCount: 8;
303
420
  /** Time at which shutdown began. */
304
421
  time_t shutdownStartTime;
305
422
  /** Collected by Pool::collectAnalytics(). */
306
423
  ProcessMetrics metrics;
307
424
 
308
- Process(pid_t _pid,
309
- const StaticString &_gupid,
310
- const FileDescriptor &_adminSocket,
311
- /** Pipe on which this process outputs errors. Mapped to the process's STDERR.
312
- * Only Processes spawned by DirectSpawner have this set.
313
- * SmartSpawner-spawned Processes use the same STDERR as their parent preloader processes.
314
- */
315
- const FileDescriptor &_errorPipe,
316
- const SocketList &_sockets,
317
- unsigned long long _spawnerCreationTime,
318
- unsigned long long _spawnStartTime)
319
- : index(-1),
320
- group(NULL),
321
- pid(_pid),
322
- stickySessionId(0),
323
- adminSocket(_adminSocket),
324
- sockets(_sockets),
325
- spawnerCreationTime(_spawnerCreationTime),
326
- spawnStartTime(_spawnStartTime),
327
- concurrency(0),
328
- dummy(false),
329
- requiresShutdown(true),
425
+
426
+ Process(const BasicGroupInfo *groupInfo, const Json::Value &json)
427
+ : info(this, groupInfo, json),
428
+ sessionSocketCount(0),
429
+ spawnerCreationTime(getJsonUint64Field(json, "spawner_creation_time")),
430
+ spawnStartTime(getJsonUint64Field(json, "spawn_start_time")),
431
+ spawnEndTime(SystemTime::getUsec()),
432
+ dummy(json["type"] == "dummy"),
433
+ requiresShutdown(false),
434
+ refcount(1),
435
+ index(-1),
436
+ lastUsed(spawnEndTime),
330
437
  sessions(0),
331
438
  processed(0),
332
439
  lifeStatus(ALIVE),
@@ -334,39 +441,65 @@ public:
334
441
  oobwStatus(OOBW_NOT_ACTIVE),
335
442
  m_osProcessExists(true),
336
443
  longRunningConnectionsAborted(false),
337
- sessionSocketCount(0),
338
444
  shutdownStartTime(0)
339
445
  {
340
- assert(_gupid.size() <= GUPID_MAX_SIZE);
446
+ initializeSocketsAndStringFields(json);
447
+ indexSessionSockets();
341
448
 
342
- if (_adminSocket != -1) {
343
- PipeWatcherPtr watcher = boost::make_shared<PipeWatcher>(_adminSocket,
344
- "stdout", pid);
345
- watcher->initialize();
346
- watcher->start();
347
- }
348
- if (_errorPipe != -1) {
349
- PipeWatcherPtr watcher = boost::make_shared<PipeWatcher>(_errorPipe,
350
- "stderr", pid);
351
- watcher->initialize();
352
- watcher->start();
353
- }
449
+ const SpawningKit::Result *skResult = dynamic_cast<const SpawningKit::Result *>(&json);
450
+ if (skResult != NULL) {
451
+ adminSocket = skResult->adminSocket;
452
+ errorPipe = skResult->errorPipe;
354
453
 
355
- indexSessionSockets();
454
+ if (adminSocket != -1) {
455
+ SpawningKit::PipeWatcherPtr watcher = boost::make_shared<SpawningKit::PipeWatcher>(
456
+ getContext()->getSpawningKitConfig(), adminSocket, "stdout", info.pid);
457
+ watcher->initialize();
458
+ watcher->start();
459
+ }
356
460
 
357
- lastUsed = SystemTime::getUsec();
358
- spawnEndTime = lastUsed;
359
- gupidSize = _gupid.size();
360
- memcpy(gupid, _gupid.data(), _gupid.size());
461
+ if (errorPipe != -1) {
462
+ SpawningKit::PipeWatcherPtr watcher = boost::make_shared<SpawningKit::PipeWatcher>(
463
+ getContext()->getSpawningKitConfig(), errorPipe, "stderr", info.pid);
464
+ watcher->initialize();
465
+ watcher->start();
466
+ }
467
+ }
361
468
  }
362
469
 
363
470
  ~Process() {
364
- if (OXT_UNLIKELY(!isDead() && requiresShutdown)) {
471
+ if (OXT_UNLIKELY(requiresShutdown && !isDead())) {
365
472
  P_BUG("You must call Process::triggerShutdown() and Process::cleanup() before actually "
366
473
  "destroying the Process object.");
367
474
  }
368
475
  }
369
476
 
477
+ void initializeStickySessionId(unsigned int value) {
478
+ info.stickySessionId = value;
479
+ }
480
+
481
+ void shutdownNotRequired() {
482
+ requiresShutdown = false;
483
+ }
484
+
485
+
486
+ /****** Memory and life time management ******/
487
+
488
+ void ref() const {
489
+ refcount.fetch_add(1, boost::memory_order_relaxed);
490
+ }
491
+
492
+ void unref() const {
493
+ if (refcount.fetch_sub(1, boost::memory_order_release) == 1) {
494
+ boost::atomic_thread_fence(boost::memory_order_acquire);
495
+ destroySelf();
496
+ }
497
+ }
498
+
499
+ ProcessPtr shared_from_this() {
500
+ return ProcessPtr(this);
501
+ }
502
+
370
503
  static void forceTriggerShutdownAndCleanup(ProcessPtr process) {
371
504
  if (process != NULL) {
372
505
  process->triggerShutdown();
@@ -377,35 +510,6 @@ public:
377
510
  }
378
511
  }
379
512
 
380
- /**
381
- * Thread-safe.
382
- * @pre getLifeState() != SHUT_DOWN
383
- * @post result != NULL
384
- */
385
- Group *getGroup() const {
386
- assert(!isDead());
387
- return group;
388
- }
389
-
390
- void setGroup(Group *group) {
391
- assert(this->group == NULL || this->group == group);
392
- this->group = group;
393
- }
394
-
395
- /**
396
- * Thread-safe.
397
- * @pre getLifeState() != DEAD
398
- * @post result != NULL
399
- */
400
- Pool *getPool() const;
401
-
402
- /**
403
- * Thread-safe.
404
- * @pre getLifeState() != DEAD
405
- * @post result != NULL
406
- */
407
- SuperGroup *getSuperGroup() const;
408
-
409
513
  // Thread-safe.
410
514
  bool isAlive() const {
411
515
  oxt::spin_lock::scoped_lock lock(lifetimeSyncher);
@@ -430,29 +534,6 @@ public:
430
534
  return lifeStatus;
431
535
  }
432
536
 
433
- // Thread-safe.
434
- StaticString getGroupSecret() const;
435
-
436
- Socket *findSessionSocketWithLowestBusyness() const {
437
- if (OXT_UNLIKELY(sessionSocketCount == 0)) {
438
- return NULL;
439
- } else if (sessionSocketCount == 1) {
440
- return sessionSockets[0];
441
- } else {
442
- int leastBusySessionSocketIndex = 0;
443
- int lowestBusyness = sessionSockets[0]->busyness();
444
-
445
- for (unsigned i = 1; i < sessionSocketCount; i++) {
446
- if (sessionSockets[i]->busyness() < lowestBusyness) {
447
- leastBusySessionSocketIndex = i;
448
- lowestBusyness = sessionSockets[i]->busyness();
449
- }
450
- }
451
-
452
- return sessionSockets[leastBusySessionSocketIndex];
453
- }
454
- }
455
-
456
537
  bool canTriggerShutdown() const {
457
538
  return getLifeStatus() == ALIVE && sessions == 0;
458
539
  }
@@ -498,6 +579,85 @@ public:
498
579
  lifeStatus = DEAD;
499
580
  }
500
581
 
582
+
583
+ /****** Basic information queries ******/
584
+
585
+ OXT_FORCE_INLINE
586
+ Context *getContext() const {
587
+ return info.groupInfo->context;
588
+ }
589
+
590
+ Group *getGroup() const {
591
+ return info.groupInfo->group;
592
+ }
593
+
594
+ StaticString getGroupName() const {
595
+ return info.groupInfo->name;
596
+ }
597
+
598
+ const ApiKey &getApiKey() const {
599
+ return info.groupInfo->apiKey;
600
+ }
601
+
602
+ const BasicProcessInfo &getInfo() const {
603
+ return info;
604
+ }
605
+
606
+ pid_t getPid() const {
607
+ return info.pid;
608
+ }
609
+
610
+ StaticString getGupid() const {
611
+ return StaticString(info.gupid, info.gupidSize);
612
+ }
613
+
614
+ unsigned int getStickySessionId() const {
615
+ return info.stickySessionId;
616
+ }
617
+
618
+ unsigned long long getSpawnerCreationTime() const {
619
+ return spawnerCreationTime;
620
+ }
621
+
622
+ bool isDummy() const {
623
+ return dummy;
624
+ }
625
+
626
+
627
+ /****** Miscellaneous ******/
628
+
629
+ unsigned int getIndex() const {
630
+ return index;
631
+ }
632
+
633
+ void setIndex(unsigned int i) {
634
+ index = i;
635
+ }
636
+
637
+ const SocketList &getSockets() const {
638
+ return sockets;
639
+ }
640
+
641
+ Socket *findSessionSocketWithLowestBusyness() const {
642
+ if (OXT_UNLIKELY(sessionSocketCount == 0)) {
643
+ return NULL;
644
+ } else if (sessionSocketCount == 1) {
645
+ return sessionSockets[0];
646
+ } else {
647
+ int leastBusySessionSocketIndex = 0;
648
+ int lowestBusyness = sessionSockets[0]->busyness();
649
+
650
+ for (unsigned i = 1; i < sessionSocketCount; i++) {
651
+ if (sessionSockets[i]->busyness() < lowestBusyness) {
652
+ leastBusySessionSocketIndex = i;
653
+ lowestBusyness = sessionSockets[i]->busyness();
654
+ }
655
+ }
656
+
657
+ return sessionSockets[leastBusySessionSocketIndex];
658
+ }
659
+ }
660
+
501
661
  /** Checks whether the OS process exists.
502
662
  * Once it has been detected that it doesn't, that event is remembered
503
663
  * so that we don't accidentally ping any new processes that have the
@@ -505,13 +665,13 @@ public:
505
665
  */
506
666
  bool osProcessExists() const {
507
667
  if (!dummy && m_osProcessExists) {
508
- if (syscalls::kill(pid, 0) == 0) {
668
+ if (syscalls::kill(getPid(), 0) == 0) {
509
669
  /* On some environments, e.g. Heroku, the init process does
510
670
  * not properly reap adopted zombie processes, which can interfere
511
671
  * with our process existance check. To work around this, we
512
672
  * explicitly check whether or not the process has become a zombie.
513
673
  */
514
- m_osProcessExists = !isZombie(pid);
674
+ m_osProcessExists = !isZombie(getPid());
515
675
  } else {
516
676
  m_osProcessExists = errno != ESRCH;
517
677
  }
@@ -524,7 +684,7 @@ public:
524
684
  /** Kill the OS process with the given signal. */
525
685
  int kill(int signo) {
526
686
  if (osProcessExists()) {
527
- return syscalls::kill(pid, signo);
687
+ return syscalls::kill(getPid(), signo);
528
688
  } else {
529
689
  return 0;
530
690
  }
@@ -594,7 +754,35 @@ public:
594
754
  }
595
755
  }
596
756
 
597
- SessionPtr createSessionObject(Socket *socket);
757
+ SessionPtr createSessionObject(Socket *socket) {
758
+ struct Guard {
759
+ Context *context;
760
+ Session *session;
761
+
762
+ Guard(Context *c, Session *s)
763
+ : context(c),
764
+ session(s)
765
+ { }
766
+
767
+ ~Guard() {
768
+ if (session != NULL) {
769
+ context->getSessionObjectPool().free(session);
770
+ }
771
+ }
772
+
773
+ void clear() {
774
+ session = NULL;
775
+ }
776
+ };
777
+
778
+ Context *context = getContext();
779
+ LockGuard l(context->getMmSyncher());
780
+ Session *session = context->getSessionObjectPool().malloc();
781
+ Guard guard(context, session);
782
+ session = new (session) Session(context, &info, socket);
783
+ guard.clear();
784
+ return SessionPtr(session, false);
785
+ }
598
786
 
599
787
  void sessionClosed(Session *session) {
600
788
  Socket *socket = session->getSocket();
@@ -615,23 +803,18 @@ public:
615
803
  return distanceOfTimeInWords(spawnEndTime / 1000000);
616
804
  }
617
805
 
618
- string inspect() const;
619
-
620
- void recreateStrings(psg_pool_t *pool) {
621
- SocketList::iterator it;
622
-
623
- recreateString(pool, codeRevision);
624
-
625
- for (it = sockets.begin(); it != sockets.end(); it++) {
626
- it->recreateStrings(pool);
627
- }
806
+ string inspect() const {
807
+ assert(getLifeStatus() != DEAD);
808
+ stringstream result;
809
+ result << "(pid=" << getPid() << ", group=" << getGroupName() << ")";
810
+ return result.str();
628
811
  }
629
812
 
630
813
  template<typename Stream>
631
814
  void inspectXml(Stream &stream, bool includeSockets = true) const {
632
- stream << "<pid>" << pid << "</pid>";
633
- stream << "<sticky_session_id>" << stickySessionId << "</sticky_session_id>";
634
- stream << "<gupid>" << StaticString(gupid, gupidSize) << "</gupid>";
815
+ stream << "<pid>" << getPid() << "</pid>";
816
+ stream << "<sticky_session_id>" << getStickySessionId() << "</sticky_session_id>";
817
+ stream << "<gupid>" << getGupid() << "</gupid>";
635
818
  stream << "<concurrency>" << concurrency << "</concurrency>";
636
819
  stream << "<sessions>" << sessions << "</sessions>";
637
820
  stream << "<busyness>" << busyness() << "</busyness>";
@@ -706,6 +889,17 @@ public:
706
889
  };
707
890
 
708
891
 
892
+ inline void
893
+ intrusive_ptr_add_ref(const Process *process) {
894
+ process->ref();
895
+ }
896
+
897
+ inline void
898
+ intrusive_ptr_release(const Process *process) {
899
+ process->unref();
900
+ }
901
+
902
+
709
903
  } // namespace ApplicationPool2
710
904
  } // namespace Passenger
711
905