passenger 4.0.48 → 4.0.49
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.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/.editorconfig +36 -2
- data/.travis.yml +1 -1
- data/CHANGELOG +16 -0
- data/Rakefile +0 -1
- data/build/apache2.rb +4 -4
- data/build/common_library.rb +18 -18
- data/build/cplusplus_support.rb +2 -2
- data/build/documentation.rb +1 -1
- data/build/integration_tests.rb +12 -4
- data/build/misc.rb +12 -7
- data/build/packaging.rb +14 -14
- data/build/preprocessor.rb +10 -10
- data/build/rake_extensions.rb +11 -11
- data/build/ruby_extension.rb +2 -2
- data/dev/ci/inituidgid +24 -0
- data/dev/ci/run_jenkins.sh +57 -0
- data/dev/ci/run_rpm_tests.sh +77 -0
- data/dev/{run_travis.sh → ci/run_travis.sh} +60 -4
- data/doc/Users guide Nginx.txt +2 -2
- data/doc/users_guide_snippets/environment_variables.txt +0 -2
- data/doc/users_guide_snippets/tips.txt +20 -1
- data/ext/apache2/Bucket.cpp +18 -18
- data/ext/apache2/Bucket.h +4 -4
- data/ext/apache2/Configuration.cpp +7 -7
- data/ext/apache2/Configuration.hpp +43 -43
- data/ext/apache2/DirectoryMapper.h +5 -5
- data/ext/apache2/Hooks.cpp +142 -142
- data/ext/apache2/MergeDirConfig.cpp +40 -40
- data/ext/common/Account.h +17 -17
- data/ext/common/AccountsDatabase.h +9 -9
- data/ext/common/AgentsStarter.cpp +2 -2
- data/ext/common/AgentsStarter.h +40 -40
- data/ext/common/ApplicationPool2/Common.h +10 -6
- data/ext/common/ApplicationPool2/ComponentInfo.h +2 -2
- data/ext/common/ApplicationPool2/DirectSpawner.h +17 -17
- data/ext/common/ApplicationPool2/DummySpawner.h +5 -5
- data/ext/common/ApplicationPool2/Group.h +54 -38
- data/ext/common/ApplicationPool2/Implementation.cpp +76 -49
- data/ext/common/ApplicationPool2/Options.h +98 -91
- data/ext/common/ApplicationPool2/Pool.h +70 -69
- data/ext/common/ApplicationPool2/Process.h +21 -21
- data/ext/common/ApplicationPool2/Session.h +11 -11
- data/ext/common/ApplicationPool2/SmartSpawner.h +60 -60
- data/ext/common/ApplicationPool2/Socket.h +19 -19
- data/ext/common/ApplicationPool2/Spawner.h +64 -72
- data/ext/common/ApplicationPool2/SpawnerFactory.h +4 -4
- data/ext/common/ApplicationPool2/SuperGroup.h +41 -41
- data/ext/common/BackgroundEventLoop.cpp +1 -1
- data/ext/common/BackgroundEventLoop.h +2 -2
- data/ext/common/Constants.h +1 -1
- data/ext/common/EventedBufferedInput.h +5 -5
- data/ext/common/EventedClient.h +51 -51
- data/ext/common/EventedMessageServer.h +39 -39
- data/ext/common/EventedServer.h +32 -32
- data/ext/common/Exceptions.h +23 -23
- data/ext/common/FileDescriptor.h +18 -18
- data/ext/common/Logging.cpp +1 -1
- data/ext/common/MessageClient.h +27 -27
- data/ext/common/MessageReadersWriters.h +79 -79
- data/ext/common/MessageServer.h +59 -59
- data/ext/common/RandomGenerator.h +12 -12
- data/ext/common/ResourceLocator.h +8 -8
- data/ext/common/SafeLibev.h +54 -25
- data/ext/common/ServerInstanceDir.h +31 -31
- data/ext/common/StaticString.h +50 -48
- data/ext/common/Utils.cpp +73 -78
- data/ext/common/Utils.h +6 -6
- data/ext/common/Utils/Base64.cpp +3 -3
- data/ext/common/Utils/Base64.h +7 -7
- data/ext/common/Utils/BlockingQueue.h +9 -9
- data/ext/common/Utils/BufferedIO.h +17 -17
- data/ext/common/Utils/CachedFileStat.hpp +16 -16
- data/ext/common/Utils/Dechunker.h +25 -25
- data/ext/common/Utils/FileChangeChecker.h +10 -10
- data/ext/common/Utils/MemZeroGuard.h +5 -5
- data/ext/common/Utils/MemoryBarrier.h +1 -1
- data/ext/common/Utils/MessageIO.h +61 -61
- data/ext/common/Utils/ProcessMetricsCollector.h +40 -40
- data/ext/common/Utils/ScopeGuard.h +7 -7
- data/ext/common/Utils/SpeedMeter.h +1 -1
- data/ext/common/Utils/StrIntUtils.cpp +13 -13
- data/ext/common/Utils/StrIntUtils.h +3 -3
- data/ext/common/Utils/StringScanning.h +5 -5
- data/ext/common/Utils/SystemMetricsCollector.h +2 -2
- data/ext/common/Utils/SystemTime.h +10 -10
- data/ext/common/Utils/Template.h +2 -2
- data/ext/common/Utils/Timer.h +6 -6
- data/ext/common/Utils/VariantMap.h +29 -29
- data/ext/common/agents/Base.cpp +19 -19
- data/ext/common/agents/HelperAgent/AgentOptions.h +1 -1
- data/ext/common/agents/HelperAgent/FileBackedPipe.h +6 -6
- data/ext/common/agents/HelperAgent/Main.cpp +44 -43
- data/ext/common/agents/HelperAgent/RequestHandler.cpp +4 -4
- data/ext/common/agents/HelperAgent/RequestHandler.h +29 -28
- data/ext/common/agents/HelperAgent/ScgiRequestParser.h +56 -50
- data/ext/common/agents/LoggingAgent/AdminController.h +8 -8
- data/ext/common/agents/LoggingAgent/DataStoreId.h +17 -17
- data/ext/common/agents/LoggingAgent/FilterSupport.h +167 -167
- data/ext/common/agents/LoggingAgent/LoggingServer.h +122 -122
- data/ext/common/agents/LoggingAgent/Main.cpp +7 -7
- data/ext/common/agents/LoggingAgent/RemoteSender.h +54 -54
- data/ext/common/agents/SpawnPreparer.cpp +4 -4
- data/ext/common/agents/TempDirToucher.c +2 -2
- data/ext/common/agents/Watchdog/AgentWatcher.cpp +47 -47
- data/ext/common/agents/Watchdog/HelperAgentWatcher.cpp +7 -7
- data/ext/common/agents/Watchdog/LoggingAgentWatcher.cpp +7 -7
- data/ext/common/agents/Watchdog/Main.cpp +22 -22
- data/ext/common/agents/Watchdog/ServerInstanceDirToucher.cpp +9 -9
- data/ext/libeio/eio.c +1 -1
- data/ext/nginx/Configuration.c +30 -30
- data/ext/nginx/Configuration.h +1 -1
- data/ext/nginx/ContentHandler.c +54 -54
- data/ext/nginx/ContentHandler.h +3 -3
- data/ext/nginx/StaticContentHandler.c +2 -2
- data/ext/nginx/ngx_http_passenger_module.c +21 -21
- data/ext/oxt/detail/backtrace_enabled.hpp +1 -1
- data/ext/oxt/detail/context.hpp +1 -1
- data/ext/oxt/detail/spin_lock_darwin.hpp +4 -4
- data/ext/oxt/detail/spin_lock_gcc_x86.hpp +3 -3
- data/ext/oxt/detail/spin_lock_pthreads.hpp +4 -4
- data/ext/oxt/detail/tracable_exception_disabled.hpp +1 -1
- data/ext/oxt/dynamic_thread_group.hpp +18 -18
- data/ext/oxt/implementation.cpp +9 -8
- data/ext/oxt/macros.hpp +2 -2
- data/ext/oxt/system_calls.cpp +11 -11
- data/ext/oxt/system_calls.hpp +13 -13
- data/ext/oxt/thread.hpp +22 -14
- data/ext/ruby/passenger_native_support.c +55 -55
- data/lib/phusion_passenger.rb +24 -24
- data/lib/phusion_passenger/common_library.rb +2 -0
- data/lib/phusion_passenger/loader_shared_helpers.rb +18 -18
- data/lib/phusion_passenger/packaging.rb +9 -4
- data/lib/phusion_passenger/platform_info/apache.rb +45 -31
- data/lib/phusion_passenger/platform_info/compiler.rb +11 -11
- data/lib/phusion_passenger/rack/thread_handler_extension.rb +1 -1
- data/lib/phusion_passenger/request_handler/thread_handler.rb +8 -8
- data/lib/phusion_passenger/standalone/app_finder.rb +16 -16
- data/lib/phusion_passenger/standalone/command.rb +22 -22
- data/packaging/rpm/LICENSE.txt +19 -0
- data/packaging/rpm/Makefile +13 -0
- data/packaging/rpm/README.md +41 -0
- data/packaging/rpm/Vagrantfile +38 -0
- data/{rpm/Vagrantfile → packaging/rpm/Vagrantfile.centos} +0 -0
- data/packaging/rpm/build +170 -0
- data/packaging/rpm/create_project +41 -0
- data/packaging/rpm/git_update +88 -0
- data/packaging/rpm/image/Dockerfile +37 -0
- data/packaging/rpm/image/Gemfile +3 -0
- data/packaging/rpm/image/Gemfile.lock +12 -0
- data/packaging/rpm/image/RPM-GPG-KEY-amazon-ga +19 -0
- data/packaging/rpm/image/amazon2014-i386.cfg +96 -0
- data/packaging/rpm/image/amazon2014-x86_64.cfg +96 -0
- data/packaging/rpm/image/site-defaults.cfg +168 -0
- data/packaging/rpm/internal/build_tasks.rb +238 -0
- data/packaging/rpm/internal/dummygpg +11 -0
- data/packaging/rpm/internal/exec_build +42 -0
- data/packaging/rpm/internal/get_distro_arch +14 -0
- data/packaging/rpm/internal/get_distro_id +10 -0
- data/packaging/rpm/internal/git_update +27 -0
- data/packaging/rpm/internal/inituidgid +17 -0
- data/packaging/rpm/internal/my_init +344 -0
- data/packaging/rpm/internal/python27 +3 -0
- data/packaging/rpm/internal/repo_update +46 -0
- data/packaging/rpm/internal/setuser +26 -0
- data/packaging/rpm/internal/tracking_helper +40 -0
- data/packaging/rpm/jenkins_release +99 -0
- data/packaging/rpm/lib/build_tasks_support.rb +402 -0
- data/packaging/rpm/lib/preprocessor.rb +341 -0
- data/packaging/rpm/nginx_spec/404.html +119 -0
- data/packaging/rpm/nginx_spec/50x.html +119 -0
- data/packaging/rpm/nginx_spec/index.html +116 -0
- data/packaging/rpm/nginx_spec/nginx-auto-cc-gcc.patch +13 -0
- data/packaging/rpm/nginx_spec/nginx-logo.png +0 -0
- data/packaging/rpm/nginx_spec/nginx-upgrade +13 -0
- data/packaging/rpm/nginx_spec/nginx-upgrade.8 +151 -0
- data/packaging/rpm/nginx_spec/nginx.conf +131 -0
- data/packaging/rpm/nginx_spec/nginx.init +144 -0
- data/packaging/rpm/nginx_spec/nginx.logrotate +13 -0
- data/packaging/rpm/nginx_spec/nginx.service +15 -0
- data/packaging/rpm/nginx_spec/nginx.spec.template +559 -0
- data/packaging/rpm/nginx_spec/nginx.sysconfig +4 -0
- data/packaging/rpm/nginx_spec/passenger.conf +9 -0
- data/packaging/rpm/nginx_spec/poweredby.png +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/apache-passenger.conf.in +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/config.json +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/passenger.logrotate +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/passenger.spec.template +58 -31
- data/{rpm → packaging/rpm/passenger_spec}/passenger_dynamic_thread_group.patch +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/passenger_tests_default_config_example.patch +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-GLIBC_HAVE_LONG_LONG.patch +0 -0
- data/{rpm → packaging/rpm/passenger_spec}/rubygem-passenger-4.0.18-gcc47-include-sys_types.patch +0 -0
- data/packaging/rpm/repo_update +114 -0
- data/packaging/rpm/setup-system +60 -0
- data/packaging/rpm/shell +10 -0
- data/resources/templates/standalone/config.erb +3 -1
- data/test/config.json.rpm-automation +1 -1
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +11 -11
- data/test/cxx/ApplicationPool2/OptionsTest.cpp +5 -5
- data/test/cxx/ApplicationPool2/PoolTest.cpp +129 -89
- data/test/cxx/ApplicationPool2/ProcessTest.cpp +15 -15
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +22 -22
- data/test/cxx/ApplicationPool2/SpawnerTestCases.cpp +11 -11
- data/test/cxx/ScgiRequestParserTest.cpp +75 -61
- data/test/cxx/UtilsTest.cpp +86 -85
- data/test/gdbinit.example +3 -0
- data/test/integration_tests/nginx_tests.rb +3 -3
- data/test/integration_tests/source_packaging_test.rb +3 -1
- data/test/stub/nginx/nginx.conf.erb +8 -1
- data/test/support/nginx_controller.rb +7 -7
- metadata +62 -17
- metadata.gz.asc +7 -7
- data/build/rpm.rb +0 -128
- data/dev/rpmtool +0 -21
- data/dev/test_rpm_packaging.sh +0 -28
- data/rpm/get_distro_id.py +0 -4
@@ -69,11 +69,11 @@ public:
|
|
69
69
|
return *it;
|
70
70
|
}
|
71
71
|
}
|
72
|
-
|
72
|
+
|
73
73
|
ProcessPtr &operator[](unsigned int index) {
|
74
74
|
return get(index);
|
75
75
|
}
|
76
|
-
|
76
|
+
|
77
77
|
iterator last_iterator() {
|
78
78
|
if (empty()) {
|
79
79
|
return end();
|
@@ -128,7 +128,7 @@ class Process: public boost::enable_shared_from_this<Process> {
|
|
128
128
|
// Actually private, but marked public so that unit tests can access the fields.
|
129
129
|
public:
|
130
130
|
friend class Group;
|
131
|
-
|
131
|
+
|
132
132
|
/** A mutex to protect access to `lifeStatus`. */
|
133
133
|
mutable boost::mutex lifetimeSyncher;
|
134
134
|
|
@@ -137,11 +137,11 @@ public:
|
|
137
137
|
* Read-only; only set once during initialization.
|
138
138
|
*/
|
139
139
|
boost::weak_ptr<Group> group;
|
140
|
-
|
140
|
+
|
141
141
|
/** A subset of 'sockets': all sockets that speak the
|
142
142
|
* "session" protocol, sorted by socket.busyness(). */
|
143
143
|
PriorityQueue<Socket> sessionSockets;
|
144
|
-
|
144
|
+
|
145
145
|
/** The iterator inside the associated Group's process list. */
|
146
146
|
ProcessList::iterator it;
|
147
147
|
/** The handle inside the associated Group's process priority queue. */
|
@@ -201,13 +201,13 @@ public:
|
|
201
201
|
concurrency = 0;
|
202
202
|
}
|
203
203
|
}
|
204
|
-
|
204
|
+
|
205
205
|
public:
|
206
206
|
/*************************************************************
|
207
207
|
* Read-only fields, set once during initialization and never
|
208
208
|
* written to again. Reading is thread-safe.
|
209
209
|
*************************************************************/
|
210
|
-
|
210
|
+
|
211
211
|
/** Process PID. */
|
212
212
|
pid_t pid;
|
213
213
|
/** An ID that uniquely identifies this Process in the Group, for
|
@@ -245,13 +245,13 @@ public:
|
|
245
245
|
* processes are never added to Group.enabledProcesses.
|
246
246
|
*/
|
247
247
|
bool requiresShutdown;
|
248
|
-
|
248
|
+
|
249
249
|
/*************************************************************
|
250
250
|
* Information used by Pool. Do not write to these from
|
251
251
|
* outside the Pool. If you read these make sure the Pool
|
252
252
|
* isn't concurrently modifying.
|
253
253
|
*************************************************************/
|
254
|
-
|
254
|
+
|
255
255
|
/** Time at which we finished spawning this process, i.e. when this
|
256
256
|
* process was finished initializing. Microseconds resolution.
|
257
257
|
*/
|
@@ -319,7 +319,7 @@ public:
|
|
319
319
|
time_t shutdownStartTime;
|
320
320
|
/** Collected by Pool::collectAnalytics(). */
|
321
321
|
ProcessMetrics metrics;
|
322
|
-
|
322
|
+
|
323
323
|
Process(pid_t _pid,
|
324
324
|
const string &_gupid,
|
325
325
|
const string &_connectPassword,
|
@@ -365,15 +365,15 @@ public:
|
|
365
365
|
watcher->initialize();
|
366
366
|
watcher->start();
|
367
367
|
}
|
368
|
-
|
368
|
+
|
369
369
|
if (OXT_LIKELY(sockets != NULL)) {
|
370
370
|
indexSessionSockets();
|
371
371
|
}
|
372
|
-
|
372
|
+
|
373
373
|
lastUsed = SystemTime::getUsec();
|
374
374
|
spawnEndTime = lastUsed;
|
375
375
|
}
|
376
|
-
|
376
|
+
|
377
377
|
~Process() {
|
378
378
|
if (OXT_UNLIKELY(!isDead() && requiresShutdown)) {
|
379
379
|
P_BUG("You must call Process::triggerShutdown() and Process::cleanup() before actually "
|
@@ -400,7 +400,7 @@ public:
|
|
400
400
|
assert(!isDead());
|
401
401
|
return group.lock();
|
402
402
|
}
|
403
|
-
|
403
|
+
|
404
404
|
void setGroup(const GroupPtr &group) {
|
405
405
|
assert(this->group.lock() == NULL || this->group.lock() == group);
|
406
406
|
this->group = group;
|
@@ -536,7 +536,7 @@ public:
|
|
536
536
|
return 0;
|
537
537
|
}
|
538
538
|
}
|
539
|
-
|
539
|
+
|
540
540
|
int busyness() const {
|
541
541
|
/* Different processes within a Group may have different
|
542
542
|
* 'concurrency' values. We want:
|
@@ -557,7 +557,7 @@ public:
|
|
557
557
|
return (int) (((long long) sessions * INT_MAX) / (double) concurrency);
|
558
558
|
}
|
559
559
|
}
|
560
|
-
|
560
|
+
|
561
561
|
/**
|
562
562
|
* Whether we've reached the maximum number of concurrent sessions for this
|
563
563
|
* process.
|
@@ -574,7 +574,7 @@ public:
|
|
574
574
|
bool canBeRoutedTo() const {
|
575
575
|
return !isTotallyBusy();
|
576
576
|
}
|
577
|
-
|
577
|
+
|
578
578
|
/**
|
579
579
|
* Create a new communication session with this process. This will connect to one
|
580
580
|
* of the session sockets or reuse an existing connection. See Session for
|
@@ -596,13 +596,13 @@ public:
|
|
596
596
|
return boost::make_shared<Session>(shared_from_this(), socket);
|
597
597
|
}
|
598
598
|
}
|
599
|
-
|
599
|
+
|
600
600
|
void sessionClosed(Session *session) {
|
601
601
|
Socket *socket = session->getSocket();
|
602
|
-
|
602
|
+
|
603
603
|
assert(socket->sessions > 0);
|
604
604
|
assert(sessions > 0);
|
605
|
-
|
605
|
+
|
606
606
|
socket->sessions--;
|
607
607
|
this->sessions--;
|
608
608
|
processed++;
|
@@ -636,7 +636,7 @@ public:
|
|
636
636
|
stream << "<last_used_desc>" << distanceOfTimeInWords(lastUsed / 1000000).c_str() << " ago</last_used_desc>";
|
637
637
|
stream << "<uptime>" << uptime() << "</uptime>";
|
638
638
|
if (!codeRevision.empty()) {
|
639
|
-
stream << "<code_revision>" << codeRevision << "</code_revision>";
|
639
|
+
stream << "<code_revision>" << escapeForXml(codeRevision) << "</code_revision>";
|
640
640
|
}
|
641
641
|
switch (lifeStatus) {
|
642
642
|
case ALIVE:
|
@@ -57,11 +57,11 @@ private:
|
|
57
57
|
ProcessPtr process;
|
58
58
|
/** Socket to use for this session. Guaranteed to be alive thanks to the 'process' reference. */
|
59
59
|
Socket *socket;
|
60
|
-
|
60
|
+
|
61
61
|
Connection connection;
|
62
62
|
FileDescriptor theFd;
|
63
63
|
bool closed;
|
64
|
-
|
64
|
+
|
65
65
|
void deinitiate(bool success) {
|
66
66
|
connection.fail = !success;
|
67
67
|
socket->checkinConnection(connection);
|
@@ -74,7 +74,7 @@ private:
|
|
74
74
|
onInitiateFailure(this);
|
75
75
|
}
|
76
76
|
}
|
77
|
-
|
77
|
+
|
78
78
|
void callOnClose() {
|
79
79
|
if (OXT_LIKELY(onClose != NULL)) {
|
80
80
|
onClose(this);
|
@@ -85,7 +85,7 @@ private:
|
|
85
85
|
public:
|
86
86
|
Callback onInitiateFailure;
|
87
87
|
Callback onClose;
|
88
|
-
|
88
|
+
|
89
89
|
Session(const ProcessPtr &_process, Socket *_socket)
|
90
90
|
: process(_process),
|
91
91
|
socket(_socket),
|
@@ -93,7 +93,7 @@ public:
|
|
93
93
|
onInitiateFailure(NULL),
|
94
94
|
onClose(NULL)
|
95
95
|
{ }
|
96
|
-
|
96
|
+
|
97
97
|
~Session() {
|
98
98
|
TRACE_POINT();
|
99
99
|
// If user doesn't close() explicitly, we penalize performance.
|
@@ -112,7 +112,7 @@ public:
|
|
112
112
|
const GroupPtr getGroup() const;
|
113
113
|
void requestOOBW();
|
114
114
|
int kill(int signo);
|
115
|
-
|
115
|
+
|
116
116
|
bool isClosed() const {
|
117
117
|
return closed;
|
118
118
|
}
|
@@ -125,7 +125,7 @@ public:
|
|
125
125
|
assert(!closed);
|
126
126
|
return process;
|
127
127
|
}
|
128
|
-
|
128
|
+
|
129
129
|
Socket *getSocket() const {
|
130
130
|
return socket;
|
131
131
|
}
|
@@ -133,7 +133,7 @@ public:
|
|
133
133
|
const string &getProtocol() const {
|
134
134
|
return socket->protocol;
|
135
135
|
}
|
136
|
-
|
136
|
+
|
137
137
|
void initiate() {
|
138
138
|
assert(!closed);
|
139
139
|
ScopeGuard g(boost::bind(&Session::callOnInitiateFailure, this));
|
@@ -142,15 +142,15 @@ public:
|
|
142
142
|
theFd = FileDescriptor(connection.fd, false);
|
143
143
|
g.clear();
|
144
144
|
}
|
145
|
-
|
145
|
+
|
146
146
|
bool initiated() const {
|
147
147
|
return connection.fd != -1;
|
148
148
|
}
|
149
|
-
|
149
|
+
|
150
150
|
const FileDescriptor &fd() const {
|
151
151
|
return theFd;
|
152
152
|
}
|
153
|
-
|
153
|
+
|
154
154
|
/**
|
155
155
|
* This Session object becomes fully unsable after closing.
|
156
156
|
*/
|
@@ -68,7 +68,7 @@ private:
|
|
68
68
|
const vector<string> preloaderCommand;
|
69
69
|
map<string, string> preloaderAnnotations;
|
70
70
|
Options options;
|
71
|
-
|
71
|
+
|
72
72
|
// Protects m_lastUsed and pid.
|
73
73
|
mutable boost::mutex simpleFieldSyncher;
|
74
74
|
// Protects everything else.
|
@@ -82,11 +82,11 @@ private:
|
|
82
82
|
// Upon starting the preloader, its preparation info is stored here
|
83
83
|
// for future reference.
|
84
84
|
SpawnPreparationInfo preparation;
|
85
|
-
|
85
|
+
|
86
86
|
string getPreloaderCommandString() const {
|
87
87
|
string result;
|
88
88
|
unsigned int i;
|
89
|
-
|
89
|
+
|
90
90
|
for (i = 0; i < preloaderCommand.size(); i++) {
|
91
91
|
if (i != 0) {
|
92
92
|
result.append(1, '\0');
|
@@ -95,13 +95,13 @@ private:
|
|
95
95
|
}
|
96
96
|
return result;
|
97
97
|
}
|
98
|
-
|
98
|
+
|
99
99
|
vector<string> createRealPreloaderCommand(const Options &options,
|
100
100
|
shared_array<const char *> &args)
|
101
101
|
{
|
102
102
|
string agentsDir = config->resourceLocator.getAgentsDir();
|
103
103
|
vector<string> command;
|
104
|
-
|
104
|
+
|
105
105
|
if (shouldLoadShellEnvvars(options, preparation)) {
|
106
106
|
command.push_back(preparation.shell);
|
107
107
|
command.push_back(preparation.shell);
|
@@ -121,11 +121,11 @@ private:
|
|
121
121
|
for (unsigned int i = 1; i < preloaderCommand.size(); i++) {
|
122
122
|
command.push_back(preloaderCommand[i]);
|
123
123
|
}
|
124
|
-
|
124
|
+
|
125
125
|
createCommandArgs(command, args);
|
126
126
|
return command;
|
127
127
|
}
|
128
|
-
|
128
|
+
|
129
129
|
void throwPreloaderSpawnException(const string &msg,
|
130
130
|
SpawnException::ErrorKind errorKind,
|
131
131
|
StartupDetails &details)
|
@@ -147,7 +147,7 @@ private:
|
|
147
147
|
if (stderrCapturer != NULL) {
|
148
148
|
stderrOutput = stderrCapturer->stop();
|
149
149
|
}
|
150
|
-
|
150
|
+
|
151
151
|
// If the exception wasn't due to a timeout, try to capture the
|
152
152
|
// remaining stderr output for at most 2 seconds.
|
153
153
|
if (errorKind != SpawnException::PRELOADER_STARTUP_TIMEOUT
|
@@ -159,7 +159,7 @@ private:
|
|
159
159
|
while (!done) {
|
160
160
|
char buf[1024 * 32];
|
161
161
|
unsigned int ret;
|
162
|
-
|
162
|
+
|
163
163
|
try {
|
164
164
|
ret = readExact(stderrCapturer->getFd(), buf,
|
165
165
|
sizeof(buf), &timeout);
|
@@ -177,7 +177,7 @@ private:
|
|
177
177
|
}
|
178
178
|
}
|
179
179
|
stderrCapturer.reset();
|
180
|
-
|
180
|
+
|
181
181
|
// Now throw SpawnException with the captured stderr output
|
182
182
|
// as error response.
|
183
183
|
SpawnException e(msg,
|
@@ -206,7 +206,7 @@ private:
|
|
206
206
|
assert(!preloaderStarted());
|
207
207
|
P_DEBUG("Spawning new preloader: appRoot=" << options.appRoot);
|
208
208
|
checkChrootDirectories(options);
|
209
|
-
|
209
|
+
|
210
210
|
shared_array<const char *> args;
|
211
211
|
preparation = prepareSpawn(options);
|
212
212
|
vector<string> command = createRealPreloaderCommand(options, args);
|
@@ -214,7 +214,7 @@ private:
|
|
214
214
|
Pipe errorPipe = createPipe();
|
215
215
|
DebugDirPtr debugDir = boost::make_shared<DebugDir>(preparation.uid, preparation.gid);
|
216
216
|
pid_t pid;
|
217
|
-
|
217
|
+
|
218
218
|
pid = syscalls::fork();
|
219
219
|
if (pid == 0) {
|
220
220
|
setenv("PASSENGER_DEBUG_DIR", debugDir->getPath().c_str(), 1);
|
@@ -232,7 +232,7 @@ private:
|
|
232
232
|
switchUser(preparation);
|
233
233
|
setWorkingDirectory(preparation);
|
234
234
|
execvp(command[0].c_str(), (char * const *) args.get());
|
235
|
-
|
235
|
+
|
236
236
|
int e = errno;
|
237
237
|
printf("!> Error\n");
|
238
238
|
printf("!> \n");
|
@@ -243,17 +243,17 @@ private:
|
|
243
243
|
fflush(stdout);
|
244
244
|
fflush(stderr);
|
245
245
|
_exit(1);
|
246
|
-
|
246
|
+
|
247
247
|
} else if (pid == -1) {
|
248
248
|
int e = errno;
|
249
249
|
throw SystemException("Cannot fork a new process", e);
|
250
|
-
|
250
|
+
|
251
251
|
} else {
|
252
252
|
ScopeGuard guard(boost::bind(nonInterruptableKillAndWaitpid, pid));
|
253
253
|
P_DEBUG("Preloader process forked for appRoot=" << options.appRoot << ": PID " << pid);
|
254
254
|
adminSocket.first.close();
|
255
255
|
errorPipe.second.close();
|
256
|
-
|
256
|
+
|
257
257
|
StartupDetails details;
|
258
258
|
details.pid = pid;
|
259
259
|
details.adminSocket = adminSocket.second;
|
@@ -268,7 +268,7 @@ private:
|
|
268
268
|
details.debugDir = debugDir;
|
269
269
|
details.options = &options;
|
270
270
|
details.timeout = options.startTimeout * 1000;
|
271
|
-
|
271
|
+
|
272
272
|
{
|
273
273
|
this_thread::restore_interruption ri(di);
|
274
274
|
this_thread::restore_syscall_interruption rsi(dsi);
|
@@ -279,7 +279,7 @@ private:
|
|
279
279
|
boost::lock_guard<boost::mutex> l(simpleFieldSyncher);
|
280
280
|
this->pid = pid;
|
281
281
|
}
|
282
|
-
|
282
|
+
|
283
283
|
PipeWatcherPtr watcher;
|
284
284
|
|
285
285
|
watcher = boost::make_shared<PipeWatcher>(adminSocket.second,
|
@@ -291,7 +291,7 @@ private:
|
|
291
291
|
"stderr", pid);
|
292
292
|
watcher->initialize();
|
293
293
|
watcher->start();
|
294
|
-
|
294
|
+
|
295
295
|
preloaderAnnotations = debugDir->readAll();
|
296
296
|
P_INFO("Preloader for " << options.appRoot <<
|
297
297
|
" started on PID " << pid <<
|
@@ -299,12 +299,12 @@ private:
|
|
299
299
|
guard.clear();
|
300
300
|
}
|
301
301
|
}
|
302
|
-
|
302
|
+
|
303
303
|
void stopPreloader() {
|
304
304
|
TRACE_POINT();
|
305
305
|
this_thread::disable_interruption di;
|
306
306
|
this_thread::disable_syscall_interruption dsi;
|
307
|
-
|
307
|
+
|
308
308
|
if (!preloaderStarted()) {
|
309
309
|
return;
|
310
310
|
}
|
@@ -327,7 +327,7 @@ private:
|
|
327
327
|
socketAddress.clear();
|
328
328
|
preparation = SpawnPreparationInfo();
|
329
329
|
}
|
330
|
-
|
330
|
+
|
331
331
|
void sendStartupRequest(StartupDetails &details) {
|
332
332
|
TRACE_POINT();
|
333
333
|
try {
|
@@ -375,14 +375,14 @@ private:
|
|
375
375
|
details);
|
376
376
|
}
|
377
377
|
}
|
378
|
-
|
378
|
+
|
379
379
|
string handleStartupResponse(StartupDetails &details) {
|
380
380
|
TRACE_POINT();
|
381
381
|
string socketAddress;
|
382
|
-
|
382
|
+
|
383
383
|
while (true) {
|
384
384
|
string line;
|
385
|
-
|
385
|
+
|
386
386
|
try {
|
387
387
|
line = readMessageLine(details);
|
388
388
|
} catch (const SystemException &e) {
|
@@ -397,7 +397,7 @@ private:
|
|
397
397
|
SpawnException::PRELOADER_STARTUP_TIMEOUT,
|
398
398
|
details);
|
399
399
|
}
|
400
|
-
|
400
|
+
|
401
401
|
if (line.empty()) {
|
402
402
|
throwPreloaderSpawnException("An error occurred while starting up "
|
403
403
|
"the preloader. It unexpected closed the connection while "
|
@@ -413,7 +413,7 @@ private:
|
|
413
413
|
} else if (line == "\n") {
|
414
414
|
break;
|
415
415
|
}
|
416
|
-
|
416
|
+
|
417
417
|
string::size_type pos = line.find(": ");
|
418
418
|
if (pos == string::npos) {
|
419
419
|
throwPreloaderSpawnException("An error occurred while starting up "
|
@@ -422,7 +422,7 @@ private:
|
|
422
422
|
SpawnException::PRELOADER_STARTUP_PROTOCOL_ERROR,
|
423
423
|
details);
|
424
424
|
}
|
425
|
-
|
425
|
+
|
426
426
|
string key = line.substr(0, pos);
|
427
427
|
string value = line.substr(pos + 2, line.size() - pos - 3);
|
428
428
|
if (key == "socket") {
|
@@ -436,7 +436,7 @@ private:
|
|
436
436
|
details);
|
437
437
|
}
|
438
438
|
}
|
439
|
-
|
439
|
+
|
440
440
|
if (socketAddress.empty()) {
|
441
441
|
throwPreloaderSpawnException("An error occurred while starting up "
|
442
442
|
"the preloader. It did not report a socket address in its "
|
@@ -444,17 +444,17 @@ private:
|
|
444
444
|
SpawnException::PRELOADER_STARTUP_PROTOCOL_ERROR,
|
445
445
|
details);
|
446
446
|
}
|
447
|
-
|
447
|
+
|
448
448
|
return socketAddress;
|
449
449
|
}
|
450
|
-
|
450
|
+
|
451
451
|
void handleErrorResponse(StartupDetails &details) {
|
452
452
|
TRACE_POINT();
|
453
453
|
map<string, string> attributes;
|
454
|
-
|
454
|
+
|
455
455
|
while (true) {
|
456
456
|
string line;
|
457
|
-
|
457
|
+
|
458
458
|
try {
|
459
459
|
line = readMessageLine(details);
|
460
460
|
} catch (const SystemException &e) {
|
@@ -469,7 +469,7 @@ private:
|
|
469
469
|
SpawnException::PRELOADER_STARTUP_TIMEOUT,
|
470
470
|
details);
|
471
471
|
}
|
472
|
-
|
472
|
+
|
473
473
|
if (line.empty()) {
|
474
474
|
throwPreloaderSpawnException("An error occurred while starting up "
|
475
475
|
"the preloader. It unexpected closed the connection while "
|
@@ -485,7 +485,7 @@ private:
|
|
485
485
|
} else if (line == "\n") {
|
486
486
|
break;
|
487
487
|
}
|
488
|
-
|
488
|
+
|
489
489
|
string::size_type pos = line.find(": ");
|
490
490
|
if (pos == string::npos) {
|
491
491
|
throwPreloaderSpawnException("An error occurred while starting up "
|
@@ -494,12 +494,12 @@ private:
|
|
494
494
|
SpawnException::PRELOADER_STARTUP_PROTOCOL_ERROR,
|
495
495
|
details);
|
496
496
|
}
|
497
|
-
|
497
|
+
|
498
498
|
string key = line.substr(0, pos);
|
499
499
|
string value = line.substr(pos + 2, line.size() - pos - 3);
|
500
500
|
attributes[key] = value;
|
501
501
|
}
|
502
|
-
|
502
|
+
|
503
503
|
try {
|
504
504
|
string message = details.io.readAll(&details.timeout);
|
505
505
|
SpawnException e("An error occured while starting up the preloader.",
|
@@ -524,7 +524,7 @@ private:
|
|
524
524
|
details);
|
525
525
|
}
|
526
526
|
}
|
527
|
-
|
527
|
+
|
528
528
|
void handleInvalidResponseType(StartupDetails &details, const string &line) {
|
529
529
|
if (line.empty()) {
|
530
530
|
throwPreloaderSpawnException("An error occurred while starting up "
|
@@ -540,7 +540,7 @@ private:
|
|
540
540
|
details);
|
541
541
|
}
|
542
542
|
}
|
543
|
-
|
543
|
+
|
544
544
|
string negotiatePreloaderStartup(StartupDetails &details) {
|
545
545
|
TRACE_POINT();
|
546
546
|
string result;
|
@@ -558,7 +558,7 @@ private:
|
|
558
558
|
SpawnException::PRELOADER_STARTUP_TIMEOUT,
|
559
559
|
details);
|
560
560
|
}
|
561
|
-
|
561
|
+
|
562
562
|
if (result == "I have control 1.0\n") {
|
563
563
|
UPDATE_TRACE_POINT();
|
564
564
|
sendStartupRequest(details);
|
@@ -591,12 +591,12 @@ private:
|
|
591
591
|
handleInvalidResponseType(details, result);
|
592
592
|
}
|
593
593
|
}
|
594
|
-
|
594
|
+
|
595
595
|
// Never reached, shut up compiler warning.
|
596
596
|
abort();
|
597
597
|
return "";
|
598
598
|
}
|
599
|
-
|
599
|
+
|
600
600
|
SpawnResult sendSpawnCommand(const Options &options) {
|
601
601
|
TRACE_POINT();
|
602
602
|
FileDescriptor fd;
|
@@ -612,14 +612,14 @@ private:
|
|
612
612
|
options,
|
613
613
|
DebugDirPtr());
|
614
614
|
}
|
615
|
-
|
615
|
+
|
616
616
|
UPDATE_TRACE_POINT();
|
617
617
|
BufferedIO io(fd);
|
618
618
|
unsigned long long timeout = options.startTimeout * 1000;
|
619
619
|
string result;
|
620
620
|
vector<string> args;
|
621
621
|
vector<string>::const_iterator it;
|
622
|
-
|
622
|
+
|
623
623
|
writeExact(fd, "spawn\n", &timeout);
|
624
624
|
options.toVector(args, config->resourceLocator, Options::SPAWN_OPTIONS);
|
625
625
|
for (it = args.begin(); it != args.end(); it++) {
|
@@ -629,12 +629,12 @@ private:
|
|
629
629
|
writeExact(fd, key + ": " + value + "\n", &timeout);
|
630
630
|
}
|
631
631
|
writeExact(fd, "\n", &timeout);
|
632
|
-
|
632
|
+
|
633
633
|
result = io.readLine(1024, &timeout);
|
634
634
|
if (result == "OK\n") {
|
635
635
|
UPDATE_TRACE_POINT();
|
636
636
|
pid_t spawnedPid;
|
637
|
-
|
637
|
+
|
638
638
|
spawnedPid = atoi(io.readLine(1024, &timeout).c_str());
|
639
639
|
if (spawnedPid <= 0) {
|
640
640
|
BackgroundIOCapturerPtr stderrCapturer;
|
@@ -660,29 +660,29 @@ private:
|
|
660
660
|
options,
|
661
661
|
DebugDirPtr());
|
662
662
|
}
|
663
|
-
|
663
|
+
|
664
664
|
SpawnResult result;
|
665
665
|
result.pid = spawnedPid;
|
666
666
|
result.adminSocket = fd;
|
667
667
|
result.io = io;
|
668
668
|
return result;
|
669
|
-
|
669
|
+
|
670
670
|
} else if (result == "Error\n") {
|
671
671
|
UPDATE_TRACE_POINT();
|
672
672
|
NegotiationDetails details;
|
673
673
|
details.io = io;
|
674
674
|
details.timeout = timeout;
|
675
675
|
handleSpawnErrorResponse(details);
|
676
|
-
|
676
|
+
|
677
677
|
} else {
|
678
678
|
UPDATE_TRACE_POINT();
|
679
679
|
NegotiationDetails details;
|
680
680
|
handleInvalidSpawnResponseType(result, details);
|
681
681
|
}
|
682
|
-
|
682
|
+
|
683
683
|
return SpawnResult(); // Never reached.
|
684
684
|
}
|
685
|
-
|
685
|
+
|
686
686
|
template<typename Exception>
|
687
687
|
SpawnResult sendSpawnCommandAgain(const Exception &e, const Options &options) {
|
688
688
|
TRACE_POINT();
|
@@ -695,7 +695,7 @@ private:
|
|
695
695
|
guard.clear();
|
696
696
|
return result;
|
697
697
|
}
|
698
|
-
|
698
|
+
|
699
699
|
protected:
|
700
700
|
virtual void annotateAppSpawnException(SpawnException &e, NegotiationDetails &details) {
|
701
701
|
Spawner::annotateAppSpawnException(e, details);
|
@@ -713,23 +713,23 @@ public:
|
|
713
713
|
if (preloaderCommand.size() < 2) {
|
714
714
|
throw ArgumentException("preloaderCommand must have at least 2 elements");
|
715
715
|
}
|
716
|
-
|
716
|
+
|
717
717
|
generation = _generation;
|
718
718
|
options = _options.copyAndPersist().detachFromUnionStationTransaction();
|
719
719
|
pid = -1;
|
720
720
|
m_lastUsed = SystemTime::getUsec();
|
721
721
|
}
|
722
|
-
|
722
|
+
|
723
723
|
virtual ~SmartSpawner() {
|
724
724
|
boost::lock_guard<boost::mutex> l(syncher);
|
725
725
|
stopPreloader();
|
726
726
|
}
|
727
|
-
|
727
|
+
|
728
728
|
virtual ProcessPtr spawn(const Options &options) {
|
729
729
|
TRACE_POINT();
|
730
730
|
assert(options.appType == this->options.appType);
|
731
731
|
assert(options.appRoot == this->options.appRoot);
|
732
|
-
|
732
|
+
|
733
733
|
P_DEBUG("Spawning new process: appRoot=" << options.appRoot);
|
734
734
|
possiblyRaiseInternalError(options);
|
735
735
|
|
@@ -743,7 +743,7 @@ public:
|
|
743
743
|
UPDATE_TRACE_POINT();
|
744
744
|
startPreloader();
|
745
745
|
}
|
746
|
-
|
746
|
+
|
747
747
|
UPDATE_TRACE_POINT();
|
748
748
|
SpawnResult result;
|
749
749
|
try {
|
@@ -755,7 +755,7 @@ public:
|
|
755
755
|
} catch (const SpawnException &e) {
|
756
756
|
result = sendSpawnCommandAgain(e, options);
|
757
757
|
}
|
758
|
-
|
758
|
+
|
759
759
|
UPDATE_TRACE_POINT();
|
760
760
|
NegotiationDetails details;
|
761
761
|
details.preparation = &preparation;
|
@@ -772,7 +772,7 @@ public:
|
|
772
772
|
virtual bool cleanable() const {
|
773
773
|
return true;
|
774
774
|
}
|
775
|
-
|
775
|
+
|
776
776
|
virtual void cleanup() {
|
777
777
|
TRACE_POINT();
|
778
778
|
{
|
@@ -787,7 +787,7 @@ public:
|
|
787
787
|
boost::lock_guard<boost::mutex> lock(simpleFieldSyncher);
|
788
788
|
return m_lastUsed;
|
789
789
|
}
|
790
|
-
|
790
|
+
|
791
791
|
pid_t getPreloaderPid() const {
|
792
792
|
boost::lock_guard<boost::mutex> lock(simpleFieldSyncher);
|
793
793
|
return pid;
|