1 #include "git-compat-util.h"
4 #include "simple-ipc.h"
7 #include "thread-utils.h"
13 #ifndef SUPPORTS_SIMPLE_IPC
15 * This source file should only be compiled when Simple IPC is supported.
16 * See the top-level Makefile.
18 #error SUPPORTS_SIMPLE_IPC not defined
21 static int initialize_pipe_name(const char *path
, wchar_t *wpath
, size_t alloc
)
24 struct strbuf realpath
= STRBUF_INIT
;
26 if (!strbuf_realpath(&realpath
, path
, 0))
29 off
= swprintf(wpath
, alloc
, L
"\\\\.\\pipe\\");
30 if (xutftowcs(wpath
+ off
, realpath
.buf
, alloc
- off
) < 0)
33 /* Handle drive prefix */
34 if (wpath
[off
] && wpath
[off
+ 1] == L
':') {
35 wpath
[off
+ 1] = L
'_';
39 for (; wpath
[off
]; off
++)
40 if (wpath
[off
] == L
'/')
43 strbuf_release(&realpath
);
47 static enum ipc_active_state
get_active_state(wchar_t *pipe_path
)
49 if (WaitNamedPipeW(pipe_path
, NMPWAIT_USE_DEFAULT_WAIT
))
50 return IPC_STATE__LISTENING
;
52 if (GetLastError() == ERROR_SEM_TIMEOUT
)
53 return IPC_STATE__NOT_LISTENING
;
55 if (GetLastError() == ERROR_FILE_NOT_FOUND
)
56 return IPC_STATE__PATH_NOT_FOUND
;
58 trace2_data_intmax("ipc-debug", NULL
, "getstate/waitpipe/gle",
59 (intmax_t)GetLastError());
61 return IPC_STATE__OTHER_ERROR
;
64 enum ipc_active_state
ipc_get_active_state(const char *path
)
66 wchar_t pipe_path
[MAX_PATH
];
68 if (initialize_pipe_name(path
, pipe_path
, ARRAY_SIZE(pipe_path
)) < 0)
69 return IPC_STATE__INVALID_PATH
;
71 return get_active_state(pipe_path
);
74 #define WAIT_STEP_MS (50)
76 static enum ipc_active_state
connect_to_server(
79 const struct ipc_client_connect_options
*options
,
82 DWORD t_start_ms
, t_waited_ms
;
84 HANDLE hPipe
= INVALID_HANDLE_VALUE
;
85 DWORD mode
= PIPE_READMODE_BYTE
;
91 hPipe
= CreateFileW(wpath
, GENERIC_READ
| GENERIC_WRITE
,
92 0, NULL
, OPEN_EXISTING
, 0, NULL
);
93 if (hPipe
!= INVALID_HANDLE_VALUE
)
99 case ERROR_FILE_NOT_FOUND
:
100 if (!options
->wait_if_not_found
)
101 return IPC_STATE__PATH_NOT_FOUND
;
103 return IPC_STATE__PATH_NOT_FOUND
;
105 step_ms
= (timeout_ms
< WAIT_STEP_MS
) ?
106 timeout_ms
: WAIT_STEP_MS
;
107 sleep_millisec(step_ms
);
109 timeout_ms
-= step_ms
;
110 break; /* try again */
112 case ERROR_PIPE_BUSY
:
113 if (!options
->wait_if_busy
)
114 return IPC_STATE__NOT_LISTENING
;
116 return IPC_STATE__NOT_LISTENING
;
118 t_start_ms
= (DWORD
)(getnanotime() / 1000000);
120 if (!WaitNamedPipeW(wpath
, timeout_ms
)) {
121 DWORD gleWait
= GetLastError();
123 if (gleWait
== ERROR_SEM_TIMEOUT
)
124 return IPC_STATE__NOT_LISTENING
;
126 trace2_data_intmax("ipc-debug", NULL
,
127 "connect/waitpipe/gle",
130 return IPC_STATE__OTHER_ERROR
;
134 * A pipe server instance became available.
135 * Race other client processes to connect to
138 * But first decrement our overall timeout so
139 * that we don't starve if we keep losing the
140 * race. But also guard against special
141 * NPMWAIT_ values (0 and -1).
143 t_waited_ms
= (DWORD
)(getnanotime() / 1000000) - t_start_ms
;
144 if (t_waited_ms
< timeout_ms
)
145 timeout_ms
-= t_waited_ms
;
148 break; /* try again */
151 trace2_data_intmax("ipc-debug", NULL
,
152 "connect/createfile/gle",
155 return IPC_STATE__OTHER_ERROR
;
159 if (!SetNamedPipeHandleState(hPipe
, &mode
, NULL
, NULL
)) {
160 gle
= GetLastError();
161 trace2_data_intmax("ipc-debug", NULL
,
162 "connect/setpipestate/gle",
166 return IPC_STATE__OTHER_ERROR
;
169 *pfd
= _open_osfhandle((intptr_t)hPipe
, O_RDWR
|O_BINARY
);
171 gle
= GetLastError();
172 trace2_data_intmax("ipc-debug", NULL
,
173 "connect/openosfhandle/gle",
177 return IPC_STATE__OTHER_ERROR
;
180 /* fd now owns hPipe */
182 return IPC_STATE__LISTENING
;
186 * The default connection timeout for Windows clients.
188 * This is not currently part of the ipc_ API (nor the config settings)
189 * because of differences between Windows and other platforms.
191 * This value was chosen at random.
193 #define WINDOWS_CONNECTION_TIMEOUT_MS (30000)
195 enum ipc_active_state
ipc_client_try_connect(
197 const struct ipc_client_connect_options
*options
,
198 struct ipc_client_connection
**p_connection
)
200 wchar_t wpath
[MAX_PATH
];
201 enum ipc_active_state state
= IPC_STATE__OTHER_ERROR
;
204 *p_connection
= NULL
;
206 trace2_region_enter("ipc-client", "try-connect", NULL
);
207 trace2_data_string("ipc-client", NULL
, "try-connect/path", path
);
209 if (initialize_pipe_name(path
, wpath
, ARRAY_SIZE(wpath
)) < 0)
210 state
= IPC_STATE__INVALID_PATH
;
212 state
= connect_to_server(wpath
, WINDOWS_CONNECTION_TIMEOUT_MS
,
215 trace2_data_intmax("ipc-client", NULL
, "try-connect/state",
217 trace2_region_leave("ipc-client", "try-connect", NULL
);
219 if (state
== IPC_STATE__LISTENING
) {
220 (*p_connection
) = xcalloc(1, sizeof(struct ipc_client_connection
));
221 (*p_connection
)->fd
= fd
;
227 void ipc_client_close_connection(struct ipc_client_connection
*connection
)
232 if (connection
->fd
!= -1)
233 close(connection
->fd
);
238 int ipc_client_send_command_to_connection(
239 struct ipc_client_connection
*connection
,
240 const char *message
, size_t message_len
,
241 struct strbuf
*answer
)
245 strbuf_setlen(answer
, 0);
247 trace2_region_enter("ipc-client", "send-command", NULL
);
249 if (write_packetized_from_buf_no_flush(message
, message_len
,
250 connection
->fd
) < 0 ||
251 packet_flush_gently(connection
->fd
) < 0) {
252 ret
= error(_("could not send IPC command"));
256 FlushFileBuffers((HANDLE
)_get_osfhandle(connection
->fd
));
258 if (read_packetized_to_strbuf(
259 connection
->fd
, answer
,
260 PACKET_READ_GENTLE_ON_EOF
| PACKET_READ_GENTLE_ON_READ_ERROR
) < 0) {
261 ret
= error(_("could not read IPC response"));
266 trace2_region_leave("ipc-client", "send-command", NULL
);
270 int ipc_client_send_command(const char *path
,
271 const struct ipc_client_connect_options
*options
,
272 const char *message
, size_t message_len
,
273 struct strbuf
*response
)
276 enum ipc_active_state state
;
277 struct ipc_client_connection
*connection
= NULL
;
279 state
= ipc_client_try_connect(path
, options
, &connection
);
281 if (state
!= IPC_STATE__LISTENING
)
284 ret
= ipc_client_send_command_to_connection(connection
,
285 message
, message_len
,
288 ipc_client_close_connection(connection
);
294 * Duplicate the given pipe handle and wrap it in a file descriptor so
295 * that we can use pkt-line on it.
297 static int dup_fd_from_pipe(const HANDLE pipe
)
299 HANDLE process
= GetCurrentProcess();
303 if (!DuplicateHandle(process
, pipe
, process
, &handle
, 0, FALSE
,
304 DUPLICATE_SAME_ACCESS
)) {
305 errno
= err_win_to_posix(GetLastError());
309 fd
= _open_osfhandle((intptr_t)handle
, O_RDWR
|O_BINARY
);
311 errno
= err_win_to_posix(GetLastError());
317 * `handle` is now owned by `fd` and will be automatically closed
318 * when the descriptor is closed.
325 * Magic numbers used to annotate callback instance data.
326 * These are used to help guard against accidentally passing the
327 * wrong instance data across multiple levels of callbacks (which
328 * is easy to do if there are `void*` arguments).
331 MAGIC_SERVER_REPLY_DATA
,
332 MAGIC_SERVER_THREAD_DATA
,
336 struct ipc_server_reply_data
{
339 struct ipc_server_thread_data
*server_thread_data
;
342 struct ipc_server_thread_data
{
344 struct ipc_server_thread_data
*next_thread
;
345 struct ipc_server_data
*server_data
;
346 pthread_t pthread_id
;
351 * On Windows, the conceptual "ipc-server" is implemented as a pool of
352 * n idential/peer "server-thread" threads. That is, there is no
353 * hierarchy of threads; and therefore no controller thread managing
354 * the pool. Each thread has an independent handle to the named pipe,
355 * receives incoming connections, processes the client, and re-uses
356 * the pipe for the next client connection.
358 * Therefore, the "ipc-server" only needs to maintain a list of the
359 * spawned threads for eventual "join" purposes.
361 * A single "stop-event" is visible to all of the server threads to
362 * tell them to shutdown (when idle).
364 struct ipc_server_data
{
366 ipc_server_application_cb
*application_cb
;
367 void *application_data
;
368 struct strbuf buf_path
;
369 wchar_t wpath
[MAX_PATH
];
371 HANDLE hEventStopRequested
;
372 struct ipc_server_thread_data
*thread_list
;
376 enum connect_result
{
384 static enum connect_result
queue_overlapped_connect(
385 struct ipc_server_thread_data
*server_thread_data
,
388 if (ConnectNamedPipe(server_thread_data
->hPipe
, lpo
))
391 switch (GetLastError()) {
392 case ERROR_IO_PENDING
:
393 return CR_CONNECT_PENDING
;
395 case ERROR_PIPE_CONNECTED
:
396 SetEvent(lpo
->hEvent
);
404 error(_("ConnectNamedPipe failed for '%s' (%lu)"),
405 server_thread_data
->server_data
->buf_path
.buf
,
407 return CR_CONNECT_ERROR
;
411 * Use Windows Overlapped IO to wait for a connection or for our event
414 static enum connect_result
wait_for_connection(
415 struct ipc_server_thread_data
*server_thread_data
,
418 enum connect_result r
;
419 HANDLE waitHandles
[2];
422 r
= queue_overlapped_connect(server_thread_data
, lpo
);
423 if (r
!= CR_CONNECT_PENDING
)
426 waitHandles
[0] = server_thread_data
->server_data
->hEventStopRequested
;
427 waitHandles
[1] = lpo
->hEvent
;
429 dwWaitResult
= WaitForMultipleObjects(2, waitHandles
, FALSE
, INFINITE
);
430 switch (dwWaitResult
) {
431 case WAIT_OBJECT_0
+ 0:
434 case WAIT_OBJECT_0
+ 1:
435 ResetEvent(lpo
->hEvent
);
439 return CR_WAIT_ERROR
;
444 * Forward declare our reply callback function so that any compiler
445 * errors are reported when we actually define the function (in addition
446 * to any errors reported when we try to pass this callback function as
447 * a parameter in a function call). The former are easier to understand.
449 static ipc_server_reply_cb do_io_reply_callback
;
452 * Relay application's response message to the client process.
453 * (We do not flush at this point because we allow the caller
454 * to chunk data to the client thru us.)
456 static int do_io_reply_callback(struct ipc_server_reply_data
*reply_data
,
457 const char *response
, size_t response_len
)
459 if (reply_data
->magic
!= MAGIC_SERVER_REPLY_DATA
)
460 BUG("reply_cb called with wrong instance data");
462 return write_packetized_from_buf_no_flush(response
, response_len
,
467 * Receive the request/command from the client and pass it to the
468 * registered request-callback. The request-callback will compose
469 * a response and call our reply-callback to send it to the client.
471 * Simple-IPC only contains one round trip, so we flush and close
472 * here after the response.
474 static int do_io(struct ipc_server_thread_data
*server_thread_data
)
476 struct strbuf buf
= STRBUF_INIT
;
477 struct ipc_server_reply_data reply_data
;
480 reply_data
.magic
= MAGIC_SERVER_REPLY_DATA
;
481 reply_data
.server_thread_data
= server_thread_data
;
483 reply_data
.fd
= dup_fd_from_pipe(server_thread_data
->hPipe
);
484 if (reply_data
.fd
< 0)
485 return error(_("could not create fd from pipe for '%s'"),
486 server_thread_data
->server_data
->buf_path
.buf
);
488 ret
= read_packetized_to_strbuf(
490 PACKET_READ_GENTLE_ON_EOF
| PACKET_READ_GENTLE_ON_READ_ERROR
);
492 ret
= server_thread_data
->server_data
->application_cb(
493 server_thread_data
->server_data
->application_data
,
494 buf
.buf
, buf
.len
, do_io_reply_callback
, &reply_data
);
496 packet_flush_gently(reply_data
.fd
);
498 FlushFileBuffers((HANDLE
)_get_osfhandle((reply_data
.fd
)));
502 * The client probably disconnected/shutdown before it
503 * could send a well-formed message. Ignore it.
507 strbuf_release(&buf
);
508 close(reply_data
.fd
);
514 * Handle IPC request and response with this connected client. And reset
515 * the pipe to prepare for the next client.
517 static int use_connection(struct ipc_server_thread_data
*server_thread_data
)
521 ret
= do_io(server_thread_data
);
523 FlushFileBuffers(server_thread_data
->hPipe
);
524 DisconnectNamedPipe(server_thread_data
->hPipe
);
530 * Thread proc for an IPC server worker thread. It handles a series of
531 * connections from clients. It cleans and reuses the hPipe between each
534 static void *server_thread_proc(void *_server_thread_data
)
536 struct ipc_server_thread_data
*server_thread_data
= _server_thread_data
;
537 HANDLE hEventConnected
= INVALID_HANDLE_VALUE
;
539 enum connect_result cr
;
542 assert(server_thread_data
->hPipe
!= INVALID_HANDLE_VALUE
);
544 trace2_thread_start("ipc-server");
545 trace2_data_string("ipc-server", NULL
, "pipe",
546 server_thread_data
->server_data
->buf_path
.buf
);
548 hEventConnected
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
550 memset(&oConnect
, 0, sizeof(oConnect
));
551 oConnect
.hEvent
= hEventConnected
;
554 cr
= wait_for_connection(server_thread_data
, &oConnect
);
561 ret
= use_connection(server_thread_data
);
562 if (ret
== SIMPLE_IPC_QUIT
) {
563 ipc_server_stop_async(
564 server_thread_data
->server_data
);
569 * Ignore (transient) IO errors with this
570 * client and reset for the next client.
575 case CR_CONNECT_PENDING
:
576 /* By construction, this should not happen. */
577 BUG("ipc-server[%s]: unexpeced CR_CONNECT_PENDING",
578 server_thread_data
->server_data
->buf_path
.buf
);
580 case CR_CONNECT_ERROR
:
583 * Ignore these theoretical errors.
585 DisconnectNamedPipe(server_thread_data
->hPipe
);
589 BUG("unandled case after wait_for_connection");
594 CloseHandle(server_thread_data
->hPipe
);
595 CloseHandle(hEventConnected
);
597 trace2_thread_exit();
602 * We need to build a Windows "SECURITY_ATTRIBUTES" object and use it
603 * to apply an ACL when we create the initial instance of the Named
604 * Pipe. The construction is somewhat involved and consists of
605 * several sequential steps and intermediate objects.
607 * We use this structure to hold these intermediate pointers so that
608 * we can free them as a group. (It is unclear from the docs whether
609 * some of these intermediate pointers can be freed before we are
610 * finished using the "lpSA" member.)
616 PSECURITY_DESCRIPTOR pSD
;
617 LPSECURITY_ATTRIBUTES lpSA
;
620 static void init_sa(struct my_sa_data
*d
)
622 memset(d
, 0, sizeof(*d
));
625 static void release_sa(struct my_sa_data
*d
)
628 FreeSid(d
->pEveryoneSID
);
636 memset(d
, 0, sizeof(*d
));
640 * Create SECURITY_ATTRIBUTES to apply to the initial named pipe. The
641 * creator of the first server instance gets to set the ACLs on it.
643 * We allow the well-known group `EVERYONE` to have read+write access
644 * to the named pipe so that clients can send queries to the daemon
645 * and receive the response.
647 * Normally, this is not necessary since the daemon is usually
648 * automatically started by a foreground command like `git status`,
649 * but in those cases where an elevated Git command started the daemon
650 * (such that the daemon itself runs with elevation), we need to add
651 * the ACL so that non-elevated commands can write to it.
653 * The following document was helpful:
654 * https://docs.microsoft.com/en-us/windows/win32/secauthz/creating-a-security-descriptor-for-a-new-object-in-c--
656 * Returns d->lpSA set to a SA or NULL.
658 static LPSECURITY_ATTRIBUTES
get_sa(struct my_sa_data
*d
)
660 SID_IDENTIFIER_AUTHORITY sid_auth_world
= SECURITY_WORLD_SID_AUTHORITY
;
662 EXPLICIT_ACCESS ea
[NR_EA
];
665 if (!AllocateAndInitializeSid(&sid_auth_world
, 1,
666 SECURITY_WORLD_RID
, 0,0,0,0,0,0,0,
668 DWORD gle
= GetLastError();
669 trace2_data_intmax("ipc-debug", NULL
, "alloc-world-sid/gle",
674 memset(ea
, 0, NR_EA
* sizeof(EXPLICIT_ACCESS
));
676 ea
[0].grfAccessPermissions
= GENERIC_READ
| GENERIC_WRITE
;
677 ea
[0].grfAccessMode
= SET_ACCESS
;
678 ea
[0].grfInheritance
= NO_INHERITANCE
;
679 ea
[0].Trustee
.MultipleTrusteeOperation
= NO_MULTIPLE_TRUSTEE
;
680 ea
[0].Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
681 ea
[0].Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
682 ea
[0].Trustee
.ptstrName
= (LPTSTR
)d
->pEveryoneSID
;
684 dwResult
= SetEntriesInAcl(NR_EA
, ea
, NULL
, &d
->pACL
);
685 if (dwResult
!= ERROR_SUCCESS
) {
686 DWORD gle
= GetLastError();
687 trace2_data_intmax("ipc-debug", NULL
, "set-acl-entry/gle",
689 trace2_data_intmax("ipc-debug", NULL
, "set-acl-entry/dw",
694 d
->pSD
= (PSECURITY_DESCRIPTOR
)LocalAlloc(
695 LPTR
, SECURITY_DESCRIPTOR_MIN_LENGTH
);
696 if (!InitializeSecurityDescriptor(d
->pSD
, SECURITY_DESCRIPTOR_REVISION
)) {
697 DWORD gle
= GetLastError();
698 trace2_data_intmax("ipc-debug", NULL
, "init-sd/gle", (intmax_t)gle
);
702 if (!SetSecurityDescriptorDacl(d
->pSD
, TRUE
, d
->pACL
, FALSE
)) {
703 DWORD gle
= GetLastError();
704 trace2_data_intmax("ipc-debug", NULL
, "set-sd-dacl/gle", (intmax_t)gle
);
708 d
->lpSA
= (LPSECURITY_ATTRIBUTES
)LocalAlloc(LPTR
, sizeof(SECURITY_ATTRIBUTES
));
709 d
->lpSA
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
710 d
->lpSA
->lpSecurityDescriptor
= d
->pSD
;
711 d
->lpSA
->bInheritHandle
= FALSE
;
720 static HANDLE
create_new_pipe(wchar_t *wpath
, int is_first
)
723 DWORD dwOpenMode
, dwPipeMode
;
724 struct my_sa_data my_sa_data
;
726 init_sa(&my_sa_data
);
728 dwOpenMode
= PIPE_ACCESS_INBOUND
| PIPE_ACCESS_OUTBOUND
|
729 FILE_FLAG_OVERLAPPED
;
731 dwPipeMode
= PIPE_TYPE_MESSAGE
| PIPE_READMODE_BYTE
| PIPE_WAIT
|
732 PIPE_REJECT_REMOTE_CLIENTS
;
735 dwOpenMode
|= FILE_FLAG_FIRST_PIPE_INSTANCE
;
738 * On Windows, the first server pipe instance gets to
739 * set the ACL / Security Attributes on the named
740 * pipe; subsequent instances inherit and cannot
746 hPipe
= CreateNamedPipeW(wpath
, dwOpenMode
, dwPipeMode
,
747 PIPE_UNLIMITED_INSTANCES
, 1024, 1024, 0,
750 release_sa(&my_sa_data
);
755 int ipc_server_run_async(struct ipc_server_data
**returned_server_data
,
756 const char *path
, const struct ipc_server_opts
*opts
,
757 ipc_server_application_cb
*application_cb
,
758 void *application_data
)
760 struct ipc_server_data
*server_data
;
761 wchar_t wpath
[MAX_PATH
];
762 HANDLE hPipeFirst
= INVALID_HANDLE_VALUE
;
765 int nr_threads
= opts
->nr_threads
;
767 *returned_server_data
= NULL
;
769 ret
= initialize_pipe_name(path
, wpath
, ARRAY_SIZE(wpath
));
775 hPipeFirst
= create_new_pipe(wpath
, 1);
776 if (hPipeFirst
== INVALID_HANDLE_VALUE
) {
781 server_data
= xcalloc(1, sizeof(*server_data
));
782 server_data
->magic
= MAGIC_SERVER_DATA
;
783 server_data
->application_cb
= application_cb
;
784 server_data
->application_data
= application_data
;
785 server_data
->hEventStopRequested
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
786 strbuf_init(&server_data
->buf_path
, 0);
787 strbuf_addstr(&server_data
->buf_path
, path
);
788 wcscpy(server_data
->wpath
, wpath
);
793 for (k
= 0; k
< nr_threads
; k
++) {
794 struct ipc_server_thread_data
*std
;
796 std
= xcalloc(1, sizeof(*std
));
797 std
->magic
= MAGIC_SERVER_THREAD_DATA
;
798 std
->server_data
= server_data
;
799 std
->hPipe
= INVALID_HANDLE_VALUE
;
801 std
->hPipe
= (k
== 0)
803 : create_new_pipe(server_data
->wpath
, 0);
805 if (std
->hPipe
== INVALID_HANDLE_VALUE
) {
807 * If we've reached a pipe instance limit for
808 * this path, just use fewer threads.
814 if (pthread_create(&std
->pthread_id
, NULL
,
815 server_thread_proc
, std
)) {
817 * Likewise, if we're out of threads, just use
818 * fewer threads than requested.
820 * However, we just give up if we can't even get
821 * one thread. This should not happen.
824 die(_("could not start thread[0] for '%s'"),
827 CloseHandle(std
->hPipe
);
832 std
->next_thread
= server_data
->thread_list
;
833 server_data
->thread_list
= std
;
836 *returned_server_data
= server_data
;
840 int ipc_server_stop_async(struct ipc_server_data
*server_data
)
846 * Gently tell all of the ipc_server threads to shutdown.
847 * This will be seen the next time they are idle (and waiting
850 * We DO NOT attempt to force them to drop an active connection.
852 SetEvent(server_data
->hEventStopRequested
);
856 int ipc_server_await(struct ipc_server_data
*server_data
)
863 dwWaitResult
= WaitForSingleObject(server_data
->hEventStopRequested
, INFINITE
);
864 if (dwWaitResult
!= WAIT_OBJECT_0
)
865 return error(_("wait for hEvent failed for '%s'"),
866 server_data
->buf_path
.buf
);
868 while (server_data
->thread_list
) {
869 struct ipc_server_thread_data
*std
= server_data
->thread_list
;
871 pthread_join(std
->pthread_id
, NULL
);
873 server_data
->thread_list
= std
->next_thread
;
877 server_data
->is_stopped
= 1;
882 void ipc_server_free(struct ipc_server_data
*server_data
)
887 if (!server_data
->is_stopped
)
888 BUG("cannot free ipc-server while running for '%s'",
889 server_data
->buf_path
.buf
);
891 strbuf_release(&server_data
->buf_path
);
893 if (server_data
->hEventStopRequested
!= INVALID_HANDLE_VALUE
)
894 CloseHandle(server_data
->hEventStopRequested
);
896 while (server_data
->thread_list
) {
897 struct ipc_server_thread_data
*std
= server_data
->thread_list
;
899 server_data
->thread_list
= std
->next_thread
;