Skip to content

Commit c6222bf

Browse files
committed
swift-plugin-server: adjust API for portability
This begins reworking the API to be less POSIX centric and more generally usable. The API was defined in terms of `dlopen`/`dlsym` rather than the better suited `llvm::sys::DynamicLibrary` APIs which would avoid most of the work that needs to be done here for platform specifics.
1 parent ffc9fb3 commit c6222bf

File tree

3 files changed

+86
-26
lines changed

3 files changed

+86
-26
lines changed

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

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,17 @@ const void *PluginServer_createConnection(const char **errorMessage);
2929
void PluginServer_destroyConnection(const void *connHandle);
3030

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

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

3837
//===----------------------------------------------------------------------===//
3938
// Dynamic link
4039
//===----------------------------------------------------------------------===//
4140

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

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

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

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

0 commit comments

Comments
 (0)