passenger 4.0.17 → 4.0.18

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 (41) hide show
  1. data.tar.gz.asc +7 -7
  2. data/NEWS +21 -0
  3. data/bin/passenger +2 -0
  4. data/bin/passenger-config +2 -0
  5. data/bin/passenger-install-apache2-module +2 -0
  6. data/bin/passenger-install-nginx-module +2 -0
  7. data/bin/passenger-memory-stats +2 -0
  8. data/bin/passenger-status +2 -0
  9. data/build/debian.rb +3 -1
  10. data/build/packaging.rb +42 -2
  11. data/build/preprocessor.rb +7 -0
  12. data/debian.template/control.template +9 -3
  13. data/debian.template/rules.template +2 -1
  14. data/doc/Users guide Apache.idmap.txt +5 -1
  15. data/doc/Users guide Nginx.idmap.txt +5 -1
  16. data/doc/users_guide_snippets/installation.txt +71 -64
  17. data/ext/apache2/Hooks.cpp +17 -1
  18. data/ext/common/ApplicationPool2/Process.h +38 -2
  19. data/ext/common/Constants.h +5 -1
  20. data/ext/common/EventedClient.h +22 -1
  21. data/ext/common/EventedMessageServer.h +15 -0
  22. data/ext/common/UnionStation.h +2 -2
  23. data/ext/common/agents/HelperAgent/RequestHandler.h +24 -9
  24. data/ext/common/agents/LoggingAgent/LoggingServer.h +24 -11
  25. data/ext/oxt/backtrace.hpp +4 -6
  26. data/ext/oxt/detail/backtrace_disabled.hpp +1 -0
  27. data/ext/oxt/detail/backtrace_enabled.hpp +10 -4
  28. data/ext/oxt/detail/context.hpp +1 -0
  29. data/ext/oxt/implementation.cpp +21 -7
  30. data/helper-scripts/download_binaries/extconf.rb +1 -1
  31. data/lib/phusion_passenger.rb +1 -1
  32. data/lib/phusion_passenger/analytics_logger.rb +3 -3
  33. data/lib/phusion_passenger/constants.rb +2 -0
  34. data/lib/phusion_passenger/packaging.rb +16 -0
  35. data/lib/phusion_passenger/standalone/command.rb +3 -0
  36. data/lib/phusion_passenger/standalone/start_command.rb +40 -2
  37. data/resources/templates/standalone/config.erb +3 -0
  38. data/test/cxx/UnionStationTest.cpp +11 -11
  39. data/test/ruby/analytics_logger_spec.rb +1 -1
  40. metadata +2 -2
  41. metadata.gz.asc +7 -7
@@ -45,7 +45,10 @@
45
45
  #include <cstdio>
46
46
  #include <unistd.h>
47
47
 
48
+ #include <oxt/initialize.hpp>
48
49
  #include <oxt/macros.hpp>
50
+ #include <oxt/backtrace.hpp>
51
+ #include <oxt/detail/context.hpp>
49
52
  #include "Hooks.h"
50
53
  #include "Bucket.h"
51
54
  #include "Configuration.hpp"
