Skip to content

Commit d5ab98d

Browse files
authored
Merge pull request #68268 from compnerd/reinventing-the-wheel-poorly
swift-plugin-server: adjust API for portability
2 parents 60a8e72 + 7f99867 commit d5ab98d

File tree

3 files changed

+91
-28
lines changed

3 files changed

+91
-28
lines changed

tools/swift-plugin-server/Sources/CSwiftPluginServer/PluginServer.cpp

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@
1313
#include "PluginServer.h"
1414
#include "swift/ABI/MetadataValues.h"
1515
#include "swift/Demangling/Demangle.h"
16+
#include "llvm/Support/DynamicLibrary.h"
1617

18+
#if defined(_WIN32)
19+
#include <io.h>
20+
#elif defined(__unix__) || defined(__APPLE__)
1721
#include <dlfcn.h>
22+
#include <unistd.h>
23+
#endif
24+
1825
#include <errno.h>
1926
#include <string.h>
20-
#include <unistd.h>
2127

2228
using namespace swift;
2329

@@ -32,6 +38,46 @@ struct ConnectionHandle {
3238
} // namespace
3339

3440
const void *PluginServer_createConnection(const char **errorMessage) {
41+
#if defined(_WIN32)
42+
struct unique_fd {
43+
unique_fd(int fd) : fd_(fd) {}
44+
unique_fd(const unique_fd &) = delete;
45+
unique_fd &operator=(const unique_fd &) = delete;
46+
unique_fd &operator=(unique_fd &&) = delete;
47+
unique_fd(unique_fd &&uf) : fd_(uf.fd_) { uf.fd_ = -1; }
48+
~unique_fd() { if (fd_ > 0) _close(fd_); }
49+
50+
int operator*() const { return fd_; }
51+
int release() { int fd = fd_; fd_ = -1; return fd; }
52+
53+
private:
54+
int fd_;
55+
};
56+
57+
unique_fd ifd{_dup(_fileno(stdin))};
58+
if (*ifd < 0) {
59+
*errorMessage = _strerror(nullptr);
60+
return nullptr;
61+
}
62+
63+
if (_close(_fileno(stdin)) < 0) {
64+
*errorMessage = _strerror(nullptr);
65+
return nullptr;
66+
}
67+
68+
unique_fd ofd{_dup(_fileno(stdout))};
69+
if (*ofd < 0) {
70+
*errorMessage = _strerror(nullptr);
71+
return nullptr;
72+
}
73+
74+
if (_dup2(_fileno(stderr), _fileno(stdout)) < 0) {
75+
*errorMessage = _strerror(nullptr);
76+
return nullptr;
77+
}
78+
79+
return new ConnectionHandle(ifd.release(), ofd.release());
80+
#else
3581
// Duplicate the `stdin` file descriptor, which we will then use for
3682
// receiving messages from the plugin host.
3783
auto inputFD = dup(STDIN_FILENO);
@@ -65,37 +111,48 @@ const void *PluginServer_createConnection(const char **errorMessage) {
65111

66112
// Open a message channel for communicating with the plugin host.
67113
return new ConnectionHandle(inputFD, outputFD);
114+
#endif
68115
}
69116

70-
void PluginServer_destroyConnection(const void *connHandle) {
71-
const auto *conn = static_cast<const ConnectionHandle *>(connHandle);
72-
delete conn;
117+
void PluginServer_destroyConnection(const void *server) {
118+
delete static_cast<const ConnectionHandle *>(server);
73119
}
74120

75-
long PluginServer_read(const void *connHandle, void *data,
76-
unsigned long nbyte) {
77-
const auto *conn = static_cast<const ConnectionHandle *>(connHandle);
78-
return ::read(conn->inputFD, data, nbyte);
121+
size_t PluginServer_read(const void *server, void *data, size_t nbyte) {
122+
const auto *connection = static_cast<const ConnectionHandle *>(server);
123+
#if defined(_WIN32)
124+
return _read(connection->inputFD, data, nbyte);
125+
#else
126+
return ::read(connection->inputFD, data, nbyte);
127+
#endif
79128
}
80129

81-
long PluginServer_write(const void *connHandle, const void *data,
82-
unsigned long nbyte) {
83-
const auto *conn = static_cast<const ConnectionHandle *>(connHandle);
84-
return ::write(conn->outputFD, data, nbyte);
130+
size_t PluginServer_write(const void *server, const void *data, size_t nbyte) {
131+
const auto *connection = static_cast<const ConnectionHandle *>(server);
132+
#if defined(_WIN32)
133+
return _write(connection->outputFD, data, nbyte);
134+
#else
135+
return ::write(connection->outputFD, data, nbyte);
136+
#endif
85137
}
86138

87-
void *PluginServer_dlopen(const char *filename, const char **errorMessage) {
88-
auto *handle = ::dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
89-
if (!handle) {
90-
*errorMessage = dlerror();
91-
}
92-
return handle;
139+
void *PluginServer_load(const char *plugin, const char **errorMessage) {
140+
// Use a static allocation for the error as the client will not release the
141+
// string. POSIX 2008 (IEEE-1003.1-2008) specifies that it is implementation
142+
// defined if `dlerror` is re-entrant. Take advantage of that and make it
143+
// thread-unsafe. This ensures that the string outlives the call permitting
144+
// the client to duplicate it.
145+
static std::string error;
146+
auto library = llvm::sys::DynamicLibrary::getLibrary(plugin, &error);
147+
if (library.isValid())
148+
return library.getOSSpecificHandle();
149+
*errorMessage = error.c_str();
150+
return nullptr;
93151
}
94152

95153
const void *PluginServer_lookupMacroTypeMetadataByExternalName(
96154
const char *moduleName, const char *typeName, void *libraryHint,
97155
const char **errorMessage) {
98-
99156
// Look up the type metadata accessor as a struct, enum, or class.
100157
const Demangle::Node::Kind typeKinds[] = {
101158
Demangle::Node::Kind::Structure,
@@ -108,8 +165,12 @@ const void *PluginServer_lookupMacroTypeMetadataByExternalName(
108165
auto symbolName =
109166
mangledNameForTypeMetadataAccessor(moduleName, typeName, typeKind);
110167

111-
auto *handle = libraryHint ? libraryHint : RTLD_DEFAULT;
112-
accessorAddr = ::dlsym(handle, symbolName.c_str());
168+
#if !defined(_WIN32)
169+
if (libraryHint == nullptr)
170+
libraryHint = RTLD_DEFAULT;
171+
#endif
172+
accessorAddr = llvm::sys::DynamicLibrary{libraryHint}
173+
.getAddressOfSymbol(symbolName.c_str());
113174
if (accessorAddr)
114175
break;
115176
}

tools/swift-plugin-server/Sources/CSwiftPluginServer/include/PluginServer.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#ifndef SWIFT_PLUGINSERVER_PLUGINSERVER_H
1414
#define SWIFT_PLUGINSERVER_PLUGINSERVER_H
1515

16+
#include <stddef.h>
17+
#include <stdint.h>
18+
1619
#ifdef __cplusplus
1720
extern "C" {
1821
#endif
@@ -29,18 +32,17 @@ const void *PluginServer_createConnection(const char **errorMessage);
2932
void PluginServer_destroyConnection(const void *connHandle);
3033

3134
/// Read bytes from the IPC communication handle.
32-
long PluginServer_read(const void *connHandle, void *data, unsigned long nbyte);
35+
size_t PluginServer_read(const void *connHandle, void *data, size_t nbyte);
3336

3437
/// Write bytes to the IPC communication handle.
35-
long PluginServer_write(const void *connHandle, const void *data,
36-
unsigned long nbyte);
38+
size_t PluginServer_write(const void *connHandle, const void *data, size_t nbyte);
3739

3840
//===----------------------------------------------------------------------===//
3941
// Dynamic link
4042
//===----------------------------------------------------------------------===//
4143

4244
/// Load a dynamic link library, and return the handle.
43-
void *PluginServer_dlopen(const char *filename, const char **errorMessage);
45+
void *PluginServer_load(const char *filename, const char **errorMessage);
4446

4547
/// Resolve a type metadata by a pair of the module name and the type name.
4648
/// 'libraryHint' is a

tools/swift-plugin-server/Sources/swift-plugin-server/swift-plugin-server.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ extension SwiftPluginServer: PluginProvider {
4747
/// Load a macro implementation from the dynamic link library.
4848
func loadPluginLibrary(libraryPath: String, moduleName: String) throws {
4949
var errorMessage: UnsafePointer<CChar>?
50-
guard let dlHandle = PluginServer_dlopen(libraryPath, &errorMessage) else {
50+
guard let dlHandle = PluginServer_load(libraryPath, &errorMessage) else {
5151
throw PluginServerError(message: String(cString: errorMessage!))
5252
}
5353
loadedLibraryPlugins[moduleName] = dlHandle
@@ -172,7 +172,7 @@ final class PluginHostConnection: MessageConnection {
172172
var ptr = buffer.baseAddress!
173173

174174
while (bytesToWrite > 0) {
175-
let writtenSize = PluginServer_write(handle, ptr, UInt(bytesToWrite))
175+
let writtenSize = PluginServer_write(handle, ptr, Int(bytesToWrite))
176176
if (writtenSize <= 0) {
177177
// error e.g. broken pipe.
178178
break
@@ -193,7 +193,7 @@ final class PluginHostConnection: MessageConnection {
193193
var ptr = buffer.baseAddress!
194194

195195
while bytesToRead > 0 {
196-
let readSize = PluginServer_read(handle, ptr, UInt(bytesToRead))
196+
let readSize = PluginServer_read(handle, ptr, Int(bytesToRead))
197197
if (readSize <= 0) {
198198
// 0: EOF (the host closed), -1: Broken pipe (the host crashed?)
199199
break;

0 commit comments

Comments
 (0)