passenger 5.1.10 → 5.1.11

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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +18 -0
  3. data/Rakefile +20 -17
  4. data/bin/passenger-install-apache2-module +14 -11
  5. data/build/agent.rb +45 -18
  6. data/build/apache2.rb +32 -16
  7. data/build/basics.rb +29 -40
  8. data/build/common_library.rb +70 -54
  9. data/build/cxx_tests.rb +34 -43
  10. data/build/integration_tests.rb +10 -10
  11. data/build/misc.rb +6 -6
  12. data/build/node_tests.rb +1 -2
  13. data/build/oxt_tests.rb +7 -5
  14. data/build/packaging.rb +11 -441
  15. data/build/ruby_extension.rb +1 -1
  16. data/build/ruby_tests.rb +1 -2
  17. data/build/support/cplusplus.rb +6 -5
  18. data/build/support/cxx_dependency_map.rb +357 -833
  19. data/build/support/general.rb +23 -1
  20. data/build/test_basics.rb +3 -28
  21. data/dev/ci/tests/rpm/Jenkinsfile +68 -0
  22. data/dev/ci/tests/rpm/run +63 -0
  23. data/dev/ci/tests/source-packaging/run +1 -1
  24. data/dev/ci/tests/source-packaging/setup +1 -1
  25. data/doc/{Packaging.txt.md → Packaging.md} +0 -0
  26. data/resources/templates/apache2/deployment_example.txt.erb +2 -2
  27. data/resources/templates/apache2/multiple_apache_installations_detected.txt.erb +2 -2
  28. data/resources/templates/nginx/deployment_example.txt.erb +1 -1
  29. data/resources/templates/standalone/mass_deployment_default_server.erb +2 -2
  30. data/resources/templates/standalone/server.erb +2 -2
  31. data/src/agent/AgentMain.cpp +0 -4
  32. data/src/agent/Core/CoreMain.cpp +88 -5
  33. data/src/agent/Core/SpawningKit/Spawner.h +2 -1
  34. data/src/agent/Shared/Fundamentals/AbortHandler.cpp +1109 -0
  35. data/src/agent/Shared/Fundamentals/AbortHandler.h +63 -0
  36. data/src/agent/Shared/Fundamentals/Implementation.cpp +7 -0
  37. data/src/agent/Shared/Fundamentals/Initialization.cpp +614 -0
  38. data/src/agent/Shared/{Base.h → Fundamentals/Initialization.h} +23 -14
  39. data/src/agent/Shared/Fundamentals/Utils.cpp +127 -0
  40. data/src/agent/Shared/Fundamentals/Utils.h +46 -0
  41. data/src/agent/TempDirToucher/TempDirToucherMain.cpp +1 -1
  42. data/src/agent/Watchdog/CoreWatcher.cpp +3 -1
  43. data/src/agent/Watchdog/InstanceDirToucher.cpp +90 -53
  44. data/src/agent/Watchdog/WatchdogMain.cpp +13 -29
  45. data/src/apache2_module/Hooks.cpp +4 -1
  46. data/src/cxx_supportlib/ConfigKit/Store.h +32 -5
  47. data/src/cxx_supportlib/Constants.h +1 -2
  48. data/src/cxx_supportlib/Crypto.cpp +2 -1
  49. data/src/cxx_supportlib/Hooks.h +16 -37
  50. data/src/cxx_supportlib/LoggingKit/Context.h +22 -0
  51. data/src/cxx_supportlib/LoggingKit/Forward.h +1 -0
  52. data/src/cxx_supportlib/LoggingKit/Implementation.cpp +106 -22
  53. data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +106 -0
  54. data/src/{agent/UstRouter/FileSink.h → cxx_supportlib/ProcessManagement/Ruby.h} +23 -47
  55. data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +199 -0
  56. data/src/cxx_supportlib/ProcessManagement/Spawn.h +150 -0
  57. data/src/cxx_supportlib/ProcessManagement/Utils.cpp +459 -0
  58. data/src/cxx_supportlib/ProcessManagement/Utils.h +107 -0
  59. data/src/cxx_supportlib/Utils.cpp +41 -561
  60. data/src/cxx_supportlib/Utils.h +0 -68
  61. data/src/cxx_supportlib/Utils/AsyncSignalSafeUtils.h +187 -0
  62. data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +14 -2
  63. data/src/cxx_supportlib/WatchdogLauncher.h +2 -12
  64. data/src/cxx_supportlib/oxt/dynamic_thread_group.hpp +2 -2
  65. data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +4 -0
  66. data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +16 -1
  67. data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +12 -9
  68. data/src/cxx_supportlib/vendor-modified/libev/ev++.h +4 -4
  69. data/src/cxx_supportlib/vendor-modified/libev/ev.h +3 -3
  70. data/src/nginx_module/CacheLocationConfig.c +0 -75
  71. data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +1 -0
  72. data/src/nginx_module/Configuration.c +0 -1
  73. data/src/nginx_module/Configuration.h +0 -1
  74. data/src/nginx_module/ConfigurationCommands.c +1 -1
  75. data/src/nginx_module/ContentHandler.c +0 -1
  76. data/src/nginx_module/ContentHandler.h +0 -1
  77. data/src/nginx_module/CreateLocationConfig.c +0 -5
  78. data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +1 -0
  79. data/src/nginx_module/LocationConfig.h +0 -4
  80. data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -1
  81. data/src/nginx_module/MergeLocationConfig.c +0 -12
  82. data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +1 -0
  83. data/src/nginx_module/ngx_http_passenger_module.h +0 -1
  84. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  85. data/src/ruby_supportlib/phusion_passenger/common_library.rb +20 -11
  86. data/src/ruby_supportlib/phusion_passenger/config/api_call_command.rb +1 -1
  87. data/src/ruby_supportlib/phusion_passenger/config/reopen_logs_command.rb +0 -1
  88. data/src/ruby_supportlib/phusion_passenger/config/validate_install_command.rb +10 -3
  89. data/src/ruby_supportlib/phusion_passenger/console_text_template.rb +3 -1
  90. data/src/ruby_supportlib/phusion_passenger/constants.rb +0 -1
  91. data/src/ruby_supportlib/phusion_passenger/debug_logging.rb +1 -1
  92. data/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb +32 -6
  93. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +0 -1
  94. data/src/ruby_supportlib/phusion_passenger/packaging.rb +2 -4
  95. data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +101 -20
  96. data/src/ruby_supportlib/phusion_passenger/platform_info/apache_detector.rb +21 -9
  97. data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +34 -31
  98. data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +3 -1
  99. data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +2 -14
  100. data/src/ruby_supportlib/phusion_passenger/platform_info/operating_system.rb +40 -3
  101. data/src/ruby_supportlib/phusion_passenger/standalone/app_finder.rb +15 -14
  102. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +1 -1
  103. data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -1
  104. data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +8 -3
  105. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +19 -18
  106. data/src/ruby_supportlib/phusion_passenger/standalone/stop_command.rb +6 -1
  107. data/src/ruby_supportlib/phusion_passenger/vendor/daemon_controller.rb +17 -1
  108. metadata +19 -97
  109. data/build/documentation.rb +0 -70
  110. data/doc/CloudLicensingConfiguration.html +0 -172
  111. data/doc/CloudLicensingConfiguration.txt.md +0 -3
  112. data/doc/Packaging.html +0 -488
  113. data/doc/Security of user switching support.idmap.txt +0 -34
  114. data/doc/Security of user switching support.txt +0 -197
  115. data/doc/ServerOptimizationGuide.html +0 -172
  116. data/doc/ServerOptimizationGuide.txt.md +0 -3
  117. data/doc/images/by_sa.png +0 -0
  118. data/doc/images/cloud_licensing_batch_job.png +0 -0
  119. data/doc/images/code_walkthrough.jpg +0 -0
  120. data/doc/images/direct_spawning.png +0 -0
  121. data/doc/images/direct_spawning.svg +0 -251
  122. data/doc/images/glyphicons-halflings-white.png +0 -0
  123. data/doc/images/glyphicons-halflings.png +0 -0
  124. data/doc/images/icons/README +0 -5
  125. data/doc/images/icons/callouts/1.png +0 -0
  126. data/doc/images/icons/callouts/10.png +0 -0
  127. data/doc/images/icons/callouts/11.png +0 -0
  128. data/doc/images/icons/callouts/12.png +0 -0
  129. data/doc/images/icons/callouts/13.png +0 -0
  130. data/doc/images/icons/callouts/14.png +0 -0
  131. data/doc/images/icons/callouts/15.png +0 -0
  132. data/doc/images/icons/callouts/2.png +0 -0
  133. data/doc/images/icons/callouts/3.png +0 -0
  134. data/doc/images/icons/callouts/4.png +0 -0
  135. data/doc/images/icons/callouts/5.png +0 -0
  136. data/doc/images/icons/callouts/6.png +0 -0
  137. data/doc/images/icons/callouts/7.png +0 -0
  138. data/doc/images/icons/callouts/8.png +0 -0
  139. data/doc/images/icons/callouts/9.png +0 -0
  140. data/doc/images/icons/caution.png +0 -0
  141. data/doc/images/icons/example.png +0 -0
  142. data/doc/images/icons/home.png +0 -0
  143. data/doc/images/icons/important.png +0 -0
  144. data/doc/images/icons/next.png +0 -0
  145. data/doc/images/icons/note.png +0 -0
  146. data/doc/images/icons/prev.png +0 -0
  147. data/doc/images/icons/tip.png +0 -0
  148. data/doc/images/icons/up.png +0 -0
  149. data/doc/images/icons/warning.png +0 -0
  150. data/doc/images/many_web_framework_protocols.png +0 -0
  151. data/doc/images/passenger_architecture.png +0 -0
  152. data/doc/images/passenger_architecture.svg +0 -385
  153. data/doc/images/passenger_architecture_overview.png +0 -0
  154. data/doc/images/passenger_core_architecture.png +0 -0
  155. data/doc/images/passenger_nodejs_architecture.svg +0 -558
  156. data/doc/images/phusion_banner.png +0 -0
  157. data/doc/images/rack.png +0 -0
  158. data/doc/images/smart_spawning.png +0 -0
  159. data/doc/images/smart_spawning.svg +0 -323
  160. data/doc/images/spawn_server_architecture.png +0 -0
  161. data/doc/images/spawn_server_architecture.svg +0 -655
  162. data/doc/images/spawning_preparation_work.png +0 -0
  163. data/doc/images/startup_sequence.png +0 -0
  164. data/doc/images/typical_isolated_web_application.png +0 -0
  165. data/doc/images/typical_isolated_web_application.svg +0 -213
  166. data/doc/users_guide_snippets/alternative_for_flying_passenger.txt +0 -1
  167. data/doc/users_guide_snippets/analysis_and_system_maintenance.txt +0 -61
  168. data/doc/users_guide_snippets/appendix_a_about.txt +0 -13
  169. data/doc/users_guide_snippets/appendix_b_terminology.txt +0 -71
  170. data/doc/users_guide_snippets/appendix_c_spawning_methods.txt +0 -36
  171. data/doc/users_guide_snippets/deployment_basics.txt +0 -37
  172. data/doc/users_guide_snippets/enterprise_only.txt +0 -1
  173. data/doc/users_guide_snippets/environment_variables.txt +0 -44
  174. data/doc/users_guide_snippets/global_queueing_explained.txt +0 -74
  175. data/doc/users_guide_snippets/installation.txt +0 -228
  176. data/doc/users_guide_snippets/installation/run_installer.txt +0 -58
  177. data/doc/users_guide_snippets/installation/verify_running_epilogue.txt +0 -6
  178. data/doc/users_guide_snippets/passenger_spawn_method.txt +0 -37
  179. data/doc/users_guide_snippets/rackup_specifications.txt +0 -1
  180. data/doc/users_guide_snippets/rvm_helper_tool.txt +0 -44
  181. data/doc/users_guide_snippets/since_version.txt +0 -1
  182. data/doc/users_guide_snippets/support_information.txt +0 -8
  183. data/doc/users_guide_snippets/tips.txt +0 -302
  184. data/doc/users_guide_snippets/troubleshooting/default.txt +0 -48
  185. data/doc/users_guide_snippets/troubleshooting/rails.txt +0 -59
  186. data/doc/users_guide_snippets/under_the_hood/page_caching_support.txt +0 -24
  187. data/doc/users_guide_snippets/under_the_hood/relationship_with_ruby.txt +0 -10
  188. data/doc/users_guide_snippets/where_to_get_support.txt +0 -9
  189. data/src/agent/Shared/Base.cpp +0 -1678
  190. data/src/agent/UstRouter/ApiServer.h +0 -292
  191. data/src/agent/UstRouter/Client.h +0 -112
  192. data/src/agent/UstRouter/Controller.h +0 -1309
  193. data/src/agent/UstRouter/LogSink.h +0 -145
  194. data/src/agent/UstRouter/OptionParser.h +0 -180
  195. data/src/agent/UstRouter/RemoteSender.h +0 -853
  196. data/src/agent/UstRouter/RemoteSink.h +0 -145
  197. data/src/agent/UstRouter/Transaction.h +0 -278
  198. data/src/agent/UstRouter/UstRouterMain.cpp +0 -681
  199. data/src/agent/Watchdog/UstRouterWatcher.cpp +0 -80
  200. data/src/ruby_supportlib/phusion_passenger/platform_info/macos.rb +0 -45
