Skip to content

Commit 1125828

Browse files
committed
[swift-plugin-server] Use StandardIOMessageConnection
1 parent cd54cc1 commit 1125828

File tree

3 files changed

+2
-248
lines changed

3 files changed

+2
-248
lines changed

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

+1-110
Original file line numberDiff line numberDiff line change
@@ -22,121 +22,12 @@
2222
#include <unistd.h>
2323
#endif
2424

25+
#include <string>
2526
#include <errno.h>
2627
#include <string.h>
2728

2829
using namespace swift;
2930

30-
namespace {
31-
struct ConnectionHandle {
32-
int inputFD;
33-
int outputFD;
34-
35-
ConnectionHandle(int inputFD, int outputFD)
36-
: inputFD(inputFD), outputFD(outputFD) {}
37-
};
38-
} // namespace
39-
40-
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
81-
// Duplicate the `stdin` file descriptor, which we will then use for
82-
// receiving messages from the plugin host.
83-
auto inputFD = dup(STDIN_FILENO);
84-
if (inputFD < 0) {
85-
*errorMessage = strerror(errno);
86-
return nullptr;
87-
}
88-
89-
// Having duplicated the original standard-input descriptor, we close
90-
// `stdin` so that attempts by the plugin to read console input (which
91-
// are usually a mistake) return errors instead of blocking.
92-
if (close(STDIN_FILENO) < 0) {
93-
*errorMessage = strerror(errno);
94-
return nullptr;
95-
}
96-
97-
// Duplicate the `stdout` file descriptor, which we will then use for
98-
// sending messages to the plugin host.
99-
auto outputFD = dup(STDOUT_FILENO);
100-
if (outputFD < 0) {
101-
*errorMessage = strerror(errno);
102-
return nullptr;
103-
}
104-
105-
// Having duplicated the original standard-output descriptor, redirect
106-
// `stdout` to `stderr` so that all free-form text output goes there.
107-
if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) {
108-
*errorMessage = strerror(errno);
109-
return nullptr;
110-
}
111-
112-
// Open a message channel for communicating with the plugin host.
113-
return new ConnectionHandle(inputFD, outputFD);
114-
#endif
115-
}
116-
117-
void PluginServer_destroyConnection(const void *server) {
118-
delete static_cast<const ConnectionHandle *>(server);
119-
}
120-
121-
ptrdiff_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
128-
}
129-
130-
ptrdiff_t PluginServer_write(const void *server, const void *data,
131-
size_t nbyte) {
132-
const auto *connection = static_cast<const ConnectionHandle *>(server);
133-
#if defined(_WIN32)
134-
return _write(connection->outputFD, data, nbyte);
135-
#else
136-
return ::write(connection->outputFD, data, nbyte);
137-
#endif
138-
}
139-
14031
void *PluginServer_load(const char *plugin, const char **errorMessage) {
14132
// Use a static allocation for the error as the client will not release the
14233
// string. POSIX 2008 (IEEE-1003.1-2008) specifies that it is implementation

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

-18
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,6 @@
1919
extern "C" {
2020
#endif
2121

22-
//===----------------------------------------------------------------------===//
23-
// Inter-process communication.
24-
//===----------------------------------------------------------------------===//
25-
26-
/// Create an IPC communication handle.
27-
const void *PluginServer_createConnection(const char **errorMessage);
28-
29-
/// Destroy an IPC communication handle created by
30-
/// 'PluginServer_createConnection'.
31-
void PluginServer_destroyConnection(const void *connHandle);
32-
33-
/// Read bytes from the IPC communication handle.
34-
ptrdiff_t PluginServer_read(const void *connHandle, void *data, size_t nbyte);
35-
36-
/// Write bytes to the IPC communication handle.
37-
ptrdiff_t PluginServer_write(const void *connHandle, const void *data,
38-
size_t nbyte);
39-
4022
//===----------------------------------------------------------------------===//
4123
// Dynamic link
4224
//===----------------------------------------------------------------------===//

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

+1-120
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ final class SwiftPluginServer {
3838

3939
/// @main entry point.
4040
static func main() throws {
41-
let connection = try PluginHostConnection()
41+
let connection = try StandardIOMessageConnection()
4242
let listener = CompilerPluginMessageListener(
4343
connection: connection,
4444
provider: self.init()
@@ -98,125 +98,6 @@ extension SwiftPluginServer: PluginProvider {
9898
}
9999
}
100100

101-
final class PluginHostConnection: MessageConnection {
102-
let handle: UnsafeRawPointer
103-
init() throws {
104-
var errorMessage: UnsafePointer<CChar>? = nil
105-
guard let handle = PluginServer_createConnection(&errorMessage) else {
106-
throw PluginServerError(message: String(cString: errorMessage!))
107-
}
108-
self.handle = handle
109-
}
110-
111-
deinit {
112-
PluginServer_destroyConnection(self.handle)
113-
}
114-
115-
func sendMessage<TX: Encodable>(_ message: TX) throws {
116-
try JSON.encode(message).withUnsafeBufferPointer { buffer in
117-
try buffer.withMemoryRebound(to: Int8.self) { buffer in
118-
try self.sendMessageData(buffer)
119-
}
120-
}
121-
}
122-
123-
func waitForNextMessage<RX: Decodable>(_ type: RX.Type) throws -> RX? {
124-
return try self.withReadingMessageData { jsonData in
125-
try jsonData.withMemoryRebound(to: UInt8.self) { buffer in
126-
try JSON.decode(RX.self, from: buffer)
127-
}
128-
}
129-
}
130-
131-
/// Send a serialized message to the message channel.
132-
private func sendMessageData(_ data: UnsafeBufferPointer<Int8>) throws {
133-
// Write the header (a 64-bit length field in little endian byte order).
134-
var header: UInt64 = UInt64(data.count).littleEndian
135-
let writtenSize = try Swift.withUnsafeBytes(of: &header) { buffer in
136-
try self.write(buffer: UnsafeRawBufferPointer(buffer))
137-
}
138-
guard writtenSize == MemoryLayout.size(ofValue: header) else {
139-
throw PluginServerError(message: "failed to write message header")
140-
}
141-
142-
// Write the body.
143-
guard try self.write(buffer: UnsafeRawBufferPointer(data)) == data.count else {
144-
throw PluginServerError(message: "failed to write message body")
145-
}
146-
}
147-
148-
/// Read a serialized message from the message channel and call the 'body'
149-
/// with the data.
150-
private func withReadingMessageData<R>(_ body: (UnsafeBufferPointer<Int8>) throws -> R) throws -> R? {
151-
// Read the header (a 64-bit length field in little endian byte order).
152-
var header: UInt64 = 0
153-
let readSize = try Swift.withUnsafeMutableBytes(of: &header) { buffer in
154-
try self.read(into: UnsafeMutableRawBufferPointer(buffer))
155-
}
156-
guard readSize == MemoryLayout.size(ofValue: header) else {
157-
if readSize == 0 {
158-
// The host closed the pipe.
159-
return nil
160-
}
161-
// Otherwise, some error happened.
162-
throw PluginServerError(message: "failed to read message header")
163-
}
164-
165-
// Read the body.
166-
let count = Int(UInt64(littleEndian: header))
167-
let data = UnsafeMutableBufferPointer<Int8>.allocate(capacity: count)
168-
defer { data.deallocate() }
169-
guard try self.read(into: UnsafeMutableRawBufferPointer(data)) == count else {
170-
throw PluginServerError(message: "failed to read message body")
171-
}
172-
173-
// Invoke the handler.
174-
return try body(UnsafeBufferPointer(data))
175-
}
176-
177-
/// Write the 'buffer' to the message channel.
178-
/// Returns the number of bytes succeeded to write.
179-
private func write(buffer: UnsafeRawBufferPointer) throws -> Int {
180-
var bytesToWrite = buffer.count
181-
guard bytesToWrite > 0 else {
182-
return 0
183-
}
184-
var ptr = buffer.baseAddress!
185-
186-
while (bytesToWrite > 0) {
187-
let writtenSize = PluginServer_write(handle, ptr, bytesToWrite)
188-
if (writtenSize <= 0) {
189-
// error e.g. broken pipe.
190-
break
191-
}
192-
ptr = ptr.advanced(by: writtenSize)
193-
bytesToWrite -= Int(writtenSize)
194-
}
195-
return buffer.count - bytesToWrite
196-
}
197-
198-
/// Read data from the message channel into the 'buffer' up to 'buffer.count' bytes.
199-
/// Returns the number of bytes succeeded to read.
200-
private func read(into buffer: UnsafeMutableRawBufferPointer) throws -> Int {
201-
var bytesToRead = buffer.count
202-
guard bytesToRead > 0 else {
203-
return 0
204-
}
205-
var ptr = buffer.baseAddress!
206-
207-
while bytesToRead > 0 {
208-
let readSize = PluginServer_read(handle, ptr, bytesToRead)
209-
if (readSize <= 0) {
210-
// 0: EOF (the host closed), -1: Broken pipe (the host crashed?)
211-
break;
212-
}
213-
ptr = ptr.advanced(by: readSize)
214-
bytesToRead -= readSize
215-
}
216-
return buffer.count - bytesToRead
217-
}
218-
}
219-
220101
struct PluginServerError: Error, CustomStringConvertible {
221102
var description: String
222103
init(message: String) {

0 commit comments

Comments
 (0)