Skip to content

Commit dbfb163

Browse files
authored
Merge pull request #24055 from alexshap/task_queue_windows
[Windows] Add initial implementation for TaskQueue
2 parents 60ee952 + 1525e9b commit dbfb163

File tree

6 files changed

+348
-101
lines changed

6 files changed

+348
-101
lines changed

lib/Basic/Default/Task.inc

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//===--- Task.inc - ---------------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
/// This file contains the default implementation of the class Task
15+
///
16+
//===----------------------------------------------------------------------===//
17+
18+
#include "swift/Basic/LLVM.h"
19+
#include "llvm/ADT/ArrayRef.h"
20+
#include "llvm/ADT/StringExtras.h"
21+
#include "llvm/Support/FileSystem.h"
22+
#include "llvm/Support/Program.h"
23+
#include "llvm/Support/Signals.h"
24+
25+
namespace swift {
26+
namespace sys {
27+
28+
// Platform-independent implementation of Task,
29+
// a particular platform can provide its own more efficient version.
30+
class Task {
31+
public:
32+
/// The path to the executable which this Task will execute.
33+
const char *ExecPath;
34+
35+
/// Any arguments which should be passed during execution.
36+
ArrayRef<const char *> Args;
37+
38+
/// The environment which should be used during execution. If empty,
39+
/// the current process's environment will be used instead.
40+
ArrayRef<const char *> Env;
41+
42+
/// Context associated with this Task.
43+
void *Context;
44+
45+
/// True if the errors of the Task should be stored in Errors instead of
46+
/// Output.
47+
bool SeparateErrors;
48+
49+
SmallString<64> StdoutPath;
50+
51+
SmallString<64> StderrPath;
52+
53+
llvm::sys::ProcessInfo PI;
54+
55+
Task(const char *ExecPath, ArrayRef<const char *> Args,
56+
ArrayRef<const char *> Env = None, void *Context = nullptr,
57+
bool SeparateErrors = false)
58+
: ExecPath(ExecPath), Args(Args), Env(Env), Context(Context),
59+
SeparateErrors(SeparateErrors) {}
60+
61+
/// Begins execution of this Task.
62+
/// \returns true on error.
63+
bool execute();
64+
};
65+
66+
bool Task::execute() {
67+
SmallVector<const char *, 128> Argv;
68+
Argv.push_back(ExecPath);
69+
Argv.append(Args.begin(), Args.end());
70+
Argv.push_back(nullptr);
71+
72+
Optional<ArrayRef<StringRef>> Envp =
73+
Env.empty() ? decltype(Envp)(None)
74+
: decltype(Envp)(llvm::toStringRefArray(Env.data()));
75+
76+
if (llvm::sys::fs::createTemporaryFile("stdout", "tmp", StdoutPath))
77+
return true;
78+
llvm::sys::RemoveFileOnSignal(StdoutPath);
79+
80+
if (SeparateErrors) {
81+
if (llvm::sys::fs::createTemporaryFile("stderr", "tmp", StderrPath))
82+
return true;
83+
llvm::sys::RemoveFileOnSignal(StderrPath);
84+
}
85+
86+
Optional<StringRef> Redirects[] = {
87+
None, {StdoutPath}, {SeparateErrors ? StderrPath : StdoutPath}};
88+
89+
bool ExecutionFailed = false;
90+
PI = llvm::sys::ExecuteNoWait(ExecPath, llvm::toStringRefArray(Argv.data()),
91+
Envp, Redirects, /*memoryLimit*/ 0,
92+
/*ErrMsg*/ nullptr, &ExecutionFailed);
93+
return ExecutionFailed;
94+
}
95+
96+
} // namespace sys
97+
} // namespace swift

lib/Basic/Default/TaskQueue.inc

Lines changed: 41 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@
2121
//===----------------------------------------------------------------------===//
2222

2323
#include "swift/Basic/TaskQueue.h"
24-
2524
#include "swift/Basic/LLVM.h"
26-
2725
#include "llvm/ADT/StringExtras.h"
2826
#include "llvm/Support/FileSystem.h"
2927
#include "llvm/Support/MemoryBuffer.h"
@@ -35,36 +33,9 @@
3533
#include <psapi.h>
3634
#endif
3735

