summaryrefslogtreecommitdiff
path: root/w32
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2011-11-14 00:42:49 +0000
committerPaul Smith <psmith@gnu.org>2011-11-14 00:42:49 +0000
commit63888b91f62a9c126c1cfa61ec3ffac35a6a36f1 (patch)
tree345319c17418652774ea176d9175b33132240c7f /w32
parent934f51d166848c275828f14ad5cc29fe1c3b578a (diff)
downloadgunmake-63888b91f62a9c126c1cfa61ec3ffac35a6a36f1.tar.gz
Support jobserver capability on Windows systems.
Implementation contributed by Troy Runkel <Troy.Runkel@mathworks.com>
Diffstat (limited to 'w32')
-rw-r--r--w32/include/sub_proc.h12
-rw-r--r--w32/subproc/sub_proc.c142
2 files changed, 145 insertions, 9 deletions
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;