@@ -1257,6 +1257,7 @@ public:
1257
1257
  ok = LoggingKit::context->prepareConfigChange(loggingConfig,
1258
1258
  errors, req);
1259
1259
  } catch (const std::exception &e) {
1260
+ ok = false;
1260
1261
  fprintf(stderr, "ERROR: unable to configure logging system: %s\n", e.what());
1261
1262
  }
1262
1263
  if (ok) {
@@ -1576,6 +1577,8 @@ destroy_hooks(void *arg) {
1576
1577
  boost::this_thread::disable_interruption di;
1577
1578
  boost::this_thread::disable_syscall_interruption dsi;
1578
1579
  P_DEBUG("Shutting down Phusion Passenger...");
1580
+ LoggingKit::shutdown();
1581
+ oxt::shutdown();
1579
1582
  delete hooks;
1580
1583
  hooks = NULL;
1581
1584
  } catch (const thread_interrupted &) {
@@ -1609,8 +1612,8 @@ init_module(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *
1609
1612
  */
1610
1613
  if (hooks == NULL) {
1611
1614
  oxt::initialize();
1612
- LoggingKit::initialize();
1613
1615
  SystemTime::initialize();
1616
+ LoggingKit::initialize();
1614
1617
  } else {
1615
1618
  P_DEBUG("Restarting Phusion Passenger....");
1616
1619
  delete hooks;
@@ -252,6 +252,16 @@ private:
252
252
  }
253
253
 
254
254
  public:
255
+ struct PreviewOptions {
256
+ bool filterSecrets;
257
+ bool shouldApplyInspectFilters;
258
+
259
+ PreviewOptions()
260
+ : filterSecrets(true),
261
+ shouldApplyInspectFilters()
262
+ { }
263
+ };
264
+
255
265
  Store()
256
266
  : schema(NULL),
257
267
  entries(0, 0),
@@ -352,7 +362,7 @@ public:
352
362
  * are not passed through inspect filters.
353
363
  */
354
364
  Json::Value previewUpdate(const Json::Value &updates, vector<Error> &errors,
355
- bool filterSecrets = true, bool shouldApplyInspectFilters = true) const
365
+ const PreviewOptions &options = PreviewOptions()) const
356
366
  {
357
367
  if (!updates.isNull() && !updates.isObject()) {
358
368
  errors.push_back(Error("The JSON document must be an object"));
@@ -360,10 +370,23 @@ public:
360
370
  }
361
371
 
362
372
  Json::Value result(Json::objectValue);
373
+ Store storeWithPreviewData(*this);
374
+ StringKeyTable<Entry>::Iterator p_it(storeWithPreviewData.entries);
363
375
  StringKeyTable<Entry>::ConstIterator it(entries);
364
376
  vector<Error> tmpErrors;
365
377
  Error error;
366
378
 
379
+ while (*p_it != NULL) {
380
+ const HashedStaticString &key = p_it.getKey();
381
+ Entry &entry = p_it.getValue();
382
+
383
+ if (isWritable(entry) && updates.isMember(key)) {
384
+ entry.userValue = updates[key];
385
+ }
386
+
387
+ p_it.next();
388
+ }
389
+
367
390
  while (*it != NULL) {
368
391
  const HashedStaticString &key = it.getKey();
369
392
  const Entry &entry = it.getValue();
@@ -376,8 +399,9 @@ public:
376
399
  } else {
377
400
  subdoc["user_value"] = entry.userValue;
378
401
  }
402
+
379
403
  if (entry.schemaEntry->defaultValueGetter) {
380
- subdoc["default_value"] = entry.getDefaultValue(*this);
404
+ subdoc["default_value"] = entry.getDefaultValue(storeWithPreviewData);
381
405
  }
382
406
 
383
407
  const Json::Value &effectiveValue =
@@ -400,11 +424,11 @@ public:
400
424
  applyNormalizers(result);
401
425
  }
402
426
 
403
- if (shouldApplyInspectFilters) {
427
+ if (options.shouldApplyInspectFilters) {
404
428
  applyInspectFilters(result);
405
429
  }
406
430
 
407
- if (filterSecrets) {
431
+ if (options.filterSecrets) {
408
432
  doFilterSecrets(result);
409
433
  }
410
434
 
@@ -423,7 +447,10 @@ public:
423
447
  * Any keys not in `updates` do not affect existing values stored in the store.
424
448
  */
425
449
  bool update(const Json::Value &updates, vector<Error> &errors) {
426
- Json::Value preview = previewUpdate(updates, errors, false, false);
450
+ PreviewOptions options;
451
+ options.filterSecrets = false;
452
+ options.shouldApplyInspectFilters = false;
453
+ Json::Value preview = previewUpdate(updates, errors, options);
427
454
  if (errors.empty()) {
428
455
  StringKeyTable<Entry>::Iterator it(entries);
429
456
  while (*it != NULL) {
@@ -71,7 +71,6 @@
71
71
  #define DEFAULT_STICKY_SESSIONS_COOKIE_NAME "_passenger_route"
72
72
  #define DEFAULT_UNION_STATION_GATEWAY_ADDRESS "gateway.unionstationapp.com"
73
73
  #define DEFAULT_UNION_STATION_GATEWAY_PORT 443
74
- #define DEFAULT_UST_ROUTER_LISTEN_ADDRESS "tcp://127.0.0.1:9344"
75
74
  #define DEFAULT_WEB_APP_USER "nobody"
76
75
  #define ENTERPRISE_URL "https://www.phusionpassenger.com/enterprise"
77
76
  #define FEEDBACK_FD 3
@@ -83,7 +82,7 @@
83
82
  #define PASSENGER_API_VERSION_MAJOR 0
84
83
  #define PASSENGER_API_VERSION_MINOR 3
85
84
  #define PASSENGER_DEFAULT_USER "nobody"
86
- #define PASSENGER_VERSION "5.1.10"
85
+ #define PASSENGER_VERSION "5.1.11"
87
86
  #define POOL_HELPER_THREAD_STACK_SIZE 262144
88
87
  #define PROCESS_SHUTDOWN_TIMEOUT 60
89
88
  #define PROCESS_SHUTDOWN_TIMEOUT_DISPLAY "1 minute"
@@ -294,7 +294,7 @@ CFDataRef Crypto::genIV(size_t ivSize) {
294
294
 
295
295
  bool Crypto::getKeyBytes(SecKeyRef cryptokey, void **target, size_t &len) {
296
296
  const CSSM_KEY *cssmKey;
297
- CSSM_WRAP_KEY wrappedKey = {{0}};
297
+ CSSM_WRAP_KEY wrappedKey;
298
298
 
299
299
  CSSM_CSP_HANDLE cspHandle = 0;
300
300
  CSSM_CC_HANDLE ccHandle = 0;
@@ -322,6 +322,7 @@ bool Crypto::getKeyBytes(SecKeyRef cryptokey, void **target, size_t &len) {
322
322
  &ccHandle);
323
323
  if (error != CSSM_OK) { cssmPerror("CSSM_CSP_CreateSymmetricContext",error); }
324
324
 
325
+ memset(&wrappedKey, 0, sizeof(wrappedKey));
325
326
  error = CSSM_WrapKey(ccHandle,
326
327
  creds,
327
328
  cssmKey,
@@ -33,16 +33,15 @@
33
33
  #include <boost/foreach.hpp>
34
34
  #include <oxt/backtrace.hpp>
35
35
 
36
- #include <sys/types.h>
37
- #include <sys/wait.h>
38
36
  #include <cstdio>
39
37
  #include <cerrno>
40
38
  #include <cstring>
41
39
  #include <cctype>
42
40
  #include <stdlib.h>
43
- #include <unistd.h>
44
41
 
45
42
  #include <LoggingKit/LoggingKit.h>
43
+ #include <ProcessManagement/Spawn.h>
44
+ #include <ProcessManagement/Utils.h>
46
45
  #include <Utils.h>
47
46
  #include <Utils/StrIntUtils.h>
48
47
  #include <Utils/VariantMap.h>
@@ -126,44 +125,24 @@ runSingleHookScript(HookScriptOptions &options, const string &command,
126
125
  const vector< pair<string, string> > &envvars)
127
126
  {
128
127
  TRACE_POINT_WITH_DATA(command.c_str());
129
- pid_t pid;
130
- int e, status;
128
+ const char *commandArray[] = {
129
+ command.c_str(),
130
+ NULL
131
+ };
132
+ SubprocessInfo info;
131
133
 
132
134
  P_INFO("Running " << options.name << " hook script: " << command);
133
-
134
- pid = fork();
135
- if (pid == 0) {
136
- resetSignalHandlersAndMask();
137
- disableMallocDebugging();
138
- closeAllFileDescriptors(2);
139
- setEnvVarsFromVector(envvars);
140
-
141
- execlp(command.c_str(), command.c_str(), (const char * const) 0);
142
- e = errno;
143
- fprintf(stderr, "*** ERROR: Cannot execute %s hook script %s: %s (errno=%d)\n",
144
- options.name.c_str(), command.c_str(), strerror(e), e);
145
- fflush(stderr);
146
- _exit(1);
147
- return true; // Never reached.
148
-
149
- } else if (pid == -1) {
150
- e = errno;
151
- P_ERROR("Cannot fork a process for hook script " << command <<
152
- ": " << strerror(e) << " (errno=" << e << ")");
153
- return false;
154
-
155
- } else if (waitpid(pid, &status, 0) == -1) {
156
- e = errno;
157
- P_ERROR("Unable to wait for hook script " << command <<
158
- " (PID " << pid << "): " << strerror(e) << " (errno=" <<
159
- e << ")");
135
+ try {
136
+ runCommand(commandArray, info, true, true, boost::bind(setEnvVarsFromVector, envvars));
137
+ } catch (const SystemException &e) {
138
+ P_ERROR("Error running hook script " << command << ": " << e.what());
160
139
  return false;
161
-
162
- } else {
163
- P_INFO("Hook script " << command << " (PID " << pid <<
164
- ") exited with status " << WEXITSTATUS(status));
165
- return WEXITSTATUS(status) == 0;
166
140
  }
141
+ if (info.status != 0 && info.status != -2) {
142
+ P_INFO("Hook script " << command << " (PID " << info.pid <<
143
+ ") exited with status " << WEXITSTATUS(info.status));
144
+ }
145
+ return info.status == 0 || info.status == -2;
167
146
  }
168
147
 
169
148
  inline bool
@@ -26,12 +26,16 @@
26
26
  #ifndef _PASSENGER_LOGGING_KIT_CONTEXT_H_
27
27
  #define _PASSENGER_LOGGING_KIT_CONTEXT_H_
28
28
 
29
+ #include <queue>
30
+
29
31
  #include <oxt/macros.hpp>
32
+ #include <oxt/thread.hpp>
30
33
  #include <boost/thread.hpp>
31
34
  #include <boost/atomic.hpp>
32
35
  #include <ConfigKit/ConfigKit.h>
33
36
  #include <LoggingKit/Forward.h>
34
37
  #include <LoggingKit/Config.h>
38
+ #include <Utils/SystemTime.h>
35
39
 
36
40
  namespace Passenger {
37
41
  namespace LoggingKit {
@@ -68,8 +72,15 @@ private:
68
72
  ConfigKit::Store config;
69
73
  boost::atomic<ConfigRealization *> configRlz;
70
74
 
75
+ mutable boost::mutex gcSyncher;
76
+ oxt::thread *gcThread;
77
+ boost::condition_variable gcShuttingDownCond, gcHasShutDownCond;
78
+ queue< pair<ConfigRealization *, MonotonicTimeUsec> > oldConfigs;
79
+ bool shuttingDown;
80
+
71
81
  public:
72
82
  Context(const Json::Value &initialConfig = Json::Value());
83
+ ~Context();
73
84
  ConfigKit::Store getConfig() const;
74
85
 
75
86
  bool prepareConfigChange(const Json::Value &updates,
@@ -82,6 +93,17 @@ public:
82
93
  const ConfigRealization *getConfigRealization() const {
83
94
  return configRlz.load(boost::memory_order_acquire);
84
95
  }
96
+
97
+ void pushOldConfigAndCreateGcThread(ConfigRealization *oldConfigRlz, MonotonicTimeUsec monotonicNow);
98
+ void gcThreadMain();
99
+
100
+ private:
101
+ pair<ConfigRealization*,MonotonicTimeUsec> peekOldConfig();
102
+ void popOldConfig(ConfigRealization *oldConfig);
103
+ bool oldConfigsExist();
104
+ void createGcThread();
105
+ void killGcThread();
106
+ void gcLockless(bool wait, boost::unique_lock<boost::mutex> &lock);
85
107
  };
86
108
 
87
109
 
@@ -75,6 +75,7 @@ extern Context *context;
75
75
 
76
76
 
77
77
  void initialize(const Json::Value &initialConfig = Json::Value());
78
+ void shutdown();
78
79
 
79
80
  const char *_strdupFastStringStream(const FastStringStream<> &stream);
80
81
  bool _passesLogLevel(const Context *context, Level level, const ConfigRealization **outputConfigRlz);
@@ -32,8 +32,10 @@
32
32
  #include <cstring>
33
33
  #include <cerrno>
34
34
  #include <cassert>
35
+ #include <queue>
35
36
  #include <sys/time.h>
36
37
  #include <fcntl.h>
38
+ #include <utility>
37
39
  #include <unistd.h>
38
40
  #include <time.h>
39
41
  #include <pthread.h>
@@ -53,6 +55,7 @@
53
55
  #include <ConfigKit/ConfigKit.h>
54
56
  #include <Utils.h>
55
57
  #include <Utils/StrIntUtils.h>
58
+ #include <Utils/SystemTime.h>
56
59
 
57
60
  namespace Passenger {
58
61
  namespace LoggingKit {
@@ -71,6 +74,11 @@ initialize(const Json::Value &initialConfig) {
71
74
  context = new Context(initialConfig);
72
75
  }
73
76
 
77
+ void
78
+ shutdown() {
79
+ delete context;
80
+ context = NULL;
81
+ }
74
82
 
75
83
  Level getLevel() {
76
84
  if (OXT_LIKELY(context != NULL)) {
@@ -397,13 +405,32 @@ normalizeConfig(const Json::Value &effectiveValues) {
397
405
 
398
406
 
399
407
  Context::Context(const Json::Value &initialConfig)
400
- : config(schema, initialConfig)
408
+ : config(schema, initialConfig),
409
+ gcThread(NULL),
410
+ shuttingDown(false)
401
411
  {
402
412
  configRlz.store(new ConfigRealization(config));
403
413
  configRlz.load()->apply(config, NULL);
404
414
  configRlz.load()->finalize();
405
415
  }
406
416
 
417
+ Context::~Context() {
418
+ boost::unique_lock<boost::mutex> l(gcSyncher);
419
+
420
+ // If a gc thread exists, tell it to shut down and
421
+ // wait until it has done so.
422
+ shuttingDown = true;
423
+ gcShuttingDownCond.notify_one();
424
+ while (gcThread != NULL) {
425
+ gcHasShutDownCond.wait(l);
426
+ }
427
+
428
+ killGcThread();
429
+ gcLockless(false, l);
430
+
431
+ delete configRlz.load();
432
+ }
433
+
407
434
  ConfigKit::Store
408
435
  Context::getConfig() const {
409
436
  boost::lock_guard<boost::mutex> l(syncher);
@@ -442,6 +469,82 @@ Context::commitConfigChange(LoggingKit::ConfigChangeRequest &req) BOOST_NOEXCEPT
442
469
  newConfigRlz->finalize();
443
470
  }
444
471
 
472
+ pair<ConfigRealization*,MonotonicTimeUsec>
473
+ Context::peekOldConfig() {
474
+ return oldConfigs.front();
475
+ }
476
+
477
+ void
478
+ Context::popOldConfig(ConfigRealization *oldConfig) {
479
+ delete oldConfig;
480
+ oldConfigs.pop();
481
+ }
482
+
483
+ void
484
+ Context::createGcThread() {
485
+ if (gcThread == NULL) {
486
+ try {
487
+ gcThread = new oxt::thread(boost::bind(&Context::gcThreadMain, this),
488
+ "LoggingKit config garbage collector thread",
489
+ 128 * 1024);
490
+ } catch (const std::exception &e) {
491
+ P_ERROR("Error spawning background thread to garbage collect"
492
+ " old LoggingKit configuration: " << e.what());
493
+ }
494
+ }
495
+ }
496
+
497
+ void
498
+ Context::pushOldConfigAndCreateGcThread(ConfigRealization *oldConfigRlz, MonotonicTimeUsec monotonicNow) {
499
+ // Garbage collect old config realization in 5 minutes.
500
+ // There is no way to cheaply find out whether oldConfigRlz
501
+ // is still being used (we don't want to resort to more atomic
502
+ // operations, or conservative garbage collection) but
503
+ // waiting 5 minutes should be good enough.
504
+ MonotonicTimeUsec gcTime = monotonicNow + 5llu * 60llu * 1000000llu;
505
+ boost::unique_lock<boost::mutex> l(gcSyncher);
506
+ oldConfigs.push(make_pair(oldConfigRlz, gcTime));
507
+ createGcThread();
508
+ }
509
+
510
+ bool
511
+ Context::oldConfigsExist() {
512
+ return !oldConfigs.empty();
513
+ }
514
+
515
+ void
516
+ Context::gcThreadMain() {
517
+ boost::unique_lock<boost::mutex> l(gcSyncher);
518
+ gcLockless(true, l);
519
+ }
520
+
521
+ void
522
+ Context::gcLockless(bool wait, boost::unique_lock<boost::mutex> &lock) {
523
+ while (!shuttingDown && oldConfigsExist()) {
524
+ pair<ConfigRealization *, MonotonicTimeUsec> p = peekOldConfig();
525
+ for (MonotonicTimeUsec now = SystemTime::getMonotonicUsecWithGranularity<SystemTime::GRAN_1SEC>();
526
+ !shuttingDown && wait && now < p.second;
527
+ now = SystemTime::getMonotonicUsecWithGranularity<SystemTime::GRAN_1SEC>())
528
+ {
529
+ // Wait until it's time to GC this config object,
530
+ // or until the destructor tells us that we're shutting down.
531
+ gcShuttingDownCond.timed_wait(lock, boost::posix_time::microseconds(p.second - now));
532
+ }
533
+ if (!shuttingDown) {
534
+ popOldConfig(p.first);
535
+ }
536
+ }
537
+ killGcThread();
538
+ }
539
+
540
+ void
541
+ Context::killGcThread() {
542
+ if (gcThread != NULL) {
543
+ delete gcThread;
544
+ gcThread = NULL;
545
+ }
546
+ gcHasShutDownCond.notify_one();
547
+ }
445
548
 
446
549
  Json::Value
447
550
  Schema::createStderrTarget() {
@@ -636,14 +739,6 @@ ConfigRealization::~ConfigRealization() {
636
739
  }
637
740
  }
638
741
 
639
- static void
640
- garbageCollectConfigRealization(ConfigRealization *configRlz) {
641
- boost::this_thread::disable_interruption di;
642
- boost::this_thread::disable_syscall_interruption dsi;
643
- syscalls::sleep(30);
644
- delete configRlz;
645
- }
646
-
647
742
  void
648
743
  ConfigRealization::apply(const ConfigKit::Store &config, ConfigRealization *oldConfigRlz)
649
744
  BOOST_NOEXCEPT_OR_NOTHROW
@@ -658,19 +753,8 @@ ConfigRealization::apply(const ConfigKit::Store &config, ConfigRealization *oldC
658
753
  }
659
754
 
660
755
  if (oldConfigRlz != NULL) {
661
- // Garbage collect old config realization in 30 seconds.
662
- // There is no way to cheaply find out whether oldConfigRlz
663
- // is still being used (we don't want to resort to more atomic
664
- // operations, or conservative garbage collection) but
665
- // waiting 30 seconds should be good enough.
666
- try {
667
- oxt::thread(boost::bind(garbageCollectConfigRealization, oldConfigRlz),
668
- "LoggingKit config garbage collector " + toString(oldConfigRlz),
669
- 128 * 1024);
670
- } catch (const std::exception &e) {
671
- P_ERROR("Error spawning background thread to garbage collect"
672
- " old LoggingKit configuration: " << e.what());
673
- }
756
+ MonotonicTimeUsec monotonicNow = SystemTime::getMonotonicUsecWithGranularity<SystemTime::GRAN_1SEC>();
757
+ context->pushOldConfigAndCreateGcThread(oldConfigRlz, monotonicNow);
674
758
  }
675
759
  }
676
760