passenger 4.0.2 → 4.0.3

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 (79) hide show
  1. data.tar.gz.asc +7 -7
  2. data/NEWS +27 -0
  3. data/bin/passenger-config +6 -3
  4. data/bin/passenger-install-apache2-module +2 -2
  5. data/bin/passenger-install-nginx-module +16 -2
  6. data/build/agents.rb +4 -0
  7. data/build/apache2.rb +1 -1
  8. data/build/cplusplus_support.rb +1 -1
  9. data/build/cxx_tests.rb +3 -0
  10. data/build/packaging.rb +51 -8
  11. data/build/ruby_extension.rb +1 -1
  12. data/doc/Packaging.txt.md +20 -7
  13. data/doc/Users guide Apache.html +1 -1
  14. data/doc/Users guide Apache.txt +1 -1
  15. data/doc/Users guide Nginx.html +5 -4
  16. data/doc/Users guide Nginx.txt +1 -1
  17. data/doc/users_guide_snippets/installation.txt +5 -3
  18. data/ext/apache2/Configuration.cpp +12 -0
  19. data/ext/apache2/Configuration.hpp +7 -4
  20. data/ext/apache2/Hooks.cpp +29 -19
  21. data/ext/common/AgentsStarter.cpp +85 -57
  22. data/ext/common/AgentsStarter.h +570 -42
  23. data/ext/common/ApplicationPool2/DirectSpawner.h +5 -2
  24. data/ext/common/ApplicationPool2/Implementation.cpp +7 -1
  25. data/ext/common/ApplicationPool2/Pool.h +6 -3
  26. data/ext/common/ApplicationPool2/Process.h +12 -3
  27. data/ext/common/ApplicationPool2/SmartSpawner.h +2 -1
  28. data/ext/common/Constants.h +4 -1
  29. data/ext/common/EventedBufferedInput.h +139 -16
  30. data/ext/common/MultiLibeio.cpp +4 -2
  31. data/ext/common/SafeLibev.h +15 -62
  32. data/ext/common/ServerInstanceDir.h +10 -26
  33. data/ext/common/Utils.cpp +1 -3
  34. data/ext/common/Utils.h +1 -1
  35. data/ext/common/Utils/StrIntUtils.cpp +9 -0
  36. data/ext/common/Utils/StrIntUtils.h +5 -0
  37. data/ext/common/Utils/VariantMap.h +63 -14
  38. data/ext/common/agents/Base.cpp +50 -15
  39. data/ext/common/agents/HelperAgent/AgentOptions.h +20 -12
  40. data/ext/common/agents/HelperAgent/FileBackedPipe.h +1 -1
  41. data/ext/common/agents/HelperAgent/Main.cpp +5 -4
  42. data/ext/common/agents/HelperAgent/RequestHandler.h +1 -1
  43. data/ext/common/agents/LoggingAgent/Main.cpp +0 -1
  44. data/ext/common/agents/LoggingAgent/RemoteSender.h +2 -2
  45. data/ext/common/agents/SpawnPreparer.cpp +23 -5
  46. data/ext/common/agents/Watchdog/AgentWatcher.cpp +508 -0
  47. data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +93 -0
  48. data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +68 -0
  49. data/ext/common/agents/Watchdog/Main.cpp +180 -802
  50. data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +111 -0
  51. data/ext/nginx/Configuration.c +107 -92
  52. data/ext/nginx/Configuration.h +1 -0
  53. data/ext/nginx/ContentHandler.c +6 -6
  54. data/ext/nginx/ContentHandler.h +1 -1
  55. data/ext/nginx/config +8 -2
  56. data/ext/nginx/ngx_http_passenger_module.c +54 -60
  57. data/ext/nginx/ngx_http_passenger_module.h +6 -6
  58. data/lib/phusion_passenger.rb +17 -10
  59. data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
  60. data/lib/phusion_passenger/common_library.rb +0 -1
  61. data/lib/phusion_passenger/platform_info.rb +10 -1
  62. data/lib/phusion_passenger/platform_info/depcheck.rb +4 -4
  63. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +2 -2
  64. data/lib/phusion_passenger/platform_info/ruby.rb +7 -0
  65. data/lib/phusion_passenger/request_handler.rb +119 -42
  66. data/lib/phusion_passenger/request_handler/thread_handler.rb +25 -22
  67. data/lib/phusion_passenger/standalone/command.rb +2 -0
  68. data/lib/phusion_passenger/standalone/runtime_installer.rb +4 -3
  69. data/lib/phusion_passenger/standalone/start_command.rb +49 -37
  70. data/resources/templates/nginx/pcre_checksum_could_not_be_verified.txt.erb +11 -0
  71. data/test/cxx/CxxTestMain.cpp +2 -0
  72. data/test/cxx/EventedBufferedInputTest.cpp +758 -0
  73. data/test/cxx/ServerInstanceDirTest.cpp +16 -31
  74. data/test/cxx/TestSupport.cpp +2 -1
  75. data/test/cxx/VariantMapTest.cpp +23 -11
  76. metadata +8 -4
  77. metadata.gz.asc +7 -7
  78. data/ext/common/AgentsStarter.hpp +0 -655
  79. data/lib/phusion_passenger/utils/robust_interruption.rb +0 -173
