11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#include " swift/Basic/TaskQueue.h"
14
+ #include " swift/Basic/Statistic.h"
14
15
15
16
#include " llvm/ADT/StringRef.h"
16
17
#include " llvm/ADT/DenseMap.h"
@@ -84,12 +85,16 @@ class Task {
84
85
// / from the Task.
85
86
std::string Errors;
86
87
88
+ // / Optional place to count I/O and subprocess events.
89
+ UnifiedStatsReporter *Stats;
90
+
87
91
public:
88
92
Task (const char *ExecPath, ArrayRef<const char *> Args,
89
- ArrayRef<const char *> Env, void *Context, bool SeparateErrors)
93
+ ArrayRef<const char *> Env, void *Context, bool SeparateErrors,
94
+ UnifiedStatsReporter *USR)
90
95
: ExecPath(ExecPath), Args(Args), Env(Env), Context(Context),
91
96
SeparateErrors (SeparateErrors), Pid(-1 ), Pipe(-1 ), ErrorPipe(-1 ),
92
- State(Preparing) {
97
+ State(Preparing), Stats(USR) {
93
98
assert ((Env.empty () || Env.back () == nullptr ) &&
94
99
" Env must either be empty or null-terminated!" );
95
100
}
@@ -108,8 +113,11 @@ public:
108
113
bool execute ();
109
114
110
115
// / \brief Reads data from the pipes, if any is available.
111
- // / \returns true on error, false on success
112
- bool readFromPipes ();
116
+ // /
117
+ // / If \p UntilEnd is true, reads until the end of the stream; otherwise reads
118
+ // / once (possibly with a retry on EINTR), and returns.
119
+ // / \returns true on error, false on success.
120
+ bool readFromPipes (bool UntilEnd = true );
113
121
114
122
// / \brief Performs any post-execution work for this Task, such as reading
115
123
// / piped output and closing the pipe.
@@ -241,7 +249,9 @@ bool Task::execute() {
241
249
return false ;
242
250
}
243
251
244
- static bool readFromAPipe (int Pipe, std::string &Output) {
252
+ static bool readFromAPipe (int Pipe, std::string &Output,
253
+ UnifiedStatsReporter *Stats,
254
+ bool UntilEnd) {
245
255
char outputBuffer[1024 ];
246
256
ssize_t readBytes = 0 ;
247
257
while ((readBytes = read (Pipe, outputBuffer, sizeof (outputBuffer))) != 0 ) {
@@ -253,15 +263,19 @@ static bool readFromAPipe(int Pipe, std::string &Output) {
253
263
}
254
264
255
265
Output.append (outputBuffer, readBytes);
266
+ if (Stats)
267
+ Stats->getDriverCounters ().NumDriverPipeReads ++;
268
+ if (!UntilEnd)
269
+ break ;
256
270
}
257
271
258
272
return false ;
259
273
}
260
274
261
- bool Task::readFromPipes () {
262
- bool Ret = readFromAPipe (Pipe, Output);
275
+ bool Task::readFromPipes (bool UntilEnd ) {
276
+ bool Ret = readFromAPipe (Pipe, Output, Stats, UntilEnd );
263
277
if (SeparateErrors) {
264
- Ret |= readFromAPipe (ErrorPipe, Errors);
278
+ Ret |= readFromAPipe (ErrorPipe, Errors, Stats, UntilEnd );
265
279
}
266
280
return Ret;
267
281
}
@@ -302,7 +316,7 @@ void TaskQueue::addTask(const char *ExecPath, ArrayRef<const char *> Args,
302
316
ArrayRef<const char *> Env, void *Context,
303
317
bool SeparateErrors) {
304
318
std::unique_ptr<Task> T (
305
- new Task (ExecPath, Args, Env, Context, SeparateErrors));
319
+ new Task (ExecPath, Args, Env, Context, SeparateErrors, Stats ));
306
320
QueuedTasks.push (std::move (T));
307
321
}
308
322
@@ -355,6 +369,8 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
355
369
continue ;
356
370
return true ;
357
371
}
372
+ if (Stats)
373
+ Stats->getDriverCounters ().NumDriverPipePolls ++;
358
374
359
375
// Holds all fds which have finished during this loop iteration.
360
376
std::vector<int > FinishedFds;
@@ -373,8 +389,15 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
373
389
" All outstanding fds must be associated with an executing Task" );
374
390
Task &T = *iter->second ;
375
391
if (fd.revents & POLLIN || fd.revents & POLLPRI) {
376
- // There's data available to read.
377
- T.readFromPipes ();
392
+ // There's data available to read. Read _some_ of it here, but not
393
+ // necessarily _all_, since the pipe is in blocking mode and we might
394
+ // have other input pending (or soon -- before this subprocess is done
395
+ // writing) from other subprocesses.
396
+ //
397
+ // FIXME: longer term, this should probably either be restructured to
398
+ // use O_NONBLOCK, or at very least poll the stderr file descriptor as
399
+ // well; the whole loop here is a bit of a mess.
400
+ T.readFromPipes (/* UntilEnd = */ false );
378
401
}
379
402
380
403
if (fd.revents & POLLHUP || fd.revents & POLLERR) {
0 commit comments