38-
using namespace llvm::sys;
39-
40-
namespace swift {
41-
namespace sys {
42-
43-
class Task {
44-
public:
45-
/// The path to the executable which this Task will execute.
46-
const char *ExecPath;
47-
48-
/// Any arguments which should be passed during execution.
49-
ArrayRef<const char *> Args;
50-
51-
/// The environment which should be used during execution. If empty,
52-
/// the current process's environment will be used instead.
53-
ArrayRef<const char *> Env;
54-
55-
/// True if the errors of the Task should be stored in Errors instead of Output.
56-
bool SeparateErrors;
57-
58-
/// Context associated with this Task.
59-
void *Context;
60-
61-
Task(const char *ExecPath, ArrayRef<const char *> Args,
62-
ArrayRef<const char *> Env = llvm::None, void *Context = nullptr, bool SeparateErrors = false)
63-
: ExecPath(ExecPath), Args(Args), Env(Env), Context(Context), SeparateErrors(SeparateErrors) {}
64-
};
36+
#include "Task.inc"
6537

66-
} // end namespace sys
67-
} // end namespace swift
38+
using namespace llvm::sys;
6839

6940
bool TaskQueue::supportsBufferingOutput() {
7041
// The default implementation supports buffering output.
@@ -84,7 +55,7 @@ unsigned TaskQueue::getNumberOfParallelTasks() const {
8455
void TaskQueue::addTask(const char *ExecPath, ArrayRef<const char *> Args,
8556
ArrayRef<const char *> Env, void *Context,
8657
bool SeparateErrors) {
87-
std::unique_ptr<Task> T(new Task(ExecPath, Args, Env, Context, SeparateErrors));
58+
auto T = make_unique<Task>(ExecPath, Args, Env, Context, SeparateErrors);
8859
QueuedTasks.push(std::move(T));
8960
}
9061

@@ -99,54 +70,27 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
9970
while (!QueuedTasks.empty() && ContinueExecution) {
10071
std::unique_ptr<Task> T(QueuedTasks.front().release());
10172
QueuedTasks.pop();
73+
bool ExecutionFailed = T->execute();
10274

103-
SmallVector<const char *, 128> Argv;
104-
Argv.push_back(T->ExecPath);
105-
Argv.append(T->Args.begin(), T->Args.end());
106-
Argv.push_back(nullptr);
107-
108-
llvm::Optional<llvm::ArrayRef<llvm::StringRef>> Envp =
109-
T->Env.empty() ? decltype(Envp)(None)
110-
: decltype(Envp)(llvm::toStringRefArray(T->Env.data()));
111-
112-
llvm::SmallString<64> stdoutPath;
113-
if (fs::createTemporaryFile("stdout", "tmp", stdoutPath))
114-
return true;
115-
llvm::sys::RemoveFileOnSignal(stdoutPath);
116-
117-
llvm::SmallString<64> stderrPath;
118-
if (T->SeparateErrors) {
119-
if (fs::createTemporaryFile("stderr", "tmp", stdoutPath))
120-
return true;
121-
llvm::sys::RemoveFileOnSignal(stderrPath);
122-
}
123-
124-
Optional<StringRef> redirects[] = {None, {stdoutPath}, {T->SeparateErrors ? stderrPath : stdoutPath}};
125-
126-
bool ExecutionFailed = false;
127-
ProcessInfo PI = ExecuteNoWait(T->ExecPath,
128-
llvm::toStringRefArray(Argv.data()), Envp,
129-
/*redirects*/redirects, /*memoryLimit*/0,
130-
/*ErrMsg*/nullptr, &ExecutionFailed);
13175
if (ExecutionFailed) {
13276
return true;
13377
}
13478

13579
if (Began) {
136-
Began(PI.Pid, T->Context);
80+
Began(T->PI.Pid, T->Context);
13781
}
13882

13983
std::string ErrMsg;
140-
PI = Wait(PI, 0, true, &ErrMsg);
141-
int ReturnCode = PI.ReturnCode;
84+
T->PI = Wait(T->PI, 0, true, &ErrMsg);
85+
int ReturnCode = T->PI.ReturnCode;
14286

143-
auto stdoutBuffer = llvm::MemoryBuffer::getFile(stdoutPath);
144-
StringRef stdoutContents = stdoutBuffer.get()->getBuffer();
87+
auto StdoutBuffer = llvm::MemoryBuffer::getFile(T->StdoutPath);
88+
StringRef StdoutContents = StdoutBuffer.get()->getBuffer();
14589

146-
StringRef stderrContents;
90+
StringRef StderrContents;
14791
if (T->SeparateErrors) {
148-
auto stderrBuffer = llvm::MemoryBuffer::getFile(stderrPath);
149-
stderrContents = stderrBuffer.get()->getBuffer();
92+
auto StderrBuffer = llvm::MemoryBuffer::getFile(T->StderrPath);
93+
StderrContents = StderrBuffer.get()->getBuffer();
15094
}
15195

15296
#if defined(_WIN32)
@@ -155,36 +99,37 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
15599
//
156100
// This isn't a true signal on Windows, but we'll treat it as such so that
157101
// we clean up after it properly
158-
bool crashed = ReturnCode & 0xC0000000;
159-
160-
FILETIME creationTime;
161-
FILETIME exitTime;
162-
FILETIME utimeTicks;
163-
FILETIME stimeTicks;
164-
PROCESS_MEMORY_COUNTERS counters = {};
165-
GetProcessTimes(PI.Process, &creationTime, &exitTime, &stimeTicks,
166-
&utimeTicks);
102+
bool Crashed = ReturnCode & 0xC0000000;
103+
104+
FILETIME CreationTime;
105+
FILETIME ExitTime;
106+
FILETIME UtimeTicks;
107+
FILETIME StimeTicks;
108+
PROCESS_MEMORY_COUNTERS Counters = {};
109+
GetProcessTimes(T->PI.Process, &CreationTime, &ExitTime, &StimeTicks,
110+
&UtimeTicks);
167111
// Each tick is 100ns
168-
uint64_t utime =
169-
((uint64_t)utimeTicks.dwHighDateTime << 32 | utimeTicks.dwLowDateTime) /
112+
uint64_t Utime =
113+
((uint64_t)UtimeTicks.dwHighDateTime << 32 | UtimeTicks.dwLowDateTime) /
170114
10;
171-
uint64_t stime =
172-
((uint64_t)stimeTicks.dwHighDateTime << 32 | stimeTicks.dwLowDateTime) /
115+
uint64_t Stime =
116+
((uint64_t)StimeTicks.dwHighDateTime << 32 | StimeTicks.dwLowDateTime) /
173117
10;
174-
GetProcessMemoryInfo(PI.Process, &counters, sizeof(counters));
118+
GetProcessMemoryInfo(T->PI.Process, &Counters, sizeof(Counters));
175119

176-
TaskProcessInformation tpi(PI.Pid, utime, stime,
177-
counters.PeakWorkingSetSize);
120+
TaskProcessInformation TPI(T->PI.Pid, Utime, Stime,
121+
Counters.PeakWorkingSetSize);
178122
#else
179-
// Wait() returning a return code of -2 indicates the process received
180-
// a signal during execution.
181-
bool crashed = ReturnCode == -2;
182-
TaskProcessInformation tpi(PI.Pid);
123+
// Wait() returning a return code of -2 indicates the process received
124+
// a signal during execution.
125+
bool Crashed = ReturnCode == -2;
126+
TaskProcessInformation TPI(T->PI.Pid);
183127
#endif
184-
if (crashed) {
128+
if (Crashed) {
185129
if (Signalled) {
186130
TaskFinishedResponse Response =
187-
Signalled(PI.Pid, ErrMsg, stdoutContents, stderrContents, T->Context, ReturnCode, tpi);
131+
Signalled(T->PI.Pid, ErrMsg, StdoutContents, StderrContents,
132+
T->Context, ReturnCode, TPI);
188133
ContinueExecution = Response != TaskFinishedResponse::StopExecution;
189134
} else {
190135
// If we don't have a Signalled callback, unconditionally stop.
@@ -194,16 +139,17 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
194139
// Wait() returned a normal return code, so just indicate that the task
195140
// finished.
196141
if (Finished) {
197-
TaskFinishedResponse Response = Finished(PI.Pid, PI.ReturnCode,
198-
stdoutContents, stderrContents, tpi, T->Context);
142+
TaskFinishedResponse Response =
143+
Finished(T->PI.Pid, T->PI.ReturnCode, StdoutContents,
144+
StderrContents, TPI, T->Context);
199145
ContinueExecution = Response != TaskFinishedResponse::StopExecution;
200-
} else if (PI.ReturnCode != 0) {
146+
} else if (T->PI.ReturnCode != 0) {
201147
ContinueExecution = false;
202148
}
203149
}
204-
llvm::sys::fs::remove(stdoutPath);
150+
llvm::sys::fs::remove(T->StdoutPath);
205151
if (T->SeparateErrors)
206-
llvm::sys::fs::remove(stderrPath);
152+
llvm::sys::fs::remove(T->StderrPath);
207153
}
208154

209155
return !ContinueExecution;

lib/Basic/TaskQueue.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ using namespace swift::sys;
2525
// Include the correct TaskQueue implementation.
2626
#if LLVM_ON_UNIX && !defined(__CYGWIN__) && !defined(__HAIKU__)
2727
#include "Unix/TaskQueue.inc"
28+
#elif defined(_WIN32)
29+
#include "Windows/TaskQueue.inc"
2830
#else
2931
#include "Default/TaskQueue.inc"
3032
#endif

0 commit comments

Comments
 (0)