@@ -480,6 +483,17 @@ private:
480
483
  int handleRequest(request_rec *r) {
481
484
  /********** Step 1: preparation work **********/
482
485
 
486
+ /* Initialize OXT backtrace support if not already done for this thread */
487
+ if (oxt::get_thread_local_context() == NULL) {
488
+ /* There is no need to cleanup the context. Apache uses a static
489
+ * number of threads per process.
490
+ */
491
+ thread_local_context_ptr context = thread_local_context::make_shared_ptr();
492
+ unsigned long tid = (unsigned long) pthread_self();
493
+ context->thread_name = "Worker " + integerToHex(tid);
494
+ oxt::set_thread_local_context(context);
495
+ }
496
+
483
497
  /* Check whether an error occured in prepareRequest() that should be reported
484
498
  * to the browser.
485
499
  */
@@ -1583,7 +1597,9 @@ init_module(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *
1583
1597
  * universal, i.e. it works for some people but not for others. So we got rid of the
1584
1598
  * hacks, and now we always initialize in the post_config hook.
1585
1599
  */
1586
- if (hooks != NULL) {
1600
+ if (hooks == NULL) {
1601
+ oxt::initialize();
1602
+ } else {
1587
1603
  P_DEBUG("Restarting Phusion Passenger....");
1588
1604
  delete hooks;
1589
1605
  hooks = NULL;
@@ -147,6 +147,34 @@ private:
147
147
  /** The handle inside the associated Group's process priority queue. */
148
148
  PriorityQueue<Process>::Handle pqHandle;
149
149
 
150
+ static bool
151
+ isZombie(pid_t pid) {
152
+ string filename = "/proc/" + toString(pid) + "/status";
153
+ FILE *f = fopen(filename.c_str(), "r");
154
+ if (f == NULL) {
155
+ // Don't know.
156
+ return false;
157
+ }
158
+
159
+ bool result = false;
160
+ while (!feof(f)) {
161
+ char buf[512];
162
+ const char *line;
163
+
164
+ line = fgets(buf, sizeof(buf), f);
165
+ if (line == NULL) {
166
+ break;
167
+ }
168
+ if (strcmp(line, "State: Z (zombie)\n") == 0) {
169
+ // Is a zombie.
170
+ result = true;
171
+ break;
172
+ }
173
+ }
174
+ fclose(f);
175
+ return result;
176
+ }
177
+
150
178
  void indexSessionSockets() {
151
179
  SocketList::iterator it;
152
180
  concurrency = 0;
@@ -458,8 +486,16 @@ public:
458
486
  */
459
487
  bool osProcessExists() const {
460
488
  if (!dummy && m_osProcessExists) {
461
- // Once we detect that a process is gone.
462
- m_osProcessExists = syscalls::kill(pid, 0) == 0 || errno != ESRCH;
489
+ if (syscalls::kill(pid, 0) == 0) {
490
+ /* On some environments, e.g. Heroku, the init process does
491
+ * not properly reap adopted zombie processes, which can interfere
492
+ * with our process existance check. To work around this, we
493
+ * explicitly check whether or not the process has become a zombie.
494
+ */
495
+ m_osProcessExists = !isZombie(pid);
496
+ } else {
497
+ m_osProcessExists = errno != ESRCH;
498
+ }
463
499
  return m_osProcessExists;
464
500
  } else {
465
501
  return false;
@@ -42,6 +42,8 @@
42
42
 
43
43
  #define DEFAULT_ANALYTICS_LOG_USER "nobody"
44
44
 
45
+ #define DEFAULT_CONCURRENCY_MODEL "process"
46
+
45
47
  #define DEFAULT_LOG_LEVEL 0
46
48
 
47
49
  #define DEFAULT_MAX_INSTANCES_PER_APP 0
@@ -56,6 +58,8 @@
56
58
 
57
59
  #define DEFAULT_START_TIMEOUT 90000
58
60
 
61
+ #define DEFAULT_THREAD_COUNT 1
62
+
59
63
  #define DEFAULT_UNION_STATION_GATEWAY_ADDRESS "gateway.unionstationapp.com"
60
64
 
61
65
  #define DEFAULT_UNION_STATION_GATEWAY_PORT 443
@@ -68,7 +72,7 @@
68
72
 
69
73
  #define MESSAGE_SERVER_MAX_USERNAME_SIZE 100
70
74
 
71
- #define PASSENGER_VERSION "4.0.17"
75
+ #define PASSENGER_VERSION "4.0.18"
72
76
 
73
77
  #define POOL_HELPER_THREAD_STACK_SIZE 262144
74
78
 
@@ -108,7 +108,7 @@ public:
108
108
  typedef void (*Callback)(EventedClient *client);
109
109
  typedef void (*SystemErrorCallback)(EventedClient *client, const string &message, int code);
110
110
 
111
- private:
111
+ protected:
112
112
  enum {
113
113
  /**
114
114
  * This is the initial state for a client. It means we're
@@ -694,6 +694,27 @@ public:
694
694
  return oldFd;
695
695
  }
696
696
  }
697
+
698
+ const char *getStateName() const {
699
+ switch (state) {
700
+ case EC_CONNECTED:
701
+ return "EC_CONNECTED";
702
+ case EC_WRITES_PENDING:
703
+ return "EC_WRITES_PENDING";
704
+ case EC_TOO_MANY_WRITES_PENDING:
705
+ return "EC_TOO_MANY_WRITES_PENDING";
706
+ case EC_RO_CONNECTED:
707
+ return "EC_RO_CONNECTED";
708
+ case EC_RO_CONNECTED_WITH_WRITES_PENDING:
709
+ return "EC_RO_CONNECTED_WITH_WRITES_PENDING";
710
+ case EC_DISCONNECTING_WITH_WRITES_PENDING:
711
+ return "EC_DISCONNECTING_WITH_WRITES_PENDING";
712
+ case EC_DISCONNECTED:
713
+ return "EC_DISCONNECTED";
714
+ default:
715
+ return "unknown";
716
+ }
717
+ }
697
718
  };
698
719
 
699
720
 
@@ -67,6 +67,21 @@ struct EventedMessageClientContext {
67
67
  * it's properly zeroed out. */
68
68
  scalarReader.reset(true);
69
69
  }
70
+
71
+ const char *getStateName() const {
72
+ switch (state) {
73
+ case MS_READING_USERNAME:
74
+ return "MS_READING_USERNAME";
75
+ case MS_READING_PASSWORD:
76
+ return "MS_READING_PASSWORD";
77
+ case MS_READING_MESSAGE:
78
+ return "MS_READING_MESSAGE";
79
+ case MS_PROCESSING_MESSAGE:
80
+ return "MS_PROCESSING_MESSAGE";
81
+ default:
82
+ return "unknown";
83
+ }
84
+ }
70
85
  };
71
86
 
72
87
  class EventedMessageClient: public EventedClient {
@@ -720,7 +720,7 @@ public:
720
720
 
721
721
  LoggerPtr newTransaction(const string &groupName,
722
722
  const string &category = "requests",
723
- const string &unionStationKey = string(),
723
+ const string &unionStationKey = "-",
724
724
  const string &filters = string())
725
725
  {
726
726
  if (serverAddress.empty()) {
@@ -851,7 +851,7 @@ public:
851
851
  LoggerPtr continueTransaction(const string &txnId,
852
852
  const string &groupName,
853
853
  const string &category = "requests",
854
- const string &unionStationKey = string())
854
+ const string &unionStationKey = "-")
855
855
  {
856
856
  if (serverAddress.empty() || txnId.empty()) {
857
857
  return createNullLogger();
@@ -125,6 +125,12 @@ class RequestHandler;
125
125
  #define RH_DEBUG(client, x) P_DEBUG("[Client " << client->name() << "] " << x)
126
126
  #define RH_TRACE(client, level, x) P_TRACE(level, "[Client " << client->name() << "] " << x)
127
127
 
128
+ #define RH_LOG_EVENT(client, eventName) \
129
+ char _clientName[7 + 8]; \
130
+ snprintf(_clientName, sizeof(_clientName), "Client %d", client->fdnum); \
131
+ TRACE_POINT_WITH_DATA(_clientName); \
132
+ RH_TRACE(client, 3, "Event: " eventName)
133
+
128
134
 
129
135
  class Client: public enable_shared_from_this<Client> {
130
136
  private:
@@ -1069,6 +1075,7 @@ private:
1069
1075
  }
1070
1076
 
1071
1077
  size_t onAppInputData(const ClientPtr &client, const StaticString &data) {
1078
+ RH_LOG_EVENT(client, "onAppInputData");
1072
1079
  if (!client->connected()) {
1073
1080
  return 0;
1074
1081
  }
@@ -1110,10 +1117,12 @@ private:
1110
1117
  }
1111
1118
 
1112
1119
  void onAppInputChunk(const ClientPtr &client, const StaticString &data) {
1120
+ RH_LOG_EVENT(client, "onAppInputChunk");
1113
1121
  writeToClientOutputPipe(client, data);
1114
1122
  }
1115
1123
 
1116
1124
  void onAppInputEof(const ClientPtr &client) {
1125
+ RH_LOG_EVENT(client, "onAppInputEof");
1117
1126
  if (!client->connected()) {
1118
1127
  return;
1119
1128
  }
@@ -1124,6 +1133,7 @@ private:
1124
1133
  }
1125
1134
 
1126
1135
  void onAppInputError(const ClientPtr &client, const char *message, int errorCode) {
1136
+ RH_LOG_EVENT(client, "onAppInputError");
1127
1137
  if (!client->connected()) {
1128
1138
  return;
1129
1139
  }
@@ -1143,6 +1153,7 @@ private:
1143
1153
  }
1144
1154
 
1145
1155
  void onClientOutputPipeCommit(const ClientPtr &client) {
1156
+ RH_LOG_EVENT(client, "onClientOutputPipeCommit");
1146
1157
  if (!client->connected()) {
1147
1158
  return;
1148
1159
  }
@@ -1166,6 +1177,7 @@ private:
1166
1177
  void onClientOutputPipeData(const ClientPtr &client, const char *data,
1167
1178
  size_t size, const FileBackedPipe::ConsumeCallback &consumed)
1168
1179
  {
1180
+ RH_LOG_EVENT(client, "onClientOutputPipeData");
1169
1181
  if (!client->connected()) {
1170
1182
  return;
1171
1183
  }
@@ -1196,6 +1208,7 @@ private:
1196
1208
  }
1197
1209
 
1198
1210
  void onClientOutputPipeEnd(const ClientPtr &client) {
1211
+ RH_LOG_EVENT(client, "onClientOutputPipeEnd");
1199
1212
  if (!client->connected()) {
1200
1213
  return;
1201
1214
  }
@@ -1206,6 +1219,7 @@ private:
1206
1219
  }
1207
1220
 
1208
1221
  void onClientOutputPipeError(const ClientPtr &client, int errorCode) {
1222
+ RH_LOG_EVENT(client, "onClientOutputPipeError");
1209
1223
  if (!client->connected()) {
1210
1224
  return;
1211
1225
  }
@@ -1218,6 +1232,7 @@ private:
1218
1232
  }
1219
1233
 
1220
1234
  void onClientOutputWritable(const ClientPtr &client) {
1235
+ RH_LOG_EVENT(client, "onClientOutputWritable");
1221
1236
  if (!client->connected()) {
1222
1237
  return;
1223
1238
  }
@@ -1323,7 +1338,7 @@ private:
1323
1338
 
1324
1339
 
1325
1340
  size_t onClientInputData(const ClientPtr &client, const StaticString &data) {
1326
- RH_TRACE(client, 3, "Event: onClientInputData");
1341
+ RH_LOG_EVENT(client, "onClientInputData");
1327
1342
  if (!client->connected()) {
1328
1343
  return 0;
1329
1344
  }
@@ -1374,7 +1389,7 @@ private:
1374
1389
  }
1375
1390
 
1376
1391
  void onClientEof(const ClientPtr &client) {
1377
- RH_TRACE(client, 3, "Event: onClientEof; client sent EOF");
1392
+ RH_LOG_EVENT(client, "onClientEof; client sent EOF");
1378
1393
  switch (client->state) {
1379
1394
  case Client::BUFFERING_REQUEST_BODY:
1380
1395
  state_bufferingRequestBody_onClientEof(client);
@@ -1389,7 +1404,7 @@ private:
1389
1404
  }
1390
1405
 
1391
1406
  void onClientInputError(const ClientPtr &client, const char *message, int errnoCode) {
1392
- RH_TRACE(client, 3, "Event: onClientInputError");
1407
+ RH_LOG_EVENT(client, "onClientInputError");
1393
1408
  if (!client->connected()) {
1394
1409
  return;
1395
1410
  }
@@ -1410,7 +1425,7 @@ private:
1410
1425
 
1411
1426
 
1412
1427
  void onClientBodyBufferData(const ClientPtr &client, const char *data, size_t size, const FileBackedPipe::ConsumeCallback &consumed) {
1413
- RH_TRACE(client, 3, "Event: onClientBodyBufferData");
1428
+ RH_LOG_EVENT(client, "onClientBodyBufferData");
1414
1429
  if (!client->connected()) {
1415
1430
  return;
1416
1431
  }
@@ -1425,7 +1440,7 @@ private:
1425
1440
  }
1426
1441
 
1427
1442
  void onClientBodyBufferError(const ClientPtr &client, int errorCode) {
1428
- RH_TRACE(client, 3, "Event: onClientBodyBufferError");
1443
+ RH_LOG_EVENT(client, "onClientBodyBufferError");
1429
1444
  if (!client->connected()) {
1430
1445
  return;
1431
1446
  }
@@ -1438,7 +1453,7 @@ private:
1438
1453
  }
1439
1454
 
1440
1455
  void onClientBodyBufferEnd(const ClientPtr &client) {
1441
- RH_TRACE(client, 3, "Event: onClientBodyBufferEnd");
1456
+ RH_LOG_EVENT(client, "onClientBodyBufferEnd");
1442
1457
  if (!client->connected()) {
1443
1458
  return;
1444
1459
  }
@@ -1453,7 +1468,7 @@ private:
1453
1468
  }
1454
1469
 
1455
1470
  void onClientBodyBufferCommit(const ClientPtr &client) {
1456
- RH_TRACE(client, 3, "Event: onClientBodyBufferCommit");
1471
+ RH_LOG_EVENT(client, "onClientBodyBufferCommit");
1457
1472
  if (!client->connected()) {
1458
1473
  return;
1459
1474
  }
@@ -1468,7 +1483,7 @@ private:
1468
1483
  }
1469
1484
 
1470
1485
  void onAppOutputWritable(const ClientPtr &client) {
1471
- RH_TRACE(client, 3, "Event: onAppOutputWritable");
1486
+ RH_LOG_EVENT(client, "onAppOutputWritable");
1472
1487
  if (!client->connected()) {
1473
1488
  return;
1474
1489
  }
@@ -1487,7 +1502,7 @@ private:
1487
1502
 
1488
1503
 
1489
1504
  void onTimeout(const ClientPtr &client) {
1490
- RH_TRACE(client, 3, "Event: onTimeout");
1505
+ RH_LOG_EVENT(client, "onTimeout");
1491
1506
  if (!client->connected()) {
1492
1507
  return;
1493
1508
  }
@@ -389,6 +389,22 @@ private:
389
389
  type = UNINITIALIZED;
390
390
  dataReader.setMaxSize(1024 * 128);
391
391
  }
392
+
393
+ template<typename Stream>
394
+ void inspect(Stream &stream) const {
395
+ stream << " * Client " << (int) fd << "\n";
396
+ stream << " Initialized : " << bool(type == LOGGER) << "\n";
397
+ stream << " Node name : " << nodeName << "\n";
398
+ stream << " Open transactions: (" << openTransactions.size() << ")";
399
+ set<string>::const_iterator it, end = openTransactions.end();
400
+ for (it = openTransactions.begin(); it != end; it++) {
401
+ stream << " " << *it;
402
+ }
403
+ stream << "\n";
404
+ stream << " Connection state : " << getStateName() << "\n";
405
+ stream << " Message state : " << messageServer.getStateName() << "\n";
406
+ stream << " Outbox : " << outbox.size() << " bytes\n";
407
+ }
392
408
  };
393
409
 
394
410
  typedef shared_ptr<Client> ClientPtr;
@@ -639,15 +655,6 @@ private:
639
655
  char writeCountStr[sizeof(unsigned int) * 2 + 1];
640
656
  integerToHexatri(transaction->writeCount, writeCountStr);
641
657
  transaction->writeCount++;
642
- transaction->data.reserve(transaction->data.size() +
643
- transaction->txnId.size() +
644
- 1 +
645
- timestamp.size() +
646
- 1 +
647
- strlen(writeCountStr) +
648
- 1 +
649
- data.size() +
650
- 1);
651
658
  transaction->data.append(transaction->txnId);
652
659
  transaction->data.append(" ");
653
660
  transaction->data.append(timestamp);
@@ -863,7 +870,7 @@ protected:
863
870
  }
864
871
 
865
872
  transaction = make_shared<Transaction>(this, ev_now(getLoop()));
866
- if (unionStationKey.empty()) {
873
+ if (unionStationKey.empty() || unionStationKey == "-") {
867
874
  char tempNodeId[MD5_HEX_SIZE];
868
875
 
869
876
  if (nodeId == NULL) {
@@ -1156,7 +1163,13 @@ public:
1156
1163
  TransactionMap::const_iterator it;
1157
1164
  TransactionMap::const_iterator end = transactions.end();
1158
1165
 
1159
- stream << "Number of clients : " << getClients().size() << "\n";
1166
+ ClientSet::const_iterator cit, cend = getClients().end();
1167
+ stream << "Clients:\n";
1168
+ stream << " Count: " << getClients().size() << "\n";
1169
+ for (cit = getClients().begin(); cit != cend; cit++) {
1170
+ const Client *client = static_cast<Client *>(*cit);
1171
+ client->inspect(stream);
1172
+ }
1160
1173
  stream << "\n";
1161
1174
 
1162
1175
  stream << "RemoteSender:\n";
@@ -39,12 +39,10 @@
39
39
  *
40
40
  * <h2>Initialization</h2>
41
41
  * Every thread that is to contain backtrace information <b>must</b> be
42
- * initialized. Initialization is done by instantiating an
43
- * initialize_backtrace_support_for_this_thread object. This includes the main
44
- * thread as well.
45
- *
46
- * If you use oxt::thread, then initialization will be automatically done for
47
- * you for that partciular thread.
42
+ * initialized. This is done by creating a `thread_local_context` object,
43
+ * and calling `set_thread_local_context()` with that object.
44
+ * `oxt::initialize()` automatically does this for the calling thread,
45
+ * and `oxt::thread` does this automatically as well.
48
46
  *
49
47
  * <h2>Basic usage</h2>
50
48
  * Backtrace points must be specified manually in the code using TRACE_POINT().
@@ -33,6 +33,7 @@ namespace oxt {
33
33
 
34
34
  #define TRACE_POINT() do { /* nothing */ } while (false)
35
35
  #define TRACE_POINT_WITH_NAME(name) do { /* nothing */ } while (false)
36
+ #define TRACE_POINT_WITH_DATA(data) do { /* nothing */ } while (false)
36
37
  #define UPDATE_TRACE_POINT() do { /* nothing */ } while (false)
37
38
 
38
39
  } // namespace oxt
@@ -41,19 +41,25 @@ namespace oxt {
41
41
  * Except if you set the 'detached' argument to true.
42
42
  */
43
43
  struct trace_point {
44
+ struct detached { };
45
+
44
46
  const char *function;
45
47
  const char *source;
46
- unsigned int line;
48
+ const char *data;
49
+ unsigned short line;
47
50
  bool m_detached;
48
51
 
49
- trace_point(const char *function, const char *source, unsigned int line);
50
- trace_point(const char *function, const char *source, unsigned int line, bool detached);
52
+ trace_point(const char *function, const char *source, unsigned short line,
53
+ const char *data = 0);
54
+ trace_point(const char *function, const char *source, unsigned short line,
55
+ const char *data, const detached &detached_tag);
51
56
  ~trace_point();
52
- void update(const char *source, unsigned int line);
57
+ void update(const char *source, unsigned short line);
53
58
  };
54
59
 
55
60
  #define TRACE_POINT() oxt::trace_point __p(BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)
56
61
  #define TRACE_POINT_WITH_NAME(name) oxt::trace_point __p(name, __FILE__, __LINE__)
62
+ #define TRACE_POINT_WITH_DATA(data) oxt::trace_point __p(BOOST_CURRENT_FUNCTION, __FILE__, __LINE__, data)
57
63
  #define UPDATE_TRACE_POINT() __p.update(__FILE__, __LINE__)
58
64
 
59
65
  } // namespace oxt