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 --- job.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) (limited to 'job.c') diff --git a/job.c b/job.c index c2ce84d..4fe62c1 100644 --- a/job.c +++ b/job.c @@ -108,6 +108,7 @@ static void vmsWaitForChildren (int *); # include "sub_proc.h" # include "w32err.h" # include "pathstuff.h" +# define WAIT_NOHANG 1 #endif /* WINDOWS32 */ #ifdef __EMX__ @@ -528,9 +529,9 @@ reap_children (int block, int err) { #ifndef WINDOWS32 WAIT_T status; +#endif /* Initially, assume we have some. */ int reap_more = 1; -#endif #ifdef WAIT_NOHANG # define REAP_MORE reap_more @@ -699,6 +700,7 @@ reap_children (int block, int err) HANDLE hPID; int werr; HANDLE hcTID, hcPID; + DWORD dwWaitStatus = 0; exit_code = 0; exit_sig = 0; coredump = 0; @@ -722,7 +724,7 @@ reap_children (int block, int err) } /* wait for anything to finish */ - hPID = process_wait_for_any(); + hPID = process_wait_for_any(block, &dwWaitStatus); if (hPID) { @@ -744,6 +746,18 @@ reap_children (int block, int err) coredump = 0; } + else if (dwWaitStatus == WAIT_FAILED) + { + /* The WaitForMultipleObjects() failed miserably. Punt. */ + pfatal_with_name ("WaitForMultipleObjects"); + } + else if (dwWaitStatus == WAIT_TIMEOUT) + { + /* No child processes are finished. Give up waiting. */ + reap_more = 0; + break; + } + pid = (pid_t) hPID; } #endif /* WINDOWS32 */ @@ -926,6 +940,19 @@ free_child (struct child *child) /* If we're using the jobserver and this child is not the only outstanding job, put a token back into the pipe for it. */ +#ifdef WINDOWS32 + if (has_jobserver_semaphore() && jobserver_tokens > 1) + { + if (! release_jobserver_semaphore()) + { + DWORD err = GetLastError(); + fatal (NILF,_("release jobserver semaphore: (Error %d: %s)"), + err, map_windows32_error_to_string(err)); + } + + DB (DB_JOBS, (_("Released token for child %p (%s).\n"), child, child->file->name)); + } +#else if (job_fds[1] >= 0 && jobserver_tokens > 1) { char token = '+'; @@ -940,6 +967,7 @@ free_child (struct child *child) DB (DB_JOBS, (_("Released token for child %p (%s).\n"), child, child->file->name)); } +#endif --jobserver_tokens; @@ -991,7 +1019,7 @@ unblock_sigs (void) } #endif -#ifdef MAKE_JOBSERVER +#if defined(MAKE_JOBSERVER) && !defined(WINDOWS32) RETSIGTYPE job_noop (int sig UNUSED) { @@ -1740,7 +1768,11 @@ new_job (struct file *file) just once). Also more thought needs to go into the entire algorithm; this is where the old parallel job code waits, so... */ +#ifdef WINDOWS32 + else if (has_jobserver_semaphore()) +#else else if (job_fds[0] >= 0) +#endif while (1) { char token; @@ -1754,6 +1786,7 @@ new_job (struct file *file) if (!jobserver_tokens) break; +#ifndef WINDOWS32 /* Read a token. As long as there's no token available we'll block. We enable interruptible system calls before the read(2) so that if we get a SIGCHLD while we're waiting, we'll return with EINTR and @@ -1782,6 +1815,7 @@ new_job (struct file *file) DB (DB_JOBS, ("Duplicate the job FD\n")); job_rfd = dup (job_fds[0]); } +#endif /* Reap anything that's currently waiting. */ reap_children (0, 0); @@ -1800,11 +1834,24 @@ new_job (struct file *file) if (!children) fatal (NILF, "INTERNAL: no children as we go to sleep on read\n"); +#ifdef WINDOWS32 + /* On Windows we simply wait for the jobserver semaphore to become + * signalled or one of our child processes to terminate. + */ + got_token = wait_for_semaphore_or_child_process(); + if (got_token < 0) + { + DWORD err = GetLastError(); + fatal (NILF,_("semaphore or child process wait: (Error %d: %s)"), + err, map_windows32_error_to_string(err)); + } +#else /* Set interruptible system calls, and read() for a job token. */ set_child_handler_action_flags (1, waiting_jobs != NULL); got_token = read (job_rfd, &token, 1); saved_errno = errno; set_child_handler_action_flags (0, waiting_jobs != NULL); +#endif /* If we got one, we're done here. */ if (got_token == 1) @@ -1814,6 +1861,7 @@ new_job (struct file *file) break; } +#ifndef WINDOWS32 /* If the error _wasn't_ expected (EINTR or EBADF), punt. Otherwise, go back and reap_children(), and try again. */ errno = saved_errno; @@ -1821,6 +1869,7 @@ new_job (struct file *file) pfatal_with_name (_("read jobs pipe")); if (errno == EBADF) DB (DB_JOBS, ("Read returned EBADF.\n")); +#endif } #endif @@ -2150,7 +2199,7 @@ exec_command (char **argv, char **envp) } /* wait and reap last child */ - hWaitPID = process_wait_for_any(); + hWaitPID = process_wait_for_any(1, 0); while (hWaitPID) { /* was an error found on this process? */ -- cgit v1.2.3