git
904 строки · 22.4 Кб
1#include "git-compat-util.h"2#include "abspath.h"3#include "gettext.h"4#include "simple-ipc.h"5#include "strbuf.h"6#include "pkt-line.h"7#include "thread-utils.h"8#include "trace.h"9#include "trace2.h"10#include "accctrl.h"11#include "aclapi.h"12
13#ifndef SUPPORTS_SIMPLE_IPC14/*
15* This source file should only be compiled when Simple IPC is supported.
16* See the top-level Makefile.
17*/
18#error SUPPORTS_SIMPLE_IPC not defined19#endif20
21static int initialize_pipe_name(const char *path, wchar_t *wpath, size_t alloc)22{
23int off = 0;24struct strbuf realpath = STRBUF_INIT;25
26if (!strbuf_realpath(&realpath, path, 0))27return -1;28
29off = swprintf(wpath, alloc, L"\\\\.\\pipe\\");30if (xutftowcs(wpath + off, realpath.buf, alloc - off) < 0)31return -1;32
33/* Handle drive prefix */34if (wpath[off] && wpath[off + 1] == L':') {35wpath[off + 1] = L'_';36off += 2;37}38
39for (; wpath[off]; off++)40if (wpath[off] == L'/')41wpath[off] = L'\\';42
43strbuf_release(&realpath);44return 0;45}
46
47static enum ipc_active_state get_active_state(wchar_t *pipe_path)48{
49if (WaitNamedPipeW(pipe_path, NMPWAIT_USE_DEFAULT_WAIT))50return IPC_STATE__LISTENING;51
52if (GetLastError() == ERROR_SEM_TIMEOUT)53return IPC_STATE__NOT_LISTENING;54
55if (GetLastError() == ERROR_FILE_NOT_FOUND)56return IPC_STATE__PATH_NOT_FOUND;57
58trace2_data_intmax("ipc-debug", NULL, "getstate/waitpipe/gle",59(intmax_t)GetLastError());60
61return IPC_STATE__OTHER_ERROR;62}
63
64enum ipc_active_state ipc_get_active_state(const char *path)65{
66wchar_t pipe_path[MAX_PATH];67
68if (initialize_pipe_name(path, pipe_path, ARRAY_SIZE(pipe_path)) < 0)69return IPC_STATE__INVALID_PATH;70
71return get_active_state(pipe_path);72}
73
74#define WAIT_STEP_MS (50)75
76static enum ipc_active_state connect_to_server(77const wchar_t *wpath,78DWORD timeout_ms,79const struct ipc_client_connect_options *options,80int *pfd)81{
82DWORD t_start_ms, t_waited_ms;83DWORD step_ms;84HANDLE hPipe = INVALID_HANDLE_VALUE;85DWORD mode = PIPE_READMODE_BYTE;86DWORD gle;87
88*pfd = -1;89
90for (;;) {91hPipe = CreateFileW(wpath, GENERIC_READ | GENERIC_WRITE,920, NULL, OPEN_EXISTING, 0, NULL);93if (hPipe != INVALID_HANDLE_VALUE)94break;95
96gle = GetLastError();97
98switch (gle) {99case ERROR_FILE_NOT_FOUND:100if (!options->wait_if_not_found)101return IPC_STATE__PATH_NOT_FOUND;102if (!timeout_ms)103return IPC_STATE__PATH_NOT_FOUND;104
105step_ms = (timeout_ms < WAIT_STEP_MS) ?106timeout_ms : WAIT_STEP_MS;107sleep_millisec(step_ms);108
109timeout_ms -= step_ms;110break; /* try again */111
112case ERROR_PIPE_BUSY:113if (!options->wait_if_busy)114return IPC_STATE__NOT_LISTENING;115if (!timeout_ms)116return IPC_STATE__NOT_LISTENING;117
118t_start_ms = (DWORD)(getnanotime() / 1000000);119
120if (!WaitNamedPipeW(wpath, timeout_ms)) {121DWORD gleWait = GetLastError();122
123if (gleWait == ERROR_SEM_TIMEOUT)124return IPC_STATE__NOT_LISTENING;125
126trace2_data_intmax("ipc-debug", NULL,127"connect/waitpipe/gle",128(intmax_t)gleWait);129
130return IPC_STATE__OTHER_ERROR;131}132
133/*134* A pipe server instance became available.
135* Race other client processes to connect to
136* it.
137*
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).
142*/
143t_waited_ms = (DWORD)(getnanotime() / 1000000) - t_start_ms;144if (t_waited_ms < timeout_ms)145timeout_ms -= t_waited_ms;146else147timeout_ms = 1;148break; /* try again */149
150default:151trace2_data_intmax("ipc-debug", NULL,152"connect/createfile/gle",153(intmax_t)gle);154
155return IPC_STATE__OTHER_ERROR;156}157}158
159if (!SetNamedPipeHandleState(hPipe, &mode, NULL, NULL)) {160gle = GetLastError();161trace2_data_intmax("ipc-debug", NULL,162"connect/setpipestate/gle",163(intmax_t)gle);164
165CloseHandle(hPipe);166return IPC_STATE__OTHER_ERROR;167}168
169*pfd = _open_osfhandle((intptr_t)hPipe, O_RDWR|O_BINARY);170if (*pfd < 0) {171gle = GetLastError();172trace2_data_intmax("ipc-debug", NULL,173"connect/openosfhandle/gle",174(intmax_t)gle);175
176CloseHandle(hPipe);177return IPC_STATE__OTHER_ERROR;178}179
180/* fd now owns hPipe */181
182return IPC_STATE__LISTENING;183}
184
185/*
186* The default connection timeout for Windows clients.
187*
188* This is not currently part of the ipc_ API (nor the config settings)
189* because of differences between Windows and other platforms.
190*
191* This value was chosen at random.
192*/
193#define WINDOWS_CONNECTION_TIMEOUT_MS (30000)194
195enum ipc_active_state ipc_client_try_connect(196const char *path,197const struct ipc_client_connect_options *options,198struct ipc_client_connection **p_connection)199{
200wchar_t wpath[MAX_PATH];201enum ipc_active_state state = IPC_STATE__OTHER_ERROR;202int fd = -1;203
204*p_connection = NULL;205
206trace2_region_enter("ipc-client", "try-connect", NULL);207trace2_data_string("ipc-client", NULL, "try-connect/path", path);208
209if (initialize_pipe_name(path, wpath, ARRAY_SIZE(wpath)) < 0)210state = IPC_STATE__INVALID_PATH;211else212state = connect_to_server(wpath, WINDOWS_CONNECTION_TIMEOUT_MS,213options, &fd);214
215trace2_data_intmax("ipc-client", NULL, "try-connect/state",216(intmax_t)state);217trace2_region_leave("ipc-client", "try-connect", NULL);218
219if (state == IPC_STATE__LISTENING) {220(*p_connection) = xcalloc(1, sizeof(struct ipc_client_connection));221(*p_connection)->fd = fd;222}223
224return state;225}
226
227void ipc_client_close_connection(struct ipc_client_connection *connection)228{
229if (!connection)230return;231
232if (connection->fd != -1)233close(connection->fd);234
235free(connection);236}
237
238int ipc_client_send_command_to_connection(239struct ipc_client_connection *connection,240const char *message, size_t message_len,241struct strbuf *answer)242{
243int ret = 0;244
245strbuf_setlen(answer, 0);246
247trace2_region_enter("ipc-client", "send-command", NULL);248
249if (write_packetized_from_buf_no_flush(message, message_len,250connection->fd) < 0 ||251packet_flush_gently(connection->fd) < 0) {252ret = error(_("could not send IPC command"));253goto done;254}255
256FlushFileBuffers((HANDLE)_get_osfhandle(connection->fd));257
258if (read_packetized_to_strbuf(259connection->fd, answer,260PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR) < 0) {261ret = error(_("could not read IPC response"));262goto done;263}264
265done:266trace2_region_leave("ipc-client", "send-command", NULL);267return ret;268}
269
270int ipc_client_send_command(const char *path,271const struct ipc_client_connect_options *options,272const char *message, size_t message_len,273struct strbuf *response)274{
275int ret = -1;276enum ipc_active_state state;277struct ipc_client_connection *connection = NULL;278
279state = ipc_client_try_connect(path, options, &connection);280
281if (state != IPC_STATE__LISTENING)282return ret;283
284ret = ipc_client_send_command_to_connection(connection,285message, message_len,286response);287
288ipc_client_close_connection(connection);289
290return ret;291}
292
293/*
294* Duplicate the given pipe handle and wrap it in a file descriptor so
295* that we can use pkt-line on it.
296*/
297static int dup_fd_from_pipe(const HANDLE pipe)298{
299HANDLE process = GetCurrentProcess();300HANDLE handle;301int fd;302
303if (!DuplicateHandle(process, pipe, process, &handle, 0, FALSE,304DUPLICATE_SAME_ACCESS)) {305errno = err_win_to_posix(GetLastError());306return -1;307}308
309fd = _open_osfhandle((intptr_t)handle, O_RDWR|O_BINARY);310if (fd < 0) {311errno = err_win_to_posix(GetLastError());312CloseHandle(handle);313return -1;314}315
316/*317* `handle` is now owned by `fd` and will be automatically closed
318* when the descriptor is closed.
319*/
320
321return fd;322}
323
324/*
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).
329*/
330enum magic {331MAGIC_SERVER_REPLY_DATA,332MAGIC_SERVER_THREAD_DATA,333MAGIC_SERVER_DATA,334};335
336struct ipc_server_reply_data {337enum magic magic;338int fd;339struct ipc_server_thread_data *server_thread_data;340};341
342struct ipc_server_thread_data {343enum magic magic;344struct ipc_server_thread_data *next_thread;345struct ipc_server_data *server_data;346pthread_t pthread_id;347HANDLE hPipe;348};349
350/*
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.
357*
358* Therefore, the "ipc-server" only needs to maintain a list of the
359* spawned threads for eventual "join" purposes.
360*
361* A single "stop-event" is visible to all of the server threads to
362* tell them to shutdown (when idle).
363*/
364struct ipc_server_data {365enum magic magic;366ipc_server_application_cb *application_cb;367void *application_data;368struct strbuf buf_path;369wchar_t wpath[MAX_PATH];370
371HANDLE hEventStopRequested;372struct ipc_server_thread_data *thread_list;373int is_stopped;374};375
376enum connect_result {377CR_CONNECTED = 0,378CR_CONNECT_PENDING,379CR_CONNECT_ERROR,380CR_WAIT_ERROR,381CR_SHUTDOWN,382};383
384static enum connect_result queue_overlapped_connect(385struct ipc_server_thread_data *server_thread_data,386OVERLAPPED *lpo)387{
388if (ConnectNamedPipe(server_thread_data->hPipe, lpo))389goto failed;390
391switch (GetLastError()) {392case ERROR_IO_PENDING:393return CR_CONNECT_PENDING;394
395case ERROR_PIPE_CONNECTED:396SetEvent(lpo->hEvent);397return CR_CONNECTED;398
399default:400break;401}402
403failed:404error(_("ConnectNamedPipe failed for '%s' (%lu)"),405server_thread_data->server_data->buf_path.buf,406GetLastError());407return CR_CONNECT_ERROR;408}
409
410/*
411* Use Windows Overlapped IO to wait for a connection or for our event
412* to be signalled.
413*/
414static enum connect_result wait_for_connection(415struct ipc_server_thread_data *server_thread_data,416OVERLAPPED *lpo)417{
418enum connect_result r;419HANDLE waitHandles[2];420DWORD dwWaitResult;421
422r = queue_overlapped_connect(server_thread_data, lpo);423if (r != CR_CONNECT_PENDING)424return r;425
426waitHandles[0] = server_thread_data->server_data->hEventStopRequested;427waitHandles[1] = lpo->hEvent;428
429dwWaitResult = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);430switch (dwWaitResult) {431case WAIT_OBJECT_0 + 0:432return CR_SHUTDOWN;433
434case WAIT_OBJECT_0 + 1:435ResetEvent(lpo->hEvent);436return CR_CONNECTED;437
438default:439return CR_WAIT_ERROR;440}441}
442
443/*
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.
448*/
449static ipc_server_reply_cb do_io_reply_callback;450
451/*
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.)
455*/
456static int do_io_reply_callback(struct ipc_server_reply_data *reply_data,457const char *response, size_t response_len)458{
459if (reply_data->magic != MAGIC_SERVER_REPLY_DATA)460BUG("reply_cb called with wrong instance data");461
462return write_packetized_from_buf_no_flush(response, response_len,463reply_data->fd);464}
465
466/*
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.
470*
471* Simple-IPC only contains one round trip, so we flush and close
472* here after the response.
473*/
474static int do_io(struct ipc_server_thread_data *server_thread_data)475{
476struct strbuf buf = STRBUF_INIT;477struct ipc_server_reply_data reply_data;478int ret = 0;479
480reply_data.magic = MAGIC_SERVER_REPLY_DATA;481reply_data.server_thread_data = server_thread_data;482
483reply_data.fd = dup_fd_from_pipe(server_thread_data->hPipe);484if (reply_data.fd < 0)485return error(_("could not create fd from pipe for '%s'"),486server_thread_data->server_data->buf_path.buf);487
488ret = read_packetized_to_strbuf(489reply_data.fd, &buf,490PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR);491if (ret >= 0) {492ret = server_thread_data->server_data->application_cb(493server_thread_data->server_data->application_data,494buf.buf, buf.len, do_io_reply_callback, &reply_data);495
496packet_flush_gently(reply_data.fd);497
498FlushFileBuffers((HANDLE)_get_osfhandle((reply_data.fd)));499}500else {501/*502* The client probably disconnected/shutdown before it
503* could send a well-formed message. Ignore it.
504*/
505}506
507strbuf_release(&buf);508close(reply_data.fd);509
510return ret;511}
512
513/*
514* Handle IPC request and response with this connected client. And reset
515* the pipe to prepare for the next client.
516*/
517static int use_connection(struct ipc_server_thread_data *server_thread_data)518{
519int ret;520
521ret = do_io(server_thread_data);522
523FlushFileBuffers(server_thread_data->hPipe);524DisconnectNamedPipe(server_thread_data->hPipe);525
526return ret;527}
528
529/*
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
532* client.
533*/
534static void *server_thread_proc(void *_server_thread_data)535{
536struct ipc_server_thread_data *server_thread_data = _server_thread_data;537HANDLE hEventConnected = INVALID_HANDLE_VALUE;538OVERLAPPED oConnect;539enum connect_result cr;540int ret;541
542assert(server_thread_data->hPipe != INVALID_HANDLE_VALUE);543
544trace2_thread_start("ipc-server");545trace2_data_string("ipc-server", NULL, "pipe",546server_thread_data->server_data->buf_path.buf);547
548hEventConnected = CreateEventW(NULL, TRUE, FALSE, NULL);549
550memset(&oConnect, 0, sizeof(oConnect));551oConnect.hEvent = hEventConnected;552
553for (;;) {554cr = wait_for_connection(server_thread_data, &oConnect);555
556switch (cr) {557case CR_SHUTDOWN:558goto finished;559
560case CR_CONNECTED:561ret = use_connection(server_thread_data);562if (ret == SIMPLE_IPC_QUIT) {563ipc_server_stop_async(564server_thread_data->server_data);565goto finished;566}567if (ret > 0) {568/*569* Ignore (transient) IO errors with this
570* client and reset for the next client.
571*/
572}573break;574
575case CR_CONNECT_PENDING:576/* By construction, this should not happen. */577BUG("ipc-server[%s]: unexpeced CR_CONNECT_PENDING",578server_thread_data->server_data->buf_path.buf);579
580case CR_CONNECT_ERROR:581case CR_WAIT_ERROR:582/*583* Ignore these theoretical errors.
584*/
585DisconnectNamedPipe(server_thread_data->hPipe);586break;587
588default:589BUG("unandled case after wait_for_connection");590}591}592
593finished:594CloseHandle(server_thread_data->hPipe);595CloseHandle(hEventConnected);596
597trace2_thread_exit();598return NULL;599}
600
601/*
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.
606*
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.)
611*/
612struct my_sa_data613{
614PSID pEveryoneSID;615PACL pACL;616PSECURITY_DESCRIPTOR pSD;617LPSECURITY_ATTRIBUTES lpSA;618};619
620static void init_sa(struct my_sa_data *d)621{
622memset(d, 0, sizeof(*d));623}
624
625static void release_sa(struct my_sa_data *d)626{
627if (d->pEveryoneSID)628FreeSid(d->pEveryoneSID);629if (d->pACL)630LocalFree(d->pACL);631if (d->pSD)632LocalFree(d->pSD);633if (d->lpSA)634LocalFree(d->lpSA);635
636memset(d, 0, sizeof(*d));637}
638
639/*
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.
642*
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.
646*
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.
652*
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--
655*
656* Returns d->lpSA set to a SA or NULL.
657*/
658static LPSECURITY_ATTRIBUTES get_sa(struct my_sa_data *d)659{
660SID_IDENTIFIER_AUTHORITY sid_auth_world = SECURITY_WORLD_SID_AUTHORITY;661#define NR_EA (1)662EXPLICIT_ACCESS ea[NR_EA];663DWORD dwResult;664
665if (!AllocateAndInitializeSid(&sid_auth_world, 1,666SECURITY_WORLD_RID, 0,0,0,0,0,0,0,667&d->pEveryoneSID)) {668DWORD gle = GetLastError();669trace2_data_intmax("ipc-debug", NULL, "alloc-world-sid/gle",670(intmax_t)gle);671goto fail;672}673
674memset(ea, 0, NR_EA * sizeof(EXPLICIT_ACCESS));675
676ea[0].grfAccessPermissions = GENERIC_READ | GENERIC_WRITE;677ea[0].grfAccessMode = SET_ACCESS;678ea[0].grfInheritance = NO_INHERITANCE;679ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;680ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;681ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;682ea[0].Trustee.ptstrName = (LPTSTR)d->pEveryoneSID;683
684dwResult = SetEntriesInAcl(NR_EA, ea, NULL, &d->pACL);685if (dwResult != ERROR_SUCCESS) {686DWORD gle = GetLastError();687trace2_data_intmax("ipc-debug", NULL, "set-acl-entry/gle",688(intmax_t)gle);689trace2_data_intmax("ipc-debug", NULL, "set-acl-entry/dw",690(intmax_t)dwResult);691goto fail;692}693
694d->pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(695LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);696if (!InitializeSecurityDescriptor(d->pSD, SECURITY_DESCRIPTOR_REVISION)) {697DWORD gle = GetLastError();698trace2_data_intmax("ipc-debug", NULL, "init-sd/gle", (intmax_t)gle);699goto fail;700}701
702if (!SetSecurityDescriptorDacl(d->pSD, TRUE, d->pACL, FALSE)) {703DWORD gle = GetLastError();704trace2_data_intmax("ipc-debug", NULL, "set-sd-dacl/gle", (intmax_t)gle);705goto fail;706}707
708d->lpSA = (LPSECURITY_ATTRIBUTES)LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES));709d->lpSA->nLength = sizeof(SECURITY_ATTRIBUTES);710d->lpSA->lpSecurityDescriptor = d->pSD;711d->lpSA->bInheritHandle = FALSE;712
713return d->lpSA;714
715fail:716release_sa(d);717return NULL;718}
719
720static HANDLE create_new_pipe(wchar_t *wpath, int is_first)721{
722HANDLE hPipe;723DWORD dwOpenMode, dwPipeMode;724struct my_sa_data my_sa_data;725
726init_sa(&my_sa_data);727
728dwOpenMode = PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND |729FILE_FLAG_OVERLAPPED;730
731dwPipeMode = PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE | PIPE_WAIT |732PIPE_REJECT_REMOTE_CLIENTS;733
734if (is_first) {735dwOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;736
737/*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
741* change them.
742*/
743get_sa(&my_sa_data);744}745
746hPipe = CreateNamedPipeW(wpath, dwOpenMode, dwPipeMode,747PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0,748my_sa_data.lpSA);749
750release_sa(&my_sa_data);751
752return hPipe;753}
754
755int ipc_server_run_async(struct ipc_server_data **returned_server_data,756const char *path, const struct ipc_server_opts *opts,757ipc_server_application_cb *application_cb,758void *application_data)759{
760struct ipc_server_data *server_data;761wchar_t wpath[MAX_PATH];762HANDLE hPipeFirst = INVALID_HANDLE_VALUE;763int k;764int ret = 0;765int nr_threads = opts->nr_threads;766
767*returned_server_data = NULL;768
769ret = initialize_pipe_name(path, wpath, ARRAY_SIZE(wpath));770if (ret < 0) {771errno = EINVAL;772return -1;773}774
775hPipeFirst = create_new_pipe(wpath, 1);776if (hPipeFirst == INVALID_HANDLE_VALUE) {777errno = EADDRINUSE;778return -2;779}780
781server_data = xcalloc(1, sizeof(*server_data));782server_data->magic = MAGIC_SERVER_DATA;783server_data->application_cb = application_cb;784server_data->application_data = application_data;785server_data->hEventStopRequested = CreateEvent(NULL, TRUE, FALSE, NULL);786strbuf_init(&server_data->buf_path, 0);787strbuf_addstr(&server_data->buf_path, path);788wcscpy(server_data->wpath, wpath);789
790if (nr_threads < 1)791nr_threads = 1;792
793for (k = 0; k < nr_threads; k++) {794struct ipc_server_thread_data *std;795
796std = xcalloc(1, sizeof(*std));797std->magic = MAGIC_SERVER_THREAD_DATA;798std->server_data = server_data;799std->hPipe = INVALID_HANDLE_VALUE;800
801std->hPipe = (k == 0)802? hPipeFirst803: create_new_pipe(server_data->wpath, 0);804
805if (std->hPipe == INVALID_HANDLE_VALUE) {806/*807* If we've reached a pipe instance limit for
808* this path, just use fewer threads.
809*/
810free(std);811break;812}813
814if (pthread_create(&std->pthread_id, NULL,815server_thread_proc, std)) {816/*817* Likewise, if we're out of threads, just use
818* fewer threads than requested.
819*
820* However, we just give up if we can't even get
821* one thread. This should not happen.
822*/
823if (k == 0)824die(_("could not start thread[0] for '%s'"),825path);826
827CloseHandle(std->hPipe);828free(std);829break;830}831
832std->next_thread = server_data->thread_list;833server_data->thread_list = std;834}835
836*returned_server_data = server_data;837return 0;838}
839
840int ipc_server_stop_async(struct ipc_server_data *server_data)841{
842if (!server_data)843return 0;844
845/*846* Gently tell all of the ipc_server threads to shutdown.
847* This will be seen the next time they are idle (and waiting
848* for a connection).
849*
850* We DO NOT attempt to force them to drop an active connection.
851*/
852SetEvent(server_data->hEventStopRequested);853return 0;854}
855
856int ipc_server_await(struct ipc_server_data *server_data)857{
858DWORD dwWaitResult;859
860if (!server_data)861return 0;862
863dwWaitResult = WaitForSingleObject(server_data->hEventStopRequested, INFINITE);864if (dwWaitResult != WAIT_OBJECT_0)865return error(_("wait for hEvent failed for '%s'"),866server_data->buf_path.buf);867
868while (server_data->thread_list) {869struct ipc_server_thread_data *std = server_data->thread_list;870
871pthread_join(std->pthread_id, NULL);872
873server_data->thread_list = std->next_thread;874free(std);875}876
877server_data->is_stopped = 1;878
879return 0;880}
881
882void ipc_server_free(struct ipc_server_data *server_data)883{
884if (!server_data)885return;886
887if (!server_data->is_stopped)888BUG("cannot free ipc-server while running for '%s'",889server_data->buf_path.buf);890
891strbuf_release(&server_data->buf_path);892
893if (server_data->hEventStopRequested != INVALID_HANDLE_VALUE)894CloseHandle(server_data->hEventStopRequested);895
896while (server_data->thread_list) {897struct ipc_server_thread_data *std = server_data->thread_list;898
899server_data->thread_list = std->next_thread;900free(std);901}902
903free(server_data);904}
905