@@ -49,13 +49,13 @@
49
49
  #define HELPER_SERVER_PASSWORD_SIZE 64
50
50
 
51
51
 
52
- static int first_start = 1;
53
- ngx_str_t passenger_schema_string;
54
- ngx_str_t passenger_placeholder_upstream_address;
55
- PassengerCachedFileStat *passenger_stat_cache;
52
+ static int first_start = 1;
53
+ ngx_str_t passenger_schema_string;
54
+ ngx_str_t passenger_placeholder_upstream_address;
55
+ PassengerCachedFileStat *passenger_stat_cache;
56
56
  PassengerAppTypeDetector *passenger_app_type_detector;
57
- AgentsStarter *passenger_agents_starter = NULL;
58
- ngx_cycle_t *passenger_current_cycle;
57
+ PSG_AgentsStarter *passenger_agents_starter = NULL;
58
+ ngx_cycle_t *passenger_current_cycle;
59
59
 
60
60
 
61
61
  /*
@@ -104,6 +104,14 @@ ngx_str_null_terminate(ngx_str_t *str) {
104
104
  return result;
105
105
  }
106
106
 
107
+ static void
108
+ psg_variant_map_set_ngx_str(PSG_VariantMap *m,
109
+ const char *name,
110
+ ngx_str_t *value)
111
+ {
112
+ psg_variant_map_set(m, name, (const char *) value->data, value->len);
113
+ }
114
+
107
115
  /**
108
116
  * Save the Nginx master process's PID into a file under the server instance directory.
109
117
  *
@@ -121,7 +129,7 @@ save_master_process_pid(ngx_cycle_t *cycle) {
121
129
  FILE *f;
122
130
 
123
131
  last = ngx_snprintf(filename, sizeof(filename) - 1, "%s/control_process.pid",
124
- agents_starter_get_server_instance_dir(passenger_agents_starter));
132
+ psg_agents_starter_get_server_instance_dir(passenger_agents_starter));
125
133
  *last = (u_char) '\0';
126
134
 
127
135
  f = fopen((const char *) filename, "w");
@@ -241,35 +249,16 @@ start_helper_server(ngx_cycle_t *cycle) {
241
249
  ngx_uint_t i;
242
250
  ngx_str_t *prestart_uris;
243
251
  char **prestart_uris_ary = NULL;
252
+ ngx_keyval_t *ctl = NULL;
253
+ PSG_VariantMap *params = NULL;
244
254
  u_char filename[NGX_MAX_PATH], *last;
245
- char *debug_log_file = NULL;
246
- char *default_user = NULL;
247
- char *default_group = NULL;
248
255
  char *passenger_root = NULL;
249
- char *default_ruby = NULL;
250
- char *temp_dir = NULL;
251
- char *analytics_log_user;
252
- char *analytics_log_group;
253
- char *union_station_gateway_address;
254
- char *union_station_gateway_cert;
255
- char *union_station_proxy_address;
256
256
  char *error_message = NULL;
257
257
 
258
258
  core_conf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
259
259
  result = NGX_OK;
260
-
261
- /* Create null-terminated versions of some strings. */
262
- debug_log_file = ngx_str_null_terminate(&passenger_main_conf.debug_log_file);
263
- default_user = ngx_str_null_terminate(&passenger_main_conf.default_user);
264
- default_group = ngx_str_null_terminate(&passenger_main_conf.default_group);
260
+ params = psg_variant_map_new();
265
261
  passenger_root = ngx_str_null_terminate(&passenger_main_conf.root_dir);
266
- default_ruby = ngx_str_null_terminate(&passenger_main_conf.default_ruby);
267
- temp_dir = ngx_str_null_terminate(&passenger_main_conf.temp_dir);
268
- analytics_log_user = ngx_str_null_terminate(&passenger_main_conf.analytics_log_user);
269
- analytics_log_group = ngx_str_null_terminate(&passenger_main_conf.analytics_log_group);
270
- union_station_gateway_address = ngx_str_null_terminate(&passenger_main_conf.union_station_gateway_address);
271
- union_station_gateway_cert = ngx_str_null_terminate(&passenger_main_conf.union_station_gateway_cert);
272
- union_station_proxy_address = ngx_str_null_terminate(&passenger_main_conf.union_station_proxy_address);
273
262
 
