summaryrefslogtreecommitdiff
path: root/src/ipc.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-03-02 20:48:01 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-03-02 20:48:01 +0200
commit8d98b4e0d1d83b9a170dd8dccd86451c1c104419 (patch)
tree7edb6a0c92d5c07999ea222037e782b30e19d8c6 /src/ipc.c
parentf992ba117fe420a7231f005e62627380689d57ab (diff)
Windows: Implement IPC with mailslots
Diffstat (limited to 'src/ipc.c')
-rw-r--r--src/ipc.c204
1 files changed, 170 insertions, 34 deletions
diff --git a/src/ipc.c b/src/ipc.c
index 8fdc3bd5..6c528468 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -57,37 +57,31 @@ void init_Ipc(const char *runDir) {
57 signal(SIGUSR1, SIG_IGN); 57 signal(SIGUSR1, SIG_IGN);
58} 58}
59 59
60void deinit_Ipc(void) { 60static void doStopListening_Ipc_(iIpc *d) {
61 iIpc *d = &ipc_;
62 signal(SIGUSR1, SIG_IGN);
63 if (d->isListening) { 61 if (d->isListening) {
64 remove(lockFilePath_(d)); 62 remove(lockFilePath_(d));
63 d->isListening = iFalse;
65 } 64 }
66 deinit_String(&d->dir);
67} 65}
68 66
69static void handleUserSignal_(int sig) { 67iProcessId check_Ipc(void) {
70 iIpc *d = &ipc_; 68 const iIpc *d = &ipc_;
71 iAssert(sig == SIGUSR1); 69 iProcessId pid = 0;
72 iUnused(sig); 70 iFile *f = newCStr_File(lockFilePath_(d));
73 const char *path = inputFilePath_(d, 0);
74 iFile *f = newCStr_File(path);
75 if (open_File(f, readOnly_FileMode)) { 71 if (open_File(f, readOnly_FileMode)) {
76 iString *cmds = new_String(); 72 const iBlock *running = collect_Block(readAll_File(f));
77 initBlock_String(cmds, collect_Block(readAll_File(f))); 73 close_File(f);
78 iRangecc line = iNullRange; 74 pid = atoi(constData_Block(running));
79 while (nextSplit_Rangecc(range_String(cmds), "\n", &line)) { 75 if (!exists_Process(pid)) {
80 postCommand_App(cstr_Rangecc(line)); 76 pid = 0;
77 remove(cstr_String(path_File(f))); /* Stale. */
81 } 78 }
82 delete_String(cmds);
83 } 79 }
84 iRelease(f); 80 iRelease(f);
85 remove(path); 81 return pid;
86} 82}
87 83
88void listen_Ipc(void) { 84static void doListen_Ipc_(iIpc *d) {
89 iIpc *d = &ipc_;
90 signal(SIGUSR1, handleUserSignal_);
91 iFile *f = newCStr_File(lockFilePath_(d)); 85 iFile *f = newCStr_File(lockFilePath_(d));
92 if (open_File(f, writeOnly_FileMode)) { 86 if (open_File(f, writeOnly_FileMode)) {
93 printf_Stream(stream_File(f), "%u", currentId_Process()); 87 printf_Stream(stream_File(f), "%u", currentId_Process());
@@ -96,24 +90,41 @@ void listen_Ipc(void) {
96 iRelease(f); 90 iRelease(f);
97} 91}
98 92
99iProcessId check_Ipc(void) { 93static void postCommands_Ipc_(const iBlock *cmds) {
100 const iIpc *d = &ipc_; 94 iRangecc line = iNullRange;
101 iProcessId pid = 0; 95 while (nextSplit_Rangecc(range_Block(cmds), "\n", &line)) {
102 iFile *f = newCStr_File(lockFilePath_(d)); 96 postCommand_App(cstr_Rangecc(line));
97 }
98}
99
100/*----------------------------------------------------------------------------------------------*/
101#if !defined (iPlatformMsys)
102
103void deinit_Ipc(void) {
104 iIpc *d = &ipc_;
105 signal(SIGUSR1, SIG_IGN);
106 doStopListening_Ipc_(d);
107 deinit_String(&d->dir);
108}
109
110static void handleUserSignal_(int sig) {
111 iIpc *d = &ipc_;
112 iAssert(sig == SIGUSR1);
113 iUnused(sig);
114 const char *path = inputFilePath_(d, 0);
115 iFile *f = newCStr_File(path);
103 if (open_File(f, readOnly_FileMode)) { 116 if (open_File(f, readOnly_FileMode)) {
104 const iBlock *running = collect_Block(readAll_File(f)); 117 postCommands_Ipc_(collect_Block(readAll_File(f)));
105 close_File(f);
106 pid = atoi(constData_Block(running));
107 if (!exists_Process(pid)) {
108 pid = 0;
109 remove(cstr_String(path_File(f))); /* Stale. */
110 }
111 } 118 }
112 iRelease(f); 119 iRelease(f);
113 return pid; 120 remove(path);
114} 121}
115 122
116/*----------------------------------------------------------------------------------------------*/ 123void listen_Ipc(void) {
124 iIpc *d = &ipc_;
125 signal(SIGUSR1, handleUserSignal_);
126 doListen_Ipc_(d);
127}
117 128
118iDeclareType(IpcResponse) 129iDeclareType(IpcResponse)
119 130
@@ -206,5 +217,130 @@ iString *communicate_Ipc(const iString *command) {
206} 217}
207 218
208void signal_Ipc(iProcessId pid) { 219void signal_Ipc(iProcessId pid) {
209 kill(pid, SIGUSR1); 220 if (kill(pid, SIGUSR1)) {
221 printf("kill failed: %s\n", strerror(errno));
222 fflush(stdout);
223 }
224}
225
226#endif
227/*----------------------------------------------------------------------------------------------*/
228#if defined (iPlatformMsys)
229/* Windows doesn't have user signals, so we'll use one of the simpler native
230 Win32 IPC APIs: mailslots. */
231
232#include <the_Foundation/thread.h>
233
234#define WIN32_LEAN_AND_MEAN
235#include <windows.h>
236
237static iThread *listenThread_;
238static HANDLE listenSlot_;
239
240static iThreadResult readSlotThread_Ipc_(iThread *thd) {
241 iIpc *d = &ipc_;
242 DWORD msgSize;
243 while (d->isListening) {
244 BOOL ok = GetMailslotInfo(listenSlot_, NULL, &msgSize, NULL, NULL);
245 if (msgSize == MAILSLOT_NO_MESSAGE) {
246 sleep_Thread(0.333);
247 continue;
248 }
249 if (!ok) break;
250 /* Read the message.*/
251 DWORD readBytes = 0;
252 iBlock *msg = new_Block(msgSize);
253 if (ReadFile(listenSlot_, data_Block(msg), size_Block(msg), &readBytes, NULL)) {
254 postCommands_Ipc_(msg);
255 }
256 delete_Block(msg);
257 }
258 return 0;
259}
260
261static const char *slotName_(int pid) {
262 return format_CStr("\\\\.\\mailslot\\fi.skyjake.Lagrange\\%u", pid);
263}
264
265void deinit_Ipc(void) {
266 iIpc *d = &ipc_;
267 doStopListening_Ipc_(d);
268 CloseHandle(listenSlot_);
269 if (listenThread_) {
270 join_Thread(listenThread_);
271 iRelease(listenThread_);
272 }
273 deinit_String(&d->dir);
274}
275
276void listen_Ipc(void) {
277 iIpc *d = &ipc_;
278 /* Create a mailslot for listening. */
279 listenSlot_ = CreateMailslotA(slotName_(currentId_Process()), 0, 1000, NULL);
280 listenThread_ = new_Thread(readSlotThread_Ipc_);
281 doListen_Ipc_(d);
282 start_Thread(listenThread_);
283}
284
285iBool write_Ipc(iProcessId pid, const iString *input, enum iIpcWrite type) {
286 iUnused(type);
287 HANDLE slot = CreateFile(slotName_(pid),
288 GENERIC_WRITE,
289 FILE_SHARE_READ,
290 NULL,
291 OPEN_EXISTING,
292 FILE_ATTRIBUTE_NORMAL,
293 NULL);
294 if (slot == INVALID_HANDLE_VALUE) {
295 return iFalse;
296 }
297 DWORD writeBytes = 0;
298 iBool ok =
299 WriteFile(
300 slot, constData_Block(utf8_String(input)), size_String(input), &writeBytes, NULL) &&
301 writeBytes == size_String(input);
302 CloseHandle(slot);
303 return ok;
304}
305
306iString *communicate_Ipc(const iString *command) {
307 iProcessId pid = check_Ipc();
308 if (!pid) {
309 return NULL;
310 }
311 /* Open a mailslot for the response. */
312 HANDLE responseSlot = CreateMailslotA(slotName_(currentId_Process()), 0, 1000, NULL);
313 /* Write the commands. */
314 if (!write_Ipc(pid, command, command_IpcWrite)) {
315 CloseHandle(responseSlot);
316 return NULL;
317 }
318 /* Read the response. */
319 iString *output = NULL;
320 DWORD msgSize = 0;
321 iTime startTime;
322 for (initCurrent_Time(&startTime); elapsedSeconds_Time(&startTime) < 2; ) {
323 if (!GetMailslotInfo(responseSlot, NULL, &msgSize, NULL, NULL)) {
324 break;
325 }
326 if (msgSize == MAILSLOT_NO_MESSAGE) {
327 sleep_Thread(0.1);
328 continue;
329 }
330 iBlock *resp = new_Block(msgSize);
331 DWORD bytesRead = 0;
332 ReadFile(responseSlot, data_Block(resp), msgSize, &bytesRead, NULL);
333 output = newBlock_String(resp);
334 delete_Block(resp);
335 break;
336 }
337 CloseHandle(responseSlot);
338 return output;
339}
340
341void signal_Ipc(iProcessId pid) {
342 /* The write to the mailslot will trigger a read. */
343 iUnused(pid);
210} 344}
345
346#endif \ No newline at end of file