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.
- data.tar.gz.asc +7 -7
- data/NEWS +27 -0
- data/bin/passenger-config +6 -3
- data/bin/passenger-install-apache2-module +2 -2
- data/bin/passenger-install-nginx-module +16 -2
- data/build/agents.rb +4 -0
- data/build/apache2.rb +1 -1
- data/build/cplusplus_support.rb +1 -1
- data/build/cxx_tests.rb +3 -0
- data/build/packaging.rb +51 -8
- data/build/ruby_extension.rb +1 -1
- data/doc/Packaging.txt.md +20 -7
- data/doc/Users guide Apache.html +1 -1
- data/doc/Users guide Apache.txt +1 -1
- data/doc/Users guide Nginx.html +5 -4
- data/doc/Users guide Nginx.txt +1 -1
- data/doc/users_guide_snippets/installation.txt +5 -3
- data/ext/apache2/Configuration.cpp +12 -0
- data/ext/apache2/Configuration.hpp +7 -4
- data/ext/apache2/Hooks.cpp +29 -19
- data/ext/common/AgentsStarter.cpp +85 -57
- data/ext/common/AgentsStarter.h +570 -42
- data/ext/common/ApplicationPool2/DirectSpawner.h +5 -2
- data/ext/common/ApplicationPool2/Implementation.cpp +7 -1
- data/ext/common/ApplicationPool2/Pool.h +6 -3
- data/ext/common/ApplicationPool2/Process.h +12 -3
- data/ext/common/ApplicationPool2/SmartSpawner.h +2 -1
- data/ext/common/Constants.h +4 -1
- data/ext/common/EventedBufferedInput.h +139 -16
- data/ext/common/MultiLibeio.cpp +4 -2
- data/ext/common/SafeLibev.h +15 -62
- data/ext/common/ServerInstanceDir.h +10 -26
- data/ext/common/Utils.cpp +1 -3
- data/ext/common/Utils.h +1 -1
- data/ext/common/Utils/StrIntUtils.cpp +9 -0
- data/ext/common/Utils/StrIntUtils.h +5 -0
- data/ext/common/Utils/VariantMap.h +63 -14
- data/ext/common/agents/Base.cpp +50 -15
- data/ext/common/agents/HelperAgent/AgentOptions.h +20 -12
- data/ext/common/agents/HelperAgent/FileBackedPipe.h +1 -1
- data/ext/common/agents/HelperAgent/Main.cpp +5 -4
- data/ext/common/agents/HelperAgent/RequestHandler.h +1 -1
- data/ext/common/agents/LoggingAgent/Main.cpp +0 -1
- data/ext/common/agents/LoggingAgent/RemoteSender.h +2 -2
- data/ext/common/agents/SpawnPreparer.cpp +23 -5
- data/ext/common/agents/Watchdog/AgentWatcher.cpp +508 -0
- data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +93 -0
- data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +68 -0
- data/ext/common/agents/Watchdog/Main.cpp +180 -802
- data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +111 -0
- data/ext/nginx/Configuration.c +107 -92
- data/ext/nginx/Configuration.h +1 -0
- data/ext/nginx/ContentHandler.c +6 -6
- data/ext/nginx/ContentHandler.h +1 -1
- data/ext/nginx/config +8 -2
- data/ext/nginx/ngx_http_passenger_module.c +54 -60
- data/ext/nginx/ngx_http_passenger_module.h +6 -6
- data/lib/phusion_passenger.rb +17 -10
- data/lib/phusion_passenger/admin_tools/server_instance.rb +2 -2
- data/lib/phusion_passenger/common_library.rb +0 -1
- data/lib/phusion_passenger/platform_info.rb +10 -1
- data/lib/phusion_passenger/platform_info/depcheck.rb +4 -4
- data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +2 -2
- data/lib/phusion_passenger/platform_info/ruby.rb +7 -0
- data/lib/phusion_passenger/request_handler.rb +119 -42
- data/lib/phusion_passenger/request_handler/thread_handler.rb +25 -22
- data/lib/phusion_passenger/standalone/command.rb +2 -0
- data/lib/phusion_passenger/standalone/runtime_installer.rb +4 -3
- data/lib/phusion_passenger/standalone/start_command.rb +49 -37
- data/resources/templates/nginx/pcre_checksum_could_not_be_verified.txt.erb +11 -0
- data/test/cxx/CxxTestMain.cpp +2 -0
- data/test/cxx/EventedBufferedInputTest.cpp +758 -0
- data/test/cxx/ServerInstanceDirTest.cpp +16 -31
- data/test/cxx/TestSupport.cpp +2 -1
- data/test/cxx/VariantMapTest.cpp +23 -11
- metadata +8 -4
- metadata.gz.asc +7 -7
- data/ext/common/AgentsStarter.hpp +0 -655
- 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
|
53
|
-
ngx_str_t
|
54
|
-
ngx_str_t
|
55
|
-
PassengerCachedFileStat
|
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
|
-
|
58
|
-
ngx_cycle_t
|
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
|
-
|
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 =
|
288
|
-
|
289
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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 "
|
34
|
-
#include "
|
35
|
-
#include "
|
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
|
58
|
+
extern PassengerCachedFileStat *passenger_stat_cache;
|
59
59
|
|
60
60
|
extern PassengerAppTypeDetector *passenger_app_type_detector;
|
61
61
|
|
62
|
-
extern
|
62
|
+
extern PSG_AgentsStarter *passenger_agents_starter;
|
63
63
|
|
64
|
-
extern ngx_cycle_t
|
64
|
+
extern ngx_cycle_t *passenger_current_cycle;
|
65
65
|
|
66
66
|
#endif /* _PASSENGER_NGINX_MODULE_H_ */
|
67
67
|
|
data/lib/phusion_passenger.rb
CHANGED
@@ -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.
|
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 =
|
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}/
|
217
|
+
@client = MessageClient.new(username, password, "unix:#{@generation_path}/helper_admin")
|
218
218
|
begin
|
219
219
|
yield self
|
220
220
|
ensure
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
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
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
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
|
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
|
532
|
-
|
533
|
-
|
534
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
552
|
-
|
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
|