274
263
  prestart_uris = (ngx_str_t *) passenger_main_conf.prestart_uris->elts;
275
264
  prestart_uris_ary = calloc(sizeof(char *), passenger_main_conf.prestart_uris->nelts);
@@ -283,22 +272,36 @@ start_helper_server(ngx_cycle_t *cycle) {
283
272
  memcpy(prestart_uris_ary[i], prestart_uris[i].data, prestart_uris[i].len);
284
273
  prestart_uris_ary[i][prestart_uris[i].len] = '\0';
285
274
  }
275
+
276
+ psg_variant_map_set_int (params, "web_server_pid", getpid());
277
+ psg_variant_map_set_int (params, "web_server_worker_uid", core_conf->user);
278
+ psg_variant_map_set_int (params, "web_server_worker_gid", core_conf->group);
279
+ psg_variant_map_set_int (params, "log_level", passenger_main_conf.log_level);
280
+ psg_variant_map_set_ngx_str(params, "debug_log_file", &passenger_main_conf.debug_log_file);
281
+ psg_variant_map_set_ngx_str(params, "temp_dir", &passenger_main_conf.temp_dir);
282
+ psg_variant_map_set_bool (params, "user_switching", passenger_main_conf.user_switching);
283
+ psg_variant_map_set_ngx_str(params, "default_user", &passenger_main_conf.default_user);
284
+ psg_variant_map_set_ngx_str(params, "default_group", &passenger_main_conf.default_group);
285
+ psg_variant_map_set_ngx_str(params, "default_ruby", &passenger_main_conf.default_ruby);
286
+ psg_variant_map_set_int (params, "max_pool_size", passenger_main_conf.max_pool_size);
287
+ psg_variant_map_set_int (params, "pool_idle_time", passenger_main_conf.pool_idle_time);
288
+ psg_variant_map_set_ngx_str(params, "analytics_log_user", &passenger_main_conf.analytics_log_user);
289
+ psg_variant_map_set_ngx_str(params, "analytics_log_group", &passenger_main_conf.analytics_log_group);
290
+ psg_variant_map_set_ngx_str(params, "union_station_gateway_address", &passenger_main_conf.union_station_gateway_address);
291
+ psg_variant_map_set_ngx_str(params, "union_station_gateway_cert", &passenger_main_conf.union_station_gateway_cert);
292
+ psg_variant_map_set_ngx_str(params, "union_station_proxy_address", &passenger_main_conf.union_station_proxy_address);
293
+ psg_variant_map_set_strset (params, "prestart_urls", (const char **) prestart_uris_ary, passenger_main_conf.prestart_uris->nelts);
294
+
295
+ ctl = (ngx_keyval_t *) passenger_main_conf.ctl->elts;
296
+ for (i = 0; i < passenger_main_conf.ctl->nelts; i++) {
297
+ psg_variant_map_set2(params,
298
+ (const char *) ctl[i].key.data, ctl[i].key.len - 1,
299
+ (const char *) ctl[i].value.data, ctl[i].value.len - 1);
300
+ }
286
301
 
