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
@@ -109,7 +109,9 @@ private:
|
|
109
109
|
startBackgroundThread(detachProcessMain, (void *) (long) pid);
|
110
110
|
}
|
111
111
|
|
112
|
-
vector<string> createCommand(const Options &options,
|
112
|
+
vector<string> createCommand(const Options &options, const SpawnPreparationInfo &preparation,
|
113
|
+
shared_array<const char *> &args) const
|
114
|
+
{
|
113
115
|
vector<string> startCommandArgs;
|
114
116
|
string agentsDir = resourceLocator.getAgentsDir();
|
115
117
|
vector<string> command;
|
@@ -129,6 +131,7 @@ private:
|
|
129
131
|
command.push_back(agentsDir + "/SpawnPreparer");
|
130
132
|
}
|
131
133
|
command.push_back(agentsDir + "/SpawnPreparer");
|
134
|
+
command.push_back(preparation.appRoot);
|
132
135
|
command.push_back(serializeEnvvarsFromPoolOptions(options));
|
133
136
|
command.push_back(startCommandArgs[0]);
|
134
137
|
// Note: do not try to set a process title here.
|
@@ -166,8 +169,8 @@ public:
|
|
166
169
|
possiblyRaiseInternalError(options);
|
167
170
|
|
168
171
|
shared_array<const char *> args;
|
169
|
-
vector<string> command = createCommand(options, args);
|
170
172
|
SpawnPreparationInfo preparation = prepareSpawn(options);
|
173
|
+
vector<string> command = createCommand(options, preparation, args);
|
171
174
|
SocketPair adminSocket = createUnixSocketPair();
|
172
175
|
Pipe errorPipe = createPipe();
|
173
176
|
DebugDirPtr debugDir = make_shared<DebugDir>(preparation.uid, preparation.gid);
|
@@ -953,6 +953,12 @@ Group::detachedProcessesCheckerMain(GroupPtr self) {
|
|
953
953
|
assert(process->getLifeStatus() == Process::DEAD);
|
954
954
|
it++;
|
955
955
|
removeProcessFromList(process, detachedProcesses);
|
956
|
+
} else if (process->shutdownTimeoutExpired()) {
|
957
|
+
P_WARN("Detached process " << process->inspect() <<
|
958
|
+
" didn't shut down within " PROCESS_SHUTDOWN_TIMEOUT_DISPLAY
|
959
|
+
". Forcefully killing it with SIGKILL.");
|
960
|
+
kill(process->pid, SIGKILL);
|
961
|
+
it++;
|
956
962
|
} else {
|
957
963
|
it++;
|
958
964
|
}
|
@@ -991,7 +997,7 @@ Group::detachedProcessesCheckerMain(GroupPtr self) {
|
|
991
997
|
// someone wakes us up.
|
992
998
|
UPDATE_TRACE_POINT();
|
993
999
|
detachedProcessesCheckerCond.timed_wait(lock,
|
994
|
-
posix_time::milliseconds(
|
1000
|
+
posix_time::milliseconds(100));
|
995
1001
|
}
|
996
1002
|
}
|
997
1003
|
|
@@ -434,17 +434,20 @@ public:
|
|
434
434
|
for (p_it = processes.begin(); p_it != processes.end(); p_it++) {
|
435
435
|
const ProcessPtr &process = *p_it;
|
436
436
|
char buf[128];
|
437
|
+
char cpubuf[10];
|
437
438
|
char membuf[10];
|
438
439
|
|
440
|
+
snprintf(cpubuf, sizeof(cpubuf), "%d%%", (int) process->metrics.cpu);
|
439
441
|
snprintf(membuf, sizeof(membuf), "%ldM",
|
440
442
|
(unsigned long) (process->metrics.realMemory() / 1024));
|
441
443
|
snprintf(buf, sizeof(buf),
|
442
|
-
" * PID
|
443
|
-
" Memory: %-5s Last used: %s ago",
|
444
|
+
" * PID: %-5lu Sessions: %-2u Processed: %-5u Uptime: %s\n"
|
445
|
+
" CPU: %-5s Memory : %-5s Last used: %s ago",
|
444
446
|
(unsigned long) process->pid,
|
445
447
|
process->sessions,
|
446
448
|
process->processed,
|
447
449
|
process->uptime().c_str(),
|
450
|
+
cpubuf,
|
448
451
|
membuf,
|
449
452
|
distanceOfTimeInWords(process->lastUsed / 1000000).c_str());
|
450
453
|
result << buf << endl;
|
@@ -454,7 +457,7 @@ public:
|
|
454
457
|
} else if (process->enabled == Process::DISABLED) {
|
455
458
|
result << " DISABLED" << endl;
|
456
459
|
} else if (process->enabled == Process::DETACHED) {
|
457
|
-
result << " Shutting down...";
|
460
|
+
result << " Shutting down..." << endl;
|
458
461
|
}
|
459
462
|
|
460
463
|
const Socket *socket;
|
@@ -39,6 +39,7 @@
|
|
39
39
|
#include <ApplicationPool2/Socket.h>
|
40
40
|
#include <ApplicationPool2/Session.h>
|
41
41
|
#include <ApplicationPool2/PipeWatcher.h>
|
42
|
+
#include <Constants.h>
|
42
43
|
#include <FileDescriptor.h>
|
43
44
|
#include <SafeLibev.h>
|
44
45
|
#include <Logging.h>
|
@@ -233,10 +234,10 @@ public:
|
|
233
234
|
/** This process has been detached, and the detached processes checker has
|
234
235
|
* verified that there are no active sessions left and has told the process
|
235
236
|
* to shut down. In this state we're supposed to wait until the process
|
236
|
-
* has actually shutdown, after which
|
237
|
+
* has actually shutdown, after which cleanup() must be called. */
|
237
238
|
SHUTDOWN_TRIGGERED,
|
238
239
|
/**
|
239
|
-
* The process has exited and
|
240
|
+
* The process has exited and cleanup() has been called. In this state,
|
240
241
|
* this object is no longer usable.
|
241
242
|
*/
|
242
243
|
DEAD
|
@@ -275,6 +276,8 @@ public:
|
|
275
276
|
} oobwStatus;
|
276
277
|
/** Caches whether or not the OS process still exists. */
|
277
278
|
mutable bool m_osProcessExists;
|
279
|
+
/** Time at which shutdown began. */
|
280
|
+
time_t shutdownStartTime;
|
278
281
|
/** Collected by Pool::collectAnalytics(). */
|
279
282
|
ProcessMetrics metrics;
|
280
283
|
|
@@ -309,7 +312,8 @@ public:
|
|
309
312
|
lifeStatus(ALIVE),
|
310
313
|
enabled(ENABLED),
|
311
314
|
oobwStatus(OOBW_NOT_ACTIVE),
|
312
|
-
m_osProcessExists(true)
|
315
|
+
m_osProcessExists(true),
|
316
|
+
shutdownStartTime(0)
|
313
317
|
{
|
314
318
|
SpawnerConfigPtr config;
|
315
319
|
if (_config == NULL) {
|
@@ -412,12 +416,17 @@ public:
|
|
412
416
|
lock_guard<boost::mutex> lock(lifetimeSyncher);
|
413
417
|
assert(lifeStatus == ALIVE);
|
414
418
|
lifeStatus = SHUTDOWN_TRIGGERED;
|
419
|
+
shutdownStartTime = SystemTime::get();
|
415
420
|
}
|
416
421
|
if (!dummy) {
|
417
422
|
syscalls::shutdown(adminSocket, SHUT_WR);
|
418
423
|
}
|
419
424
|
}
|
420
425
|
|
426
|
+
bool shutdownTimeoutExpired() const {
|
427
|
+
return SystemTime::get() >= shutdownStartTime + PROCESS_SHUTDOWN_TIMEOUT;
|
428
|
+
}
|
429
|
+
|
421
430
|
bool canCleanup() const {
|
422
431
|
return getLifeStatus() == SHUTDOWN_TRIGGERED && !osProcessExists();
|
423
432
|
}
|
@@ -120,6 +120,7 @@ private:
|
|
120
120
|
command.push_back(agentsDir + "/SpawnPreparer");
|
121
121
|
}
|
122
122
|
command.push_back(agentsDir + "/SpawnPreparer");
|
123
|
+
command.push_back(preparation.appRoot);
|
123
124
|
command.push_back(serializeEnvvarsFromPoolOptions(options));
|
124
125
|
command.push_back(preloaderCommand[0]);
|
125
126
|
// Note: do not try to set a process title here.
|
@@ -210,8 +211,8 @@ private:
|
|
210
211
|
checkChrootDirectories(options);
|
211
212
|
|
212
213
|
shared_array<const char *> args;
|
213
|
-
vector<string> command = createRealPreloaderCommand(options, args);
|
214
214
|
preparation = prepareSpawn(options);
|
215
|
+
vector<string> command = createRealPreloaderCommand(options, args);
|
215
216
|
SocketPair adminSocket = createUnixSocketPair();
|
216
217
|
Pipe errorPipe = createPipe();
|
217
218
|
DebugDirPtr debugDir = make_shared<DebugDir>(preparation.uid, preparation.gid);
|
data/ext/common/Constants.h
CHANGED
@@ -26,7 +26,7 @@
|
|
26
26
|
#define _PASSENGER_CONSTANTS_H_
|
27
27
|
|
28
28
|
/* Don't forget to update lib/phusion_passenger.rb too. */
|
29
|
-
#define PASSENGER_VERSION "4.0.
|
29
|
+
#define PASSENGER_VERSION "4.0.3"
|
30
30
|
|
31
31
|
#define FEEDBACK_FD 3
|
32
32
|
|
@@ -49,4 +49,7 @@
|
|
49
49
|
|
50
50
|
#define POOL_HELPER_THREAD_STACK_SIZE (1024 * 256)
|
51
51
|
|
52
|
+
#define PROCESS_SHUTDOWN_TIMEOUT 60 /* seconds */
|
53
|
+
#define PROCESS_SHUTDOWN_TIMEOUT_DISPLAY "1 minute"
|
54
|
+
|
52
55
|
#endif /* _PASSENGER_CONSTANTS_H */
|
@@ -60,16 +60,23 @@ using namespace oxt;
|
|
60
60
|
* the number of bytes that it has actually consumed. If not everything has been
|
61
61
|
* consumed, then the handler will be called with the remaining data in the next
|
62
62
|
* tick.
|
63
|
-
*
|
64
|
-
* TODO: this code is directly ported from Zangetsu's socket_input_wrapper.js. We
|
65
|
-
* should port over the unit tests too.
|
66
63
|
*/
|
67
64
|
template<size_t bufferSize = 1024 * 8>
|
68
65
|
class EventedBufferedInput: public enable_shared_from_this< EventedBufferedInput<bufferSize> > {
|
69
66
|
private:
|
70
67
|
enum State {
|
71
68
|
LIVE,
|
69
|
+
/**
|
70
|
+
* @invariant
|
71
|
+
* paused
|
72
|
+
* socketPaused
|
73
|
+
*/
|
72
74
|
END_OF_STREAM,
|
75
|
+
/**
|
76
|
+
* @invariant
|
77
|
+
* paused
|
78
|
+
* socketPaused
|
79
|
+
*/
|
73
80
|
READ_ERROR,
|
74
81
|
CLOSED
|
75
82
|
};
|
@@ -78,13 +85,54 @@ private:
|
|
78
85
|
FileDescriptor fd;
|
79
86
|
ev::io watcher;
|
80
87
|
StaticString buffer;
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
88
|
+
|
89
|
+
State state: 2;
|
90
|
+
/**
|
91
|
+
* Whether this EventedBufferedInput is paused (not started). If it's
|
92
|
+
* paused it should not emit data events.
|
93
|
+
*
|
94
|
+
* @invariant
|
95
|
+
* if paused:
|
96
|
+
* socketPaused
|
97
|
+
*/
|
98
|
+
bool paused: 1;
|
99
|
+
/**
|
100
|
+
* Whether the underlying socket is also paused. This does not
|
101
|
+
* necessarily mean the EventedBufferedInput is also paused because
|
102
|
+
* it may be emitting data events from its internal buffer.
|
103
|
+
*/
|
104
|
+
bool socketPaused: 1;
|
105
|
+
/**
|
106
|
+
* Whether the code is inside a processingBuffer() call.
|
107
|
+
*/
|
108
|
+
bool processingBuffer: 1;
|
109
|
+
/**
|
110
|
+
* Whether processBuffer() is scheduled to be called in the next
|
111
|
+
* event loop iteration.
|
112
|
+
*/
|
113
|
+
bool nextTickInstalled: 1;
|
114
|
+
/**
|
115
|
+
* Increment this number to ensure that previously scheduled
|
116
|
+
* processBuffer() calls will do nothing, effectively canceling
|
117
|
+
* its scheduled calls.
|
118
|
+
*/
|
119
|
+
unsigned int generation;
|
85
120
|
int error;
|
121
|
+
|
86
122
|
char bufferData[bufferSize];
|
87
123
|
|
124
|
+
void verifyInvariants() {
|
125
|
+
// !a || b: logical equivalent of a IMPLIES b.
|
126
|
+
|
127
|
+
assert(!( state == END_OF_STREAM ) || ( paused ));
|
128
|
+
assert(!( state == END_OF_STREAM ) || ( socketPaused ));
|
129
|
+
|
130
|
+
assert(!( state == READ_ERROR ) || ( paused ));
|
131
|
+
assert(!( state == READ_ERROR ) || ( socketPaused ));
|
132
|
+
|
133
|
+
assert(!( paused ) || ( socketPaused ));
|
134
|
+
}
|
135
|
+
|
88
136
|
void resetCallbackFields() {
|
89
137
|
onData = NULL;
|
90
138
|
onError = NULL;
|
@@ -96,7 +144,10 @@ private:
|
|
96
144
|
shared_ptr< EventedBufferedInput<bufferSize> > self = EventedBufferedInput<bufferSize>::shared_from_this();
|
97
145
|
|
98
146
|
EBI_TRACE("onReadable");
|
99
|
-
|
147
|
+
verifyInvariants();
|
148
|
+
assert(!nextTickInstalled);
|
149
|
+
|
150
|
+
ssize_t ret = readSocket(bufferData, bufferSize);
|
100
151
|
if (ret == -1) {
|
101
152
|
if (errno != EAGAIN) {
|
102
153
|
error = errno;
|
@@ -109,8 +160,11 @@ private:
|
|
109
160
|
watcher.stop();
|
110
161
|
state = READ_ERROR;
|
111
162
|
paused = true;
|
163
|
+
socketPaused = true;
|
164
|
+
verifyInvariants();
|
112
165
|
if (onError != NULL) {
|
113
166
|
onError(self, "Cannot read from socket", error);
|
167
|
+
verifyInvariants();
|
114
168
|
}
|
115
169
|
}
|
116
170
|
|
@@ -124,7 +178,10 @@ private:
|
|
124
178
|
watcher.stop();
|
125
179
|
state = END_OF_STREAM;
|
126
180
|
paused = true;
|
181
|
+
socketPaused = true;
|
182
|
+
verifyInvariants();
|
127
183
|
onData(self, StaticString());
|
184
|
+
verifyInvariants();
|
128
185
|
|
129
186
|
} else {
|
130
187
|
EBI_TRACE("read " << ret << " bytes");
|
@@ -135,29 +192,51 @@ private:
|
|
135
192
|
|
136
193
|
buffer = StaticString(bufferData, ret);
|
137
194
|
processBuffer();
|
195
|
+
verifyInvariants();
|
138
196
|
}
|
139
197
|
}
|
140
198
|
|
141
199
|
void processBufferInNextTick() {
|
142
200
|
if (!nextTickInstalled) {
|
143
201
|
nextTickInstalled = true;
|
144
|
-
libev->
|
202
|
+
libev->runLater(boost::bind(
|
145
203
|
realProcessBufferInNextTick,
|
146
|
-
weak_ptr< EventedBufferedInput<bufferSize> >(this->shared_from_this())
|
204
|
+
weak_ptr< EventedBufferedInput<bufferSize> >(this->shared_from_this()),
|
205
|
+
generation
|
147
206
|
));
|
148
207
|
}
|
149
208
|
}
|
150
209
|
|
151
|
-
static void realProcessBufferInNextTick(weak_ptr< EventedBufferedInput<bufferSize> > wself
|
210
|
+
static void realProcessBufferInNextTick(weak_ptr< EventedBufferedInput<bufferSize> > wself,
|
211
|
+
unsigned int generation)
|
212
|
+
{
|
152
213
|
shared_ptr< EventedBufferedInput<bufferSize> > self = wself.lock();
|
153
|
-
if (self != NULL) {
|
214
|
+
if (self != NULL && generation == self->generation) {
|
215
|
+
self->verifyInvariants();
|
154
216
|
self->nextTickInstalled = false;
|
155
217
|
self->processBuffer();
|
218
|
+
self->verifyInvariants();
|
156
219
|
}
|
157
220
|
}
|
158
221
|
|
222
|
+
struct SetProcessingBufferToFalse {
|
223
|
+
EventedBufferedInput<bufferSize> *self;
|
224
|
+
|
225
|
+
SetProcessingBufferToFalse(EventedBufferedInput<bufferSize> *_self) {
|
226
|
+
self = _self;
|
227
|
+
}
|
228
|
+
|
229
|
+
~SetProcessingBufferToFalse() {
|
230
|
+
self->processingBuffer = false;
|
231
|
+
}
|
232
|
+
};
|
233
|
+
|
159
234
|
void processBuffer() {
|
160
235
|
EBI_TRACE("processBuffer");
|
236
|
+
assert(!processingBuffer);
|
237
|
+
processingBuffer = true;
|
238
|
+
SetProcessingBufferToFalse flagGuard(this);
|
239
|
+
|
161
240
|
if (state == CLOSED) {
|
162
241
|
return;
|
163
242
|
}
|
@@ -179,6 +258,7 @@ private:
|
|
179
258
|
socketPaused = false;
|
180
259
|
watcher.start();
|
181
260
|
}
|
261
|
+
cancelScheduledProcessBufferCall();
|
182
262
|
} else {
|
183
263
|
buffer = buffer.substr(consumed);
|
184
264
|
if (!socketPaused) {
|
@@ -189,18 +269,36 @@ private:
|
|
189
269
|
// Consume rest of the data in the next tick.
|
190
270
|
EBI_TRACE("Consume rest in next tick");
|
191
271
|
processBufferInNextTick();
|
272
|
+
} else {
|
273
|
+
cancelScheduledProcessBufferCall();
|
192
274
|
}
|
193
275
|
}
|
276
|
+
|
277
|
+
afterProcessingBuffer();
|
194
278
|
}
|
195
279
|
|
196
|
-
void
|
280
|
+
void cancelScheduledProcessBufferCall() {
|
281
|
+
if (nextTickInstalled) {
|
282
|
+
nextTickInstalled = false;
|
283
|
+
generation++;
|
284
|
+
}
|
285
|
+
}
|
286
|
+
|
287
|
+
void _reset(SafeLibev *libev, const FileDescriptor &fd, bool firstTime = false) {
|
288
|
+
if (firstTime) {
|
289
|
+
generation = 0;
|
290
|
+
} else {
|
291
|
+
verifyInvariants();
|
292
|
+
}
|
197
293
|
this->libev = libev;
|
198
294
|
this->fd = fd;
|
199
295
|
buffer = StaticString();
|
200
296
|
state = LIVE;
|
201
297
|
paused = true;
|
202
298
|
socketPaused = true;
|
299
|
+
processingBuffer = false;
|
203
300
|
nextTickInstalled = false;
|
301
|
+
generation++;
|
204
302
|
error = 0;
|
205
303
|
if (watcher.is_active()) {
|
206
304
|
watcher.stop();
|
@@ -211,6 +309,16 @@ private:
|
|
211
309
|
if (fd != -1) {
|
212
310
|
watcher.set(fd, ev::READ);
|
213
311
|
}
|
312
|
+
verifyInvariants();
|
313
|
+
}
|
314
|
+
|
315
|
+
protected:
|
316
|
+
virtual ssize_t readSocket(void *buf, size_t n) {
|
317
|
+
return syscalls::read(fd, buf, n);
|
318
|
+
}
|
319
|
+
|
320
|
+
virtual void afterProcessingBuffer() {
|
321
|
+
// Do nothing. To be overridden in unit tests.
|
214
322
|
}
|
215
323
|
|
216
324
|
public:
|
@@ -223,21 +331,24 @@ public:
|
|
223
331
|
|
224
332
|
EventedBufferedInput() {
|
225
333
|
resetCallbackFields();
|
226
|
-
_reset(NULL, FileDescriptor());
|
334
|
+
_reset(NULL, FileDescriptor(), true);
|
227
335
|
watcher.set<EventedBufferedInput<bufferSize>,
|
228
336
|
&EventedBufferedInput<bufferSize>::onReadable>(this);
|
229
337
|
EBI_TRACE("created");
|
338
|
+
verifyInvariants();
|
230
339
|
}
|
231
340
|
|
232
341
|
EventedBufferedInput(SafeLibev *libev, const FileDescriptor &fd) {
|
233
342
|
resetCallbackFields();
|
234
|
-
_reset(libev, fd);
|
343
|
+
_reset(libev, fd, true);
|
235
344
|
watcher.set<EventedBufferedInput<bufferSize>,
|
236
345
|
&EventedBufferedInput<bufferSize>::onReadable>(this);
|
237
346
|
EBI_TRACE("created");
|
347
|
+
verifyInvariants();
|
238
348
|
}
|
239
349
|
|
240
|
-
~EventedBufferedInput() {
|
350
|
+
virtual ~EventedBufferedInput() {
|
351
|
+
cancelScheduledProcessBufferCall();
|
241
352
|
watcher.stop();
|
242
353
|
EBI_TRACE("destroyed");
|
243
354
|
}
|
@@ -254,17 +365,21 @@ public:
|
|
254
365
|
void stop() {
|
255
366
|
if (state == LIVE && !paused) {
|
256
367
|
EBI_TRACE("stop()");
|
368
|
+
verifyInvariants();
|
257
369
|
paused = true;
|
258
370
|
if (!socketPaused) {
|
259
371
|
socketPaused = true;
|
260
372
|
watcher.stop();
|
261
373
|
}
|
374
|
+
cancelScheduledProcessBufferCall();
|
375
|
+
verifyInvariants();
|
262
376
|
}
|
263
377
|
}
|
264
378
|
|
265
379
|
void start() {
|
266
380
|
if (state == LIVE && paused) {
|
267
381
|
EBI_TRACE("start()");
|
382
|
+
verifyInvariants();
|
268
383
|
assert(socketPaused);
|
269
384
|
|
270
385
|
paused = false;
|
@@ -273,7 +388,9 @@ public:
|
|
273
388
|
} else {
|
274
389
|
socketPaused = false;
|
275
390
|
watcher.start();
|
391
|
+
cancelScheduledProcessBufferCall();
|
276
392
|
}
|
393
|
+
verifyInvariants();
|
277
394
|
}
|
278
395
|
}
|
279
396
|
|
@@ -281,11 +398,16 @@ public:
|
|
281
398
|
return !paused;
|
282
399
|
}
|
283
400
|
|
401
|
+
bool isSocketStarted() const {
|
402
|
+
return !socketPaused;
|
403
|
+
}
|
404
|
+
|
284
405
|
bool endReached() const {
|
285
406
|
return state == END_OF_STREAM;
|
286
407
|
}
|
287
408
|
|
288
409
|
void readNow() {
|
410
|
+
assert(!nextTickInstalled);
|
289
411
|
onReadable(watcher, 0);
|
290
412
|
}
|
291
413
|
|
@@ -322,6 +444,7 @@ public:
|
|
322
444
|
result << ", paused=" << paused;
|
323
445
|
result << ", socketPaused=" << socketPaused;
|
324
446
|
result << ", nextTickInstalled=" << nextTickInstalled;
|
447
|
+
result << ", generation=" << generation;
|
325
448
|
result << ", error=" << error;
|
326
449
|
|
327
450
|
return result.str();
|