Skip to content

Commit 60a8e72

Browse files
authored
Merge pull request #68280 from compnerd/execution
AST,Basic: update support for process execution on Windows
2 parents bc9ee85 + 219f6ea commit 60a8e72

File tree

5 files changed

+162
-31
lines changed

5 files changed

+162
-31
lines changed

include/swift/AST/PluginRegistry.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,13 @@ class LoadedExecutablePlugin {
5252

5353
/// Represents the current process of the executable plugin.
5454
struct PluginProcess {
55-
const llvm::sys::procid_t pid;
56-
const int inputFileDescriptor;
57-
const int outputFileDescriptor;
55+
const llvm::sys::ProcessInfo process;
56+
const int input;
57+
const int output;
5858
bool isStale = false;
5959

60-
PluginProcess(llvm::sys::procid_t pid, int inputFileDescriptor,
61-
int outputFileDescriptor);
62-
60+
PluginProcess(llvm::sys::ProcessInfo process, int input, int output)
61+
: process(process), input(input), output(output) {}
6362
~PluginProcess();
6463

6564
ssize_t write(const void *buf, size_t nbyte) const;
@@ -138,7 +137,8 @@ class LoadedExecutablePlugin {
138137
llvm::erase_value(onReconnect, fn);
139138
}
140139

141-
llvm::sys::procid_t getPid() { return Process->pid; }
140+
llvm::sys::procid_t getPid() { return Process->process.Pid; }
141+
llvm::sys::process_t getProcess() { return Process->process.Process; }
142142

143143
NullTerminatedStringRef getExecutablePath() {
144144
return {ExecutablePath.c_str(), ExecutablePath.size()};

include/swift/Basic/Program.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,12 @@ int ExecuteInPlace(const char *Program, const char **args,
4040
const char **env = nullptr);
4141

4242
struct ChildProcessInfo {
43-
llvm::sys::procid_t Pid;
44-
int WriteFileDescriptor;
45-
int ReadFileDescriptor;
43+
llvm::sys::ProcessInfo ProcessInfo;
44+
int Write;
45+
int Read;
4646

47-
ChildProcessInfo(llvm::sys::procid_t Pid, int WriteFileDescriptor,
48-
int ReadFileDescriptor)
49-
: Pid(Pid), WriteFileDescriptor(WriteFileDescriptor),
50-
ReadFileDescriptor(ReadFileDescriptor) {}
47+
ChildProcessInfo(llvm::sys::ProcessInfo ProcessInfo, int Write, int Read)
48+
: ProcessInfo(ProcessInfo), Write(Write), Read(Read) {}
5149
};
5250

5351
/// This function executes the program using the argument provided.

lib/AST/PluginLoader.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,13 @@ PluginRegistry *PluginLoader::getRegistry() {
4141
static StringRef pluginModuleNameStringFromPath(StringRef path) {
4242
// Plugin library must be named 'lib${module name}(.dylib|.so|.dll)'.
4343
// FIXME: Shared library prefix might be different between platforms.
44+
#if defined(_WIN32)
45+
constexpr StringRef libPrefix{};
46+
constexpr StringRef libSuffix = ".dll";
47+
#else
4448
constexpr StringRef libPrefix = "lib";
4549
constexpr StringRef libSuffix = LTDL_SHLIB_EXT;
50+
#endif
4651

4752
StringRef filename = llvm::sys::path::filename(path);
4853
if (filename.starts_with(libPrefix) && filename.ends_with(libSuffix)) {

lib/AST/PluginRegistry.cpp

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ void *LoadedLibraryPlugin::getAddressOfSymbol(const char *symbolName) {
7575
auto &cached = resolvedSymbols[symbolName];
7676
if (cached)
7777
return cached;
78-
#if !defined(_WIN32)
78+
#if defined(_WIN32)
79+
cached = GetProcAddress(static_cast<HMODULE>(handle), symbolName);
80+
#else
7981
cached = dlsym(handle, symbolName);
8082
#endif
8183
return cached;
@@ -153,9 +155,8 @@ llvm::Error LoadedExecutablePlugin::spawnIfNeeded() {
153155
return llvm::errorCodeToError(childInfo.getError());
154156
}
155157

156-
Process = std::make_unique<PluginProcess>(childInfo->Pid,
157-
childInfo->ReadFileDescriptor,
158-
childInfo->WriteFileDescriptor);
158+
Process = std::make_unique<PluginProcess>(childInfo->ProcessInfo,
159+
childInfo->Read, childInfo->Write);
159160

160161
// Call "on reconnect" callbacks.
161162
for (auto *callback : onReconnect) {
@@ -165,15 +166,15 @@ llvm::Error LoadedExecutablePlugin::spawnIfNeeded() {
165166
return llvm::Error::success();
166167
}
167168

168-
LoadedExecutablePlugin::PluginProcess::PluginProcess(llvm::sys::procid_t pid,
169-
int inputFileDescriptor,
170-
int outputFileDescriptor)
171-
: pid(pid), inputFileDescriptor(inputFileDescriptor),
172-
outputFileDescriptor(outputFileDescriptor) {}
173-
174169
LoadedExecutablePlugin::PluginProcess::~PluginProcess() {
175-
close(inputFileDescriptor);
176-
close(outputFileDescriptor);
170+
#if defined(_WIN32)
171+
_close(input);
172+
_close(output);
173+
CloseHandle(process.Process);
174+
#else
175+
close(input);
176+
close(output);
177+
#endif
177178
}
178179

179180
LoadedExecutablePlugin::~LoadedExecutablePlugin() {
@@ -184,6 +185,17 @@ LoadedExecutablePlugin::~LoadedExecutablePlugin() {
184185

185186
ssize_t LoadedExecutablePlugin::PluginProcess::read(void *buf,
186187
size_t nbyte) const {
188+
#if defined(_WIN32)
189+
size_t nread = 0;
190+
while (nread < nbyte) {
191+
int n = _read(input, static_cast<char*>(buf) + nread,
192+
std::min(static_cast<size_t>(UINT32_MAX), nbyte - nread));
193+
if (n <= 0)
194+
break;
195+
nread += n;
196+
}
197+
return nread;
198+
#else
187199
ssize_t bytesToRead = nbyte;
188200
void *ptr = buf;
189201

@@ -195,7 +207,7 @@ ssize_t LoadedExecutablePlugin::PluginProcess::read(void *buf,
195207

196208
while (bytesToRead > 0) {
197209
ssize_t readingSize = std::min(ssize_t(INT32_MAX), bytesToRead);
198-
ssize_t readSize = ::read(inputFileDescriptor, ptr, readingSize);
210+
ssize_t readSize = ::read(input, ptr, readingSize);
199211
if (readSize <= 0) {
200212
// 0: EOF (the plugin exited?), -1: error (e.g. broken pipe.)
201213
// FIXME: Mark the plugin 'stale' and relaunch later.
@@ -206,10 +218,22 @@ ssize_t LoadedExecutablePlugin::PluginProcess::read(void *buf,
206218
}
207219

208220
return nbyte - bytesToRead;
221+
#endif
209222
}
210223

211224
ssize_t LoadedExecutablePlugin::PluginProcess::write(const void *buf,
212225
size_t nbyte) const {
226+
#if defined(_WIN32)
227+
size_t nwritten = 0;
228+
while (nwritten < nbyte) {
229+
int n = _write(output, static_cast<const char *>(buf) + nwritten,
230+
std::min(static_cast<size_t>(UINT32_MAX), nbyte - nwritten));
231+
if (n <= 0)
232+
break;
233+
nwritten += n;
234+
}
235+
return nwritten;
236+
#else
213237
ssize_t bytesToWrite = nbyte;
214238
const void *ptr = buf;
215239

@@ -221,7 +245,7 @@ ssize_t LoadedExecutablePlugin::PluginProcess::write(const void *buf,
221245

222246
while (bytesToWrite > 0) {
223247
ssize_t writingSize = std::min(ssize_t(INT32_MAX), bytesToWrite);
224-
ssize_t writtenSize = ::write(outputFileDescriptor, ptr, writingSize);
248+
ssize_t writtenSize = ::write(output, ptr, writingSize);
225249
if (writtenSize <= 0) {
226250
// -1: error (e.g. broken pipe,)
227251
// FIXME: Mark the plugin 'stale' and relaunch later.
@@ -231,13 +255,14 @@ ssize_t LoadedExecutablePlugin::PluginProcess::write(const void *buf,
231255
bytesToWrite -= writtenSize;
232256
}
233257
return nbyte - bytesToWrite;
258+
#endif
234259
}
235260

236261
llvm::Error LoadedExecutablePlugin::sendMessage(llvm::StringRef message) const {
237262
ssize_t writtenSize = 0;
238263

239264
if (dumpMessaging) {
240-
llvm::dbgs() << "->(plugin:" << Process->pid << ") " << message << "\n";
265+
llvm::dbgs() << "->(plugin:" << Process->process.Pid << ") " << message << '\n';
241266
}
242267

243268
const char *data = message.data();
@@ -297,7 +322,7 @@ llvm::Expected<std::string> LoadedExecutablePlugin::waitForNextMessage() const {
297322
}
298323

299324
if (dumpMessaging) {
300-
llvm::dbgs() << "<-(plugin:" << Process->pid << ") " << message << "\n";
325+
llvm::dbgs() << "<-(plugin:" << Process->process.Pid << ") " << message << "\n";
301326
}
302327

303328
return message;

lib/Basic/Program.cpp

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
#include "llvm/Config/config.h"
1919
#include "llvm/Support/Allocator.h"
2020
#include "llvm/Support/Program.h"
21+
#if defined(_WIN32)
22+
#include "llvm/Support/Windows/WindowsSupport.h"
23+
#endif
2124

25+
#include <memory>
2226
#include <system_error>
2327

2428
#if HAVE_POSIX_SPAWN
@@ -29,6 +33,12 @@
2933
#include <unistd.h>
3034
#endif
3135

36+
#if defined(_WIN32)
37+
#define WIN32_LEAN_AND_MEAN
38+
#include <Windows.h>
39+
#include <io.h>
40+
#endif
41+
3242
using namespace swift;
3343

3444
int swift::ExecuteInPlace(const char *Program, const char **args,
@@ -175,7 +185,100 @@ swift::ExecuteWithPipe(llvm::StringRef program,
175185
#endif
176186
close(p1.read);
177187
close(p2.write);
178-
return ChildProcessInfo(pid, p1.write, p2.read);
188+
llvm::sys::ProcessInfo proc;
189+
proc.Pid = pid;
190+
return ChildProcessInfo(proc, p1.write, p2.read);
191+
}
192+
193+
#elif defined(_WIN32)
194+
195+
llvm::ErrorOr<swift::ChildProcessInfo>
196+
swift::ExecuteWithPipe(llvm::StringRef program,
197+
llvm::ArrayRef<llvm::StringRef> args,
198+
llvm::Optional<llvm::ArrayRef<llvm::StringRef>> env) {
199+
using unique_handle = std::unique_ptr<void, decltype(&CloseHandle)>;
200+
enum { PI_READ, PI_WRITE };
201+
202+
unique_handle input[2] = {
203+
{INVALID_HANDLE_VALUE, CloseHandle},
204+
{INVALID_HANDLE_VALUE, CloseHandle},
205+
};
206+
unique_handle output[2] = {
207+
{INVALID_HANDLE_VALUE, CloseHandle},
208+
{INVALID_HANDLE_VALUE, CloseHandle},
209+
};
210+
unique_handle error{INVALID_HANDLE_VALUE, CloseHandle};
211+
HANDLE hRead = INVALID_HANDLE_VALUE, hWrite = INVALID_HANDLE_VALUE;
212+
SECURITY_ATTRIBUTES saAttrs{sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
213+
214+
if (!CreatePipe(&hRead, &hWrite, &saAttrs, 0))
215+
return std::error_code(GetLastError(), std::system_category());
216+
output[PI_READ].reset(hRead);
217+
output[PI_WRITE].reset(hWrite);
218+
219+
if (!SetHandleInformation(output[PI_READ].get(), HANDLE_FLAG_INHERIT, FALSE))
220+
return std::error_code(GetLastError(), std::system_category());
221+
222+
if (!CreatePipe(&hRead, &hWrite, &saAttrs, 0))
223+
return std::error_code(GetLastError(), std::system_category());
224+
input[PI_READ].reset(hRead);
225+
input[PI_WRITE].reset(hWrite);
226+
227+
if (!SetHandleInformation(input[PI_WRITE].get(), HANDLE_FLAG_INHERIT, FALSE))
228+
return std::error_code(GetLastError(), std::system_category());
229+
230+
if (!DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE),
231+
GetCurrentProcess(), &hWrite, DUPLICATE_SAME_ACCESS,
232+
TRUE, DUPLICATE_SAME_ACCESS))
233+
return std::error_code(GetLastError(), std::system_category());
234+
error.reset(hWrite);
235+
236+
STARTUPINFO si = {0};
237+
si.cb = sizeof(si);
238+
si.hStdInput = input[PI_READ].get();
239+
si.hStdOutput = output[PI_WRITE].get();
240+
si.hStdError = error.get();
241+
si.dwFlags = STARTF_USESTDHANDLES;
242+
243+
llvm::SmallVector<wchar_t, MAX_PATH> executable;
244+
if (std::error_code ec = llvm::sys::windows::widenPath(program, executable))
245+
return ec;
246+
247+
std::vector<StringRef> components;
248+
components.push_back(program);
249+
components.assign(args.begin(), args.end());
250+
llvm::ErrorOr<std::wstring> commandline =
251+
llvm::sys::flattenWindowsCommandLine(components);
252+
if (!commandline)
253+
return commandline.getError();
254+
255+
std::vector<wchar_t> command(commandline->size() + 1, 0);
256+
std::copy(commandline->begin(), commandline->end(), command.begin());
257+
258+
PROCESS_INFORMATION pi = {0};
259+
if (!CreateProcessW(executable.data(),
260+
command.data(), nullptr, nullptr, TRUE, 0, nullptr,
261+
nullptr, &si, &pi))
262+
return std::error_code(GetLastError(), std::system_category());
263+
264+
unique_handle hThread{pi.hThread, CloseHandle};
265+
unique_handle hProcess{pi.hProcess, CloseHandle};
266+
267+
int ifd = _open_osfhandle(reinterpret_cast<intptr_t>(input[PI_WRITE].get()), 0);
268+
if (ifd < 0)
269+
return std::error_code(errno, std::system_category());
270+
input[PI_WRITE].release();
271+
272+
int ofd = _open_osfhandle(reinterpret_cast<intptr_t>(output[PI_READ].get()), 0);
273+
if (ofd < 0) {
274+
_close(ifd);
275+
return std::error_code(errno, std::system_category());
276+
}
277+
output[PI_READ].release();
278+
279+
llvm::sys::ProcessInfo proc;
280+
proc.Process = pi.hProcess;
281+
return ChildProcessInfo(proc, ifd, ofd);
179282
}
180283

181284
#else // HAVE_UNISTD_H

0 commit comments

Comments
 (0)