287
- ret = agents_starter_start(passenger_agents_starter,
288
- passenger_main_conf.log_level, debug_log_file, getpid(),
289
- temp_dir, passenger_main_conf.user_switching,
290
- default_user, default_group,
291
- core_conf->user, core_conf->group,
292
- passenger_root, default_ruby, passenger_main_conf.max_pool_size,
293
- passenger_main_conf.max_instances_per_app,
294
- passenger_main_conf.pool_idle_time,
295
- "",
296
- analytics_log_user, analytics_log_group,
297
- union_station_gateway_address,
298
- passenger_main_conf.union_station_gateway_port,
299
- union_station_gateway_cert,
300
- union_station_proxy_address,
301
- (const char **) prestart_uris_ary, passenger_main_conf.prestart_uris->nelts,
302
+ ret = psg_agents_starter_start(passenger_agents_starter,
303
+ passenger_root,
304
+ params,
302
305
  starting_helper_server_after_fork,
303
306
  cycle,
304
307
  &error_message);
@@ -314,7 +317,7 @@ start_helper_server(ngx_cycle_t *cycle) {
314
317
  */
315
318
  last = ngx_snprintf(filename, sizeof(filename) - 1,
316
319
  "%s/control_process.pid",
317
- agents_starter_get_server_instance_dir(passenger_agents_starter));
320
+ psg_agents_starter_get_server_instance_dir(passenger_agents_starter));
318
321
  *last = (u_char) '\0';
319
322
  if (create_file(cycle, filename, (const u_char *) "", 0) != NGX_OK) {
320
323
  result = NGX_ERROR;
@@ -331,7 +334,7 @@ start_helper_server(ngx_cycle_t *cycle) {
331
334
  /* Create various other info files. */
332
335
  last = ngx_snprintf(filename, sizeof(filename) - 1,
333
336
  "%s/web_server.txt",
334
- agents_starter_get_generation_dir(passenger_agents_starter));
337
+ psg_agents_starter_get_generation_dir(passenger_agents_starter));
335
338
  *last = (u_char) '\0';
336
339
  if (create_file(cycle, filename, (const u_char *) NGINX_VER, strlen(NGINX_VER)) != NGX_OK) {
337
340
  result = NGX_ERROR;
@@ -340,7 +343,7 @@ start_helper_server(ngx_cycle_t *cycle) {
340
343
 
341
344
  last = ngx_snprintf(filename, sizeof(filename) - 1,
342
345
  "%s/config_files.txt",
343
- agents_starter_get_generation_dir(passenger_agents_starter));
346
+ psg_agents_starter_get_generation_dir(passenger_agents_starter));
344
347
  *last = (u_char) '\0';
345
348
  if (create_file(cycle, filename, cycle->conf_file.data, cycle->conf_file.len) != NGX_OK) {
346
349
  result = NGX_ERROR;
@@ -348,17 +351,8 @@ start_helper_server(ngx_cycle_t *cycle) {
348
351
  }
349
352
 
350
353
  cleanup:
351
- free(debug_log_file);
352
- free(default_user);
353
- free(default_group);
354
+ psg_variant_map_free(params);
354
355
  free(passenger_root);
355
- free(default_ruby);
356
- free(temp_dir);
357
- free(analytics_log_user);
358
- free(analytics_log_group);
359
- free(union_station_gateway_address);
360
- free(union_station_gateway_cert);
361
- free(union_station_proxy_address);
362
356
  free(error_message);
363
357
  if (prestart_uris_ary != NULL) {
364
358
  for (i = 0; i < passenger_main_conf.prestart_uris->nelts; i++) {
@@ -380,7 +374,7 @@ cleanup:
380
374
  static void
381
375
  shutdown_helper_server() {
382
376
  if (passenger_agents_starter != NULL) {
383
- agents_starter_free(passenger_agents_starter);
377
+ psg_agents_starter_free(passenger_agents_starter);
384
378
  passenger_agents_starter = NULL;
385
379
  }
386
380
  }
@@ -405,7 +399,7 @@ pre_config_init(ngx_conf_t *cf)
405
399
  passenger_placeholder_upstream_address.len = sizeof("unix:/passenger_helper_server") - 1;
406
400
  passenger_stat_cache = cached_file_stat_new(1024);
407
401
  passenger_app_type_detector = passenger_app_type_detector_new();
408
- passenger_agents_starter = agents_starter_new(AS_NGINX, &error_message);
402
+ passenger_agents_starter = psg_agents_starter_new(AS_NGINX, &error_message);
409
403
 
410
404
  if (passenger_agents_starter == NULL) {
411
405
  ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, "%s", error_message);
@@ -458,7 +452,7 @@ init_worker_process(ngx_cycle_t *cycle) {
458
452
 
459
453
  core_conf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
460
454
  if (core_conf->master) {
461
- agents_starter_detach(passenger_agents_starter);
455
+ psg_agents_starter_detach(passenger_agents_starter);
462
456
  }
463
457
  }
464
458
  return NGX_OK;
@@ -30,9 +30,9 @@
30
30
 
31
31
  #include <ngx_config.h>
32
32
  #include <ngx_core.h>
33
- #include "../common/AgentsStarter.h"
34
- #include "../common/ApplicationPool2/AppTypes.h"
35
- #include "../common/Utils/CachedFileStat.h"
33
+ #include "common/AgentsStarter.h"
34
+ #include "common/ApplicationPool2/AppTypes.h"
35
+ #include "common/Utils/CachedFileStat.h"
36
36
 
37
37
  /**
38
38
  * The Nginx version number as an integer.
@@ -55,13 +55,13 @@ extern ngx_str_t passenger_placeholder_upstream_address;
55
55
  /**
56
56
  * A CachedFileStat object used for caching stat() calls.
57
57
  */
58
- extern PassengerCachedFileStat *passenger_stat_cache;
58
+ extern PassengerCachedFileStat *passenger_stat_cache;
59
59
 
60
60
  extern PassengerAppTypeDetector *passenger_app_type_detector;
61
61
 
62
- extern AgentsStarter *passenger_agents_starter;
62
+ extern PSG_AgentsStarter *passenger_agents_starter;
63
63
 
64
- extern ngx_cycle_t *passenger_current_cycle;
64
+ extern ngx_cycle_t *passenger_current_cycle;
65
65
 
66
66
  #endif /* _PASSENGER_NGINX_MODULE_H_ */
67
67
 
@@ -31,10 +31,14 @@ module PhusionPassenger
31
31
  PACKAGE_NAME = 'passenger'
32
32
 
33
33
  # Phusion Passenger version number. Don't forget to edit ext/common/Constants.h too.
34
- VERSION_STRING = '4.0.2'
34
+ VERSION_STRING = '4.0.3'
35
35
 
36
36
  PREFERRED_NGINX_VERSION = '1.4.1'
37
+ NGINX_SHA256_CHECKSUM = 'bca5d1e89751ba29406185e1736c390412603a7e6b604f5b4575281f6565d119'
38
+
37
39
  PREFERRED_PCRE_VERSION = '8.32'
40
+ PCRE_SHA256_CHECKSUM = 'd5d8634b36baf3d08be442a627001099583b397f456bc795304a013383b6423a'
41
+
38
42
  STANDALONE_INTERFACE_VERSION = 1
39
43
 
40
44
 
@@ -58,15 +62,6 @@ module PhusionPassenger
58
62
  # System-wide directory for storing Phusion Passenger Standalone runtime files.
59
63
  GLOBAL_STANDALONE_RESOURCE_DIR = "/var/lib/#{GLOBAL_STANDALONE_NAMESPACE_DIRNAME}".freeze
60
64
 
61
- NATIVELY_PACKAGED_BIN_DIR = "/usr/bin".freeze
62
- NATIVELY_PACKAGED_AGENTS_DIR = "/usr/lib/#{GLOBAL_NAMESPACE_DIRNAME}/agents".freeze
63
- NATIVELY_PACKAGED_HELPER_SCRIPTS_DIR = "/usr/share/#{GLOBAL_NAMESPACE_DIRNAME}/helper-scripts".freeze
64
- NATIVELY_PACKAGED_RESOURCES_DIR = "/usr/share/#{GLOBAL_NAMESPACE_DIRNAME}".freeze
65
- NATIVELY_PACKAGED_DOC_DIR = "/usr/share/doc/#{GLOBAL_NAMESPACE_DIRNAME}".freeze
66
- NATIVELY_PACKAGED_RUNTIME_LIBDIR = "/usr/lib/#{GLOBAL_NAMESPACE_DIRNAME}".freeze
67
- NATIVELY_PACKAGED_HEADER_DIR = "/usr/include/#{GLOBAL_NAMESPACE_DIRNAME}".freeze
68
- NATIVELY_PACKAGED_APACHE2_MODULE = "/usr/lib/apache2/modules/mod_passenger.so".freeze
69
-
70
65
  # Follows the logic of ext/common/ResourceLocator.h, so don't forget to modify that too.
71
66
  def self.locate_directories(source_root_or_location_configuration_file = nil)
72
67
  source_root_or_location_configuration_file ||= find_location_configuration_file
@@ -93,8 +88,10 @@ module PhusionPassenger
93
88
  @natively_packaged = get_bool_option(filename, options, 'natively_packaged')
94
89
  @bin_dir = get_option(filename, options, 'bin').freeze
95
90
  @agents_dir = get_option(filename, options, 'agents').freeze
91
+ @lib_dir = get_option(filename, options, 'libdir').freeze
96
92
  @helper_scripts_dir = get_option(filename, options, 'helper_scripts').freeze
97
93
  @resources_dir = get_option(filename, options, 'resources').freeze
94
+ @include_dir = get_option(filename, options, 'includedir').freeze
98
95
  @doc_dir = get_option(filename, options, 'doc').freeze
99
96
  @apache2_module_path = get_option(filename, options, 'apache2_module').freeze
100
97
  @ruby_extension_source_dir = get_option(filename, options, 'ruby_extension_source').freeze
@@ -103,8 +100,10 @@ module PhusionPassenger
103
100
  @natively_packaged = false
104
101
  @bin_dir = "#{@source_root}/bin".freeze
105
102
  @agents_dir = "#{@source_root}/agents".freeze
103
+ @lib_dir = "#{@source_root}/libout".freeze
106
104
  @helper_scripts_dir = "#{@source_root}/helper-scripts".freeze
107
105
  @resources_dir = "#{@source_root}/resources".freeze
106
+ @include_dir = "#{@source_root}/ext".freeze
108
107
  @doc_dir = "#{@source_root}/doc".freeze
109
108
  @apache2_module_path = "#{@source_root}/libout/apache2/mod_passenger.so".freeze
110
109
  @ruby_extension_source_dir = "#{@source_root}/ext/ruby"
@@ -134,6 +133,10 @@ module PhusionPassenger
134
133
  def self.agents_dir
135
134
  return @agents_dir
136
135
  end
136
+
137
+ def self.lib_dir
138
+ return @lib_dir
139
+ end
137
140
 
138
141
  def self.helper_scripts_dir
139
142
  return @helper_scripts_dir
@@ -142,6 +145,10 @@ module PhusionPassenger
142
145
  def self.resources_dir
143
146
  return @resources_dir
144
147
  end
148
+
149
+ def self.include_dir
150
+ return @include_dir
151
+ end
145
152
 
146
153
  def self.doc_dir
147
154
  return @doc_dir
@@ -39,7 +39,7 @@ class ServerInstance
39
39
 
40
40
  DIR_STRUCTURE_MAJOR_VERSION = 1
41
41
  DIR_STRUCTURE_MINOR_VERSION = 0
42
- GENERATION_STRUCTURE_MAJOR_VERSION = 1
42
+ GENERATION_STRUCTURE_MAJOR_VERSION = 2
43
43
  GENERATION_STRUCTURE_MINOR_VERSION = 0
44
44
 
45
45
  STALE_TIME_THRESHOLD = 60
@@ -214,7 +214,7 @@ class ServerInstance
214
214
  username = role_or_username
215
215
  end
216
216
 
217
- @client = MessageClient.new(username, password, "unix:#{@generation_path}/socket")
217
+ @client = MessageClient.new(username, password, "unix:#{@generation_path}/helper_admin")
218
218
  begin
219
219
  yield self
220
220
  ensure
@@ -408,7 +408,6 @@ COMMON_LIBRARY = CommonLibraryBuilder.new do
408
408
  :category => :other,
409
409
  :deps => %w(
410
410
  AgentsStarter.h
411
- AgentsStarter.hpp
412
411
  ResourceLocator.h
413
412
  MessageClient.h
414
413
  ServerInstanceDir.h
@@ -323,8 +323,17 @@ public
323
323
  #
324
324
  # This function exists because system('which') doesn't always behave
325
325
  # correctly, for some weird reason.
326
- def self.find_command(name)
326
+ #
327
+ # When `is_executable` is true, this function checks whether
328
+ # there is an executable named `name` in $PATH. When false, it
329
+ # assumes that `name` is not an executable name but a command string
330
+ # (e.g. "ccache gcc"). It then infers the executable name ("ccache")
331
+ # from the command string, and checks for that instead.
332
+ def self.find_command(name, is_executable = true)
327
333
  name = name.to_s
334
+ if !is_executable && name =~ / /
335
+ name = name.sub(/ .*/, '')
336
+ end
328
337
  if name =~ /^\//
329
338
  if File.executable?(name)
330
339
  return name
@@ -124,8 +124,8 @@ module Depcheck
124
124
  @checker = block
125
125
  end
126
126
 
127
- def check_for_command(name)
128
- result = find_command(name)
127
+ def check_for_command(name, *args)
128
+ result = find_command(name, *args)
129
129
  if result
130
130
  { :found => true,
131
131
  "Location" => result }
@@ -270,8 +270,8 @@ module Depcheck
270
270
  PlatformInfo.gem_command
271
271
  end
272
272
 
273
- def find_command(command)
274
- PlatformInfo.find_command(command)
273
+ def find_command(command, *args)
274
+ PlatformInfo.find_command(command, *args)
275
275
  end
276
276
 
277
277
  def linux_distro_tags
@@ -3,7 +3,7 @@ define 'gcc' do
3
3
  website "http://gcc.gnu.org/"
4
4
  define_checker do
5
5
  require 'phusion_passenger/platform_info/compiler'
6
- check_for_command(PlatformInfo.cc)
6
+ check_for_command(PlatformInfo.cc, false)
7
7
  end
8
8
 
9
9
  on :debian do
@@ -28,7 +28,7 @@ define 'g++' do
28
28
  website "http://gcc.gnu.org/"
29
29
  define_checker do
30
30
  require 'phusion_passenger/platform_info/compiler'
31
- check_for_command(PlatformInfo.cxx)
31
+ check_for_command(PlatformInfo.cxx, false)
32
32
  end
33
33
 
34
34
  on :debian do
@@ -130,6 +130,13 @@ module PlatformInfo
130
130
  RUBY_ENGINE != "macruby" &&
131
131
  rb_config['target_os'] !~ /mswin|windows|mingw/
132
132
  end
133
+
134
+ # Returns whether Phusion Passenger needs Ruby development headers to
135
+ # be available for the current Ruby implementation.
136
+ def self.passenger_needs_ruby_dev_header?
137
+ # Too much of a trouble for JRuby. We can do without it.
138
+ return RUBY_ENGINE != "jruby"
139
+ end
133
140
 
134
141
  # Returns the correct 'gem' command for this Ruby interpreter.
135
142
  def self.gem_command
@@ -30,7 +30,6 @@ require 'phusion_passenger/public_api'
30
30
  require 'phusion_passenger/message_client'
31
31
  require 'phusion_passenger/debug_logging'
32
32
  require 'phusion_passenger/utils'
33
- require 'phusion_passenger/utils/robust_interruption'
34
33
  require 'phusion_passenger/utils/tmpdir'
35
34
  require 'phusion_passenger/ruby_core_enhancements'
36
35
  require 'phusion_passenger/request_handler/thread_handler'
@@ -70,10 +69,6 @@ class RequestHandler
70
69
 
71
70
  attr_reader :concurrency
72
71
 
73
- # The number of times the main loop has iterated so far. Mostly useful
74
- # for unit test assertions.
75
- attr_reader :iterations
76
-
77
72
  # If a soft termination signal was received, then the main loop will quit
78
73
  # the given amount of seconds after the last time a connection was accepted.
79
74
  # Defaults to 3 seconds.
@@ -139,7 +134,6 @@ class RequestHandler
139
134
  @main_loop_thread_cond = ConditionVariable.new
140
135
  @threads = []
141
136
  @threads_mutex = Mutex.new
142
- @iterations = 0
143
137
  @soft_termination_linger_time = 3
144
138
  @main_loop_running = false
145
139
 
@@ -203,9 +197,9 @@ class RequestHandler
203
197
  end
204
198
 
205
199
  install_useful_signal_handlers
206
- RobustInterruption.install
207
200
  start_threads
208
- wait_until_termination
201
+ wait_until_termination_requested
202
+ wait_until_all_threads_are_idle
209
203
  terminate_threads
210
204
  debug("Request handler main loop exited normally")
211
205
 
@@ -440,17 +434,14 @@ private
440
434
  @concurrency.times do |i|
441
435
  thread = Thread.new(i) do |number|
442
436
  Thread.current.abort_on_exception = true
443
- RobustInterruption.install
444
- RobustInterruption.disable_interruptions do
445
- begin
446
- Thread.current[:name] = "Worker #{number + 1}"
447
- handler = thread_handler.new(self, main_socket_options)
448
- handler.install
449
- handler.main_loop(set_initialization_state_to_true)
450
- ensure
451
- set_initialization_state.call(false)
452
- unregister_current_thread
453
- end
437
+ begin
438
+ Thread.current[:name] = "Worker #{number + 1}"
439
+ handler = thread_handler.new(self, main_socket_options)
440
+ handler.install
441
+ handler.main_loop(set_initialization_state_to_true)
442
+ ensure
443
+ set_initialization_state.call(false)
444
+ unregister_current_thread
454
445
  end
455
446
  end
456
447
  @threads << thread
@@ -459,17 +450,14 @@ private
459
450
 
460
451
  thread = Thread.new do
461
452
  Thread.current.abort_on_exception = true
462
- RobustInterruption.install
463
- RobustInterruption.disable_interruptions do
464
- begin
465
- Thread.current[:name] = "HTTP helper worker"
466
- handler = thread_handler.new(self, http_socket_options)
467
- handler.install
468
- handler.main_loop(set_initialization_state_to_true)
469
- ensure
470
- set_initialization_state.call(false)
471
- unregister_current_thread
472
- end
453
+ begin
454
+ Thread.current[:name] = "HTTP helper worker"
455
+ handler = thread_handler.new(self, http_socket_options)
456
+ handler.install
457
+ handler.main_loop(set_initialization_state_to_true)
458
+ ensure
459
+ set_initialization_state.call(false)
460
+ unregister_current_thread
473
461
  end
474
462
  end
475
463
  @threads << thread
@@ -490,7 +478,7 @@ private
490
478
  end
491
479
  end
492
480
 
493
- def wait_until_termination
481
+ def wait_until_termination_requested
494
482
  ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
495
483
  if ruby_engine == "jruby"
496
484
  # On JRuby, selecting on an input TTY always returns, so
@@ -528,32 +516,121 @@ private
528
516
  end
529
517
  end
530
518
 
531
- def terminate_threads
532
- debug("Stopping all threads")
533
- done = false
534
- while !done
519
+ def wakeup_all_threads
520
+ threads = []
521
+ if get_socket_address_type(@server_sockets[:main][:address]) == :unix &&
522
+ !File.exist?(@server_sockets[:main][:address].sub(/^unix:/, ''))
523
+ # It looks like someone deleted the Unix domain socket we listen on.
524
+ # This makes it impossible to wake up the worker threads gracefully,
525
+ # so we hard kill them.
526
+ warn("Unix domain socket gone; force aborting all threads")
535
527
  @threads_mutex.synchronize do
536
528
  @threads.each do |thread|
537
- Utils::RobustInterruption.raise(thread)
529
+ thread.raise(RuntimeError.new("Force abort"))
530
+ end
531
+ end
532
+ else
533
+ @concurrency.times do
534
+ Thread.abort_on_exception = true
535
+ threads << Thread.new(@server_sockets[:main][:address]) do |address|
536
+ begin
537
+ debug("Shutting down worker thread by connecting to #{address}")
538
+ connect_to_server(address).close
539
+ rescue Errno::ECONNREFUSED
540
+ debug("Worker thread listening on #{address} already exited")
541
+ rescue SystemCallError, IOError => e
542
+ debug("Error shutting down worker thread (#{address}): #{e} (#{e.class})")
543
+ end
538
544
  end
539
- done = @threads.empty?
540
545
  end
541
- sleep 0.02 if !done
546
+ end
547
+ threads << Thread.new(@server_sockets[:http][:address]) do |address|
548
+ Thread.abort_on_exception = true
549
+ begin
550
+ debug("Shutting down HTTP thread by connecting to #{address}")
551
+ connect_to_server(address).close
552
+ rescue Errno::ECONNREFUSED
553
+ debug("Worker thread listening on #{address} already exited")
554
+ rescue SystemCallError, IOError => e
555
+ debug("Error shutting down HTTP thread (#{address}): #{e} (#{e.class})")
556
+ end
557
+ end
558
+ return threads
559
+ end
560
+
561
+ def terminate_threads
562
+ debug("Stopping all threads")
563
+ threads = @threads_mutex.synchronize do
564
+ @threads.dup
565
+ end
566
+ threads.each do |thr|
567
+ thr.raise(ThreadHandler::Interrupted.new)
568
+ end
569
+ threads.each do |thr|
570
+ thr.join
542
571
  end
543
572
  debug("All threads stopped")
544
573
  end
545
574
 
546
575
  def wait_until_all_threads_are_idle
547
576
  debug("Waiting until all threads have become idle...")
577
+
578
+ # We wait until 100 ms have passed since all handlers have become
579
+ # interruptable and remained in the same iterations.
580
+
548
581
  done = false
582
+
549
583
  while !done
550
- @threads_mutex.synchronize do
551
- done = @threads.all? do |thread|
552
- thread[:handler].idle?
584
+ handlers = @threads_mutex.synchronize do
585
+ @threads.map do |thr|
586
+ thr[:passenger_thread_handler]
587
+ end
588
+ end
589
+ debug("There are currently #{handlers.size} threads")
590
+ if handlers.empty?
591
+ # There are no threads, so we're done.
592
+ done = true
593
+ break
594
+ end
595
+
596
+ # Record initial state.
597
+ handlers.each { |h| h.stats_mutex.lock }
598
+ iterations = handlers.map { |h| h.iteration }
599
+ handlers.each { |h| h.stats_mutex.unlock }
600
+
601
+ start_time = Time.now
602
+ sleep 0.01
603
+
604
+ while true
605
+ if handlers.size != @threads_mutex.synchronize { @threads.size }
606
+ debug("The number of threads changed. Restarting waiting algorithm")
607
+ break
608
+ end
609
+
610
+ # Record current state.
611
+ handlers.each { |h| h.stats_mutex.lock }
612
+ all_interruptable = handlers.all? { |h| h.interruptable }
613
+ new_iterations = handlers.map { |h| h.iteration }
614
+
615
+ # Are all threads interruptable and has there been no activity
616
+ # since last time we checked?
617
+ if all_interruptable && new_iterations == iterations
618
+ # Yes. If enough time has passed then we're done.
619
+ handlers.each { |h| h.stats_mutex.unlock }
620
+ if Time.now >= start_time + 0.1
621
+ done = true
622
+ break
623
+ end
624
+ else
625
+ # No. We reset the timer and check again later.
626
+ handlers.each { |h| h.stats_mutex.unlock }
627
+ iterations = new_iterations
628
+ start_time = Time.now
629
+ sleep 0.01
553
630
  end
554
631
  end
555
- sleep 0.02 if !done
556
632
  end
633
+
557
634
  debug("All threads are now idle")
558
635
  end
559
636
  end