From 63888b91f62a9c126c1cfa61ec3ffac35a6a36f1 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Mon, 14 Nov 2011 00:42:49 +0000 Subject: Support jobserver capability on Windows systems. Implementation contributed by Troy Runkel --- w32/include/sub_proc.h | 12 ++++- w32/subproc/sub_proc.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 145 insertions(+), 9 deletions(-) (limited to 'w32') diff --git a/w32/include/sub_proc.h b/w32/include/sub_proc.h index 9133ce3..b61373d 100644 --- a/w32/include/sub_proc.h +++ b/w32/include/sub_proc.h @@ -40,7 +40,7 @@ EXTERN_DECL(long process_pipe_io, (HANDLE proc, char *stdin_data, int stdin_data_len)); EXTERN_DECL(long process_file_io, (HANDLE proc)); EXTERN_DECL(void process_cleanup, (HANDLE proc)); -EXTERN_DECL(HANDLE process_wait_for_any, (VOID_DECL)); +EXTERN_DECL(HANDLE process_wait_for_any, (int block, DWORD* pdwWaitStatus)); EXTERN_DECL(void process_register, (HANDLE proc)); EXTERN_DECL(HANDLE process_easy, (char** argv, char** env)); EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal)); @@ -57,4 +57,14 @@ EXTERN_DECL(int process_outcnt, (HANDLE proc)); EXTERN_DECL(int process_errcnt, (HANDLE proc)); EXTERN_DECL(void process_pipes, (HANDLE proc, int pipes[3])); +/* jobserver routines */ +EXTERN_DECL(int open_jobserver_semaphore, (char* name)); +EXTERN_DECL(int create_jobserver_semaphore, (int tokens)); +EXTERN_DECL(void free_jobserver_semaphore, (VOID_DECL)); +EXTERN_DECL(int acquire_jobserver_semaphore, (VOID_DECL)); +EXTERN_DECL(int release_jobserver_semaphore, (VOID_DECL)); +EXTERN_DECL(int has_jobserver_semaphore, (VOID_DECL)); +EXTERN_DECL(char* get_jobserver_semaphore_name, (VOID_DECL)); +EXTERN_DECL(int wait_for_semaphore_or_child_process, (VOID_DECL)); + #endif diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c index dcb77bf..64185b3 100644 --- a/w32/subproc/sub_proc.c +++ b/w32/subproc/sub_proc.c @@ -58,6 +58,126 @@ static sub_process *proc_array[MAXIMUM_WAIT_OBJECTS]; static int proc_index = 0; static int fake_exits_pending = 0; +/* Windows jobserver implementation variables */ +static char jobserver_semaphore_name[MAX_PATH + 1]; +static HANDLE jobserver_semaphore = NULL; + +/* Open existing jobserver semaphore */ +int open_jobserver_semaphore(char* name) +{ + jobserver_semaphore = OpenSemaphore( + SEMAPHORE_ALL_ACCESS, // Semaphore access setting + FALSE, // Child processes DON'T inherit + name); // Semaphore name + + if (jobserver_semaphore == NULL) + return 0; + + return 1; +} + +/* Create new jobserver semaphore */ +int create_jobserver_semaphore(int tokens) +{ + sprintf(jobserver_semaphore_name, "gmake_semaphore_%d", _getpid()); + + jobserver_semaphore = CreateSemaphore( + NULL, // Use default security descriptor + tokens, // Initial count + tokens, // Maximum count + jobserver_semaphore_name); // Semaphore name + + if (jobserver_semaphore == NULL) + return 0; + + return 1; +} + +/* Close jobserver semaphore */ +void free_jobserver_semaphore() +{ + if (jobserver_semaphore != NULL) + { + CloseHandle(jobserver_semaphore); + jobserver_semaphore = NULL; + } +} + +/* Decrement semaphore count */ +int acquire_jobserver_semaphore() +{ + DWORD dwEvent = WaitForSingleObject( + jobserver_semaphore, // Handle to semaphore + 0); // DON'T wait on semaphore + + return (dwEvent == WAIT_OBJECT_0); +} + +/* Increment semaphore count */ +int release_jobserver_semaphore() +{ + BOOL bResult = ReleaseSemaphore( + jobserver_semaphore, // handle to semaphore + 1, // increase count by one + NULL); // not interested in previous count + + return (bResult); +} + +int has_jobserver_semaphore() +{ + return (jobserver_semaphore != NULL); +} + +char* get_jobserver_semaphore_name() +{ + return (jobserver_semaphore_name); +} + +/* Wait for either the jobserver semaphore to become signalled or one of our + * child processes to terminate. + */ +int wait_for_semaphore_or_child_process() +{ + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + DWORD dwHandleCount = 1; + DWORD dwEvent; + int i; + + /* Add jobserver semaphore to first slot. */ + handles[0] = jobserver_semaphore; + + /* Build array of handles to wait for */ + for (i = 0; i < proc_index; i++) + { + /* Don't wait on child processes that have already finished */ + if (fake_exits_pending && proc_array[i]->exit_code) + continue; + + handles[dwHandleCount++] = (HANDLE) proc_array[i]->pid; + } + + dwEvent = WaitForMultipleObjects( + dwHandleCount, // number of objects in array + handles, // array of objects + FALSE, // wait for any object + INFINITE); // wait until object is signalled + + switch(dwEvent) + { + case WAIT_FAILED: + return -1; + + case WAIT_OBJECT_0: + /* Indicate that the semaphore was signalled */ + return 1; + + default: + /* Assume that one or more of the child processes terminated. */ + return 0; + } +} + /* * When a process has been waited for, adjust the wait state * array so that we don't wait for it again @@ -87,7 +207,7 @@ process_adjust_wait_state(sub_process* pproc) * Waits for any of the registered child processes to finish. */ static sub_process * -process_wait_for_any_private(void) +process_wait_for_any_private(int block, DWORD* pdwWaitStatus) { HANDLE handles[MAXIMUM_WAIT_OBJECTS]; DWORD retval, which; @@ -106,7 +226,7 @@ process_wait_for_any_private(void) /* wait for someone to exit */ if (!fake_exits_pending) { - retval = WaitForMultipleObjects(proc_index, handles, FALSE, INFINITE); + retval = WaitForMultipleObjects(proc_index, handles, FALSE, (block ? INFINITE : 0)); which = retval - WAIT_OBJECT_0; } else { fake_exits_pending--; @@ -114,13 +234,19 @@ process_wait_for_any_private(void) which = i; } + /* If the pointer is not NULL, set the wait status result variable. */ + if (pdwWaitStatus) + *pdwWaitStatus = retval; + /* return pointer to process */ - if (retval != WAIT_FAILED) { + if ((retval == WAIT_TIMEOUT) || (retval == WAIT_FAILED)) { + return NULL; + } + else { sub_process* pproc = proc_array[which]; process_adjust_wait_state(pproc); return pproc; - } else - return NULL; + } } /* @@ -179,9 +305,9 @@ process_used_slots(void) */ HANDLE -process_wait_for_any(void) +process_wait_for_any(int block, DWORD* pdwWaitStatus) { - sub_process* pproc = process_wait_for_any_private(); + sub_process* pproc = process_wait_for_any_private(block, pdwWaitStatus); if (!pproc) return NULL; @@ -865,7 +991,7 @@ process_file_io( DWORD ierr; if (proc == NULL) - pproc = process_wait_for_any_private(); + pproc = process_wait_for_any_private(1, 0); else pproc = (sub_process *)proc; -- cgit v1.2.3