Skip to content

Commit 06ad3a7

Browse files
committed
AST,Basic: update support for process execution on Windows
Implement process launching on Windows to support macros. Prefer to use the LLVM types wherever possible. The pipes are converted into file descriptors as the types are internal to the process. This allows us to have similar paths on both sides and avoid having to drag in `Windows.h` for the definition of `HANDLE`. This is the core missing functionality for Windows to support macros.
1 parent ffc9fb3 commit 06ad3a7

File tree

5 files changed

+157
-28
lines changed

5 files changed

+157
-28
lines changed

include/swift/AST/PluginRegistry.h

+7-7
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

+5-7
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

+5
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

+39-14
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

@@ -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

@@ -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

+101
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,
@@ -178,6 +188,97 @@ swift::ExecuteWithPipe(llvm::StringRef program,
178188
return ChildProcessInfo(pid, p1.write, p2.read);
179189
}
180190

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

183284
llvm::ErrorOr<swift::ChildProcessInfo>

0 commit comments

Comments
 (0)