@@ -58,12 +58,18 @@ class Task {
58
58
// / Context which should be associated with this task.
59
59
void *Context;
60
60
61
+ // / True if the errors of the Task should be stored in Errors instead of Output.
62
+ bool SeparateErrors;
63
+
61
64
// / The pid of this Task when executing.
62
65
pid_t Pid;
63
66
64
67
// / A pipe for reading output from the child process.
65
68
int Pipe;
66
69
70
+ // / A pipe for reading errors from the child prcess, if SeparateErrors is true.
71
+ int ErrorPipe;
72
+
67
73
// / The current state of the Task.
68
74
enum {
69
75
Preparing,
@@ -74,29 +80,36 @@ class Task {
74
80
// / Once the Task has finished, this contains the buffered output of the Task.
75
81
std::string Output;
76
82
83
+ // / Once the Task has finished, if SeparateErrors is true, this contains the errors
84
+ // / from the Task.
85
+ std::string Errors;
86
+
77
87
public:
78
88
Task (const char *ExecPath, ArrayRef<const char *> Args,
79
- ArrayRef<const char *> Env, void *Context)
89
+ ArrayRef<const char *> Env, void *Context, bool SeparateErrors )
80
90
: ExecPath(ExecPath), Args(Args), Env(Env), Context(Context),
81
- Pid (-1 ), Pipe(-1 ), State(Preparing) {
91
+ SeparateErrors (SeparateErrors), Pid(-1 ), Pipe(-1 ), ErrorPipe(-1 ),
92
+ State(Preparing) {
82
93
assert ((Env.empty () || Env.back () == nullptr ) &&
83
94
" Env must either be empty or null-terminated!" );
84
95
}
85
96
86
97
const char *getExecPath () const { return ExecPath; }
87
98
ArrayRef<const char *> getArgs () const { return Args; }
88
99
StringRef getOutput () const { return Output; }
100
+ StringRef getErrors () const { return Errors; }
89
101
void *getContext () const { return Context; }
90
102
pid_t getPid () const { return Pid; }
91
103
int getPipe () const { return Pipe; }
104
+ int getErrorPipe () const { return ErrorPipe; }
92
105
93
106
// / \brief Begins execution of this Task.
94
107
// / \returns true on error, false on success
95
108
bool execute ();
96
109
97
- // / \brief Reads data from the pipe , if any is available.
110
+ // / \brief Reads data from the pipes , if any is available.
98
111
// / \returns true on error, false on success
99
- bool readFromPipe ();
112
+ bool readFromPipes ();
100
113
101
114
// / \brief Performs any post-execution work for this Task, such as reading
102
115
// / piped output and closing the pipe.
@@ -121,6 +134,12 @@ bool Task::execute() {
121
134
pipe (FullPipe);
122
135
Pipe = FullPipe[0 ];
123
136
137
+ int FullErrorPipe[2 ];
138
+ if (SeparateErrors) {
139
+ pipe (FullErrorPipe);
140
+ ErrorPipe = FullErrorPipe[0 ];
141
+ }
142
+
124
143
// Get the environment to pass down to the subtask.
125
144
const char *const *envp = Env.empty () ? nullptr : Env.data ();
126
145
if (!envp) {
@@ -138,8 +157,19 @@ bool Task::execute() {
138
157
posix_spawn_file_actions_init (&FileActions);
139
158
140
159
posix_spawn_file_actions_adddup2 (&FileActions, FullPipe[1 ], STDOUT_FILENO);
141
- posix_spawn_file_actions_adddup2 (&FileActions, STDOUT_FILENO, STDERR_FILENO);
160
+
161
+ if (SeparateErrors) {
162
+ posix_spawn_file_actions_adddup2 (&FileActions, FullErrorPipe[1 ],
163
+ STDERR_FILENO);
164
+ } else {
165
+ posix_spawn_file_actions_adddup2 (&FileActions, STDOUT_FILENO,
166
+ STDERR_FILENO);
167
+ }
168
+
142
169
posix_spawn_file_actions_addclose (&FileActions, FullPipe[0 ]);
170
+ if (SeparateErrors) {
171
+ posix_spawn_file_actions_addclose (&FileActions, FullErrorPipe[0 ]);
172
+ }
143
173
144
174
// Spawn the subtask.
145
175
int spawnErr = posix_spawn (&Pid, ExecPath, &FileActions, nullptr ,
@@ -148,9 +178,15 @@ bool Task::execute() {
148
178
149
179
posix_spawn_file_actions_destroy (&FileActions);
150
180
close (FullPipe[1 ]);
181
+ if (SeparateErrors) {
182
+ close (FullErrorPipe[1 ]);
183
+ }
151
184
152
185
if (spawnErr != 0 || Pid == 0 ) {
153
186
close (FullPipe[0 ]);
187
+ if (SeparateErrors) {
188
+ close (FullErrorPipe[0 ]);
189
+ }
154
190
State = Finished;
155
191
return true ;
156
192
}
@@ -159,15 +195,25 @@ bool Task::execute() {
159
195
switch (Pid) {
160
196
case -1 : {
161
197
close (FullPipe[0 ]);
198
+ if (SeparateErrors) {
199
+ close (FullErrorPipe[0 ]);
200
+ }
162
201
State = Finished;
163
202
Pid = 0 ;
164
203
break ;
165
204
}
166
205
case 0 : {
167
206
// Child process: Execute the program.
168
207
dup2 (FullPipe[1 ], STDOUT_FILENO);
169
- dup2 (STDOUT_FILENO, STDERR_FILENO);
208
+ if (SeparateErrors) {
209
+ dup2 (FullErrorPipe[1 ], STDERR_FILENO);
210
+ } else {
211
+ dup2 (STDOUT_FILENO, STDERR_FILENO);
212
+ }
170
213
close (FullPipe[0 ]);
214
+ if (SeparateErrors) {
215
+ close (FullErrorPipe[0 ]);
216
+ }
171
217
execve (ExecPath, const_cast <char **>(argvp), const_cast <char **>(envp));
172
218
173
219
// If the execve() failed, we should exit. Follow Unix protocol and
@@ -184,6 +230,9 @@ bool Task::execute() {
184
230
}
185
231
186
232
close (FullPipe[1 ]);
233
+ if (SeparateErrors) {
234
+ close (FullErrorPipe[1 ]);
235
+ }
187
236
188
237
if (Pid == 0 )
189
238
return true ;
@@ -192,7 +241,7 @@ bool Task::execute() {
192
241
return false ;
193
242
}
194
243
195
- bool Task::readFromPipe ( ) {
244
+ static bool readFromAPipe ( int Pipe, std::string &Output ) {
196
245
char outputBuffer[1024 ];
197
246
ssize_t readBytes = 0 ;
198
247
while ((readBytes = read (Pipe, outputBuffer, sizeof (outputBuffer))) != 0 ) {
@@ -209,16 +258,27 @@ bool Task::readFromPipe() {
209
258
return false ;
210
259
}
211
260
261
+ bool Task::readFromPipes () {
262
+ bool Ret = readFromAPipe (Pipe, Output);
263
+ if (SeparateErrors) {
264
+ Ret |= readFromAPipe (ErrorPipe, Errors);
265
+ }
266
+ return Ret;
267
+ }
268
+
212
269
void Task::finishExecution () {
213
270
assert (State == Executing &&
214
271
" This Task must be executing to finish execution!" );
215
272
216
273
State = Finished;
217
274
218
275
// Read the output of the command, so we can use it later.
219
- readFromPipe ();
276
+ readFromPipes ();
220
277
221
278
close (Pipe);
279
+ if (SeparateErrors) {
280
+ close (ErrorPipe);
281
+ }
222
282
}
223
283
224
284
bool TaskQueue::supportsBufferingOutput () {
@@ -239,8 +299,10 @@ unsigned TaskQueue::getNumberOfParallelTasks() const {
239
299
}
240
300
241
301
void TaskQueue::addTask (const char *ExecPath, ArrayRef<const char *> Args,
242
- ArrayRef<const char *> Env, void *Context) {
243
- std::unique_ptr<Task> T (new Task (ExecPath, Args, Env, Context));
302
+ ArrayRef<const char *> Env, void *Context,
303
+ bool SeparateErrors) {
304
+ std::unique_ptr<Task> T (
305
+ new Task (ExecPath, Args, Env, Context, SeparateErrors));
244
306
QueuedTasks.push (std::move (T));
245
307
}
246
308
@@ -279,6 +341,8 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
279
341
}
280
342
281
343
PollFds.push_back ({ T->getPipe (), POLLIN | POLLPRI | POLLHUP, 0 });
344
+ // We should also poll T->getErrorPipe(), but this intrroduces timing
345
+ // issues with shutting down the task after reading getPipe().
282
346
ExecutingTasks[Pid] = std::move (T);
283
347
}
284
348
@@ -299,7 +363,7 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
299
363
if (fd.revents & POLLIN || fd.revents & POLLPRI || fd.revents & POLLHUP ||
300
364
fd.revents & POLLERR) {
301
365
// An event which we care about occurred. Find the appropriate Task.
302
- auto predicate = [&fd] (PidToTaskMap::value_type &value) -> bool {
366
+ auto predicate = [&fd](PidToTaskMap::value_type &value) -> bool {
303
367
return value.second ->getPipe () == fd.fd ;
304
368
};
305
369
@@ -310,7 +374,7 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
310
374
Task &T = *iter->second ;
311
375
if (fd.revents & POLLIN || fd.revents & POLLPRI) {
312
376
// There's data available to read.
313
- T.readFromPipe ();
377
+ T.readFromPipes ();
314
378
}
315
379
316
380
if (fd.revents & POLLHUP || fd.revents & POLLERR) {
@@ -339,7 +403,7 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
339
403
// If we have a TaskFinishedCallback, only set SubtaskFailed to
340
404
// true if the callback returns StopExecution.
341
405
SubtaskFailed = Finished (T.getPid (), Result, T.getOutput (),
342
- T.getContext ()) ==
406
+ T.getErrors (), T. getContext ()) ==
343
407
TaskFinishedResponse::StopExecution;
344
408
} else if (Result != 0 ) {
345
409
// Since we don't have a TaskFinishedCallback, treat a subtask
@@ -353,9 +417,9 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
353
417
StringRef ErrorMsg = strsignal (Signal);
354
418
355
419
if (Signalled) {
356
- TaskFinishedResponse Response = Signalled (T. getPid (), ErrorMsg,
357
- T.getOutput (),
358
- T.getContext ());
420
+ TaskFinishedResponse Response =
421
+ Signalled (T. getPid (), ErrorMsg, T.getOutput (), T. getErrors (),
422
+ T.getContext ());
359
423
if (Response == TaskFinishedResponse::StopExecution)
360
424
// If we have a TaskCrashedCallback, only set SubtaskFailed to
361
425
// true if the callback returns StopExecution.
0 commit comments