summaryrefslogtreecommitdiff
path: root/job.c
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 /job.c
parent934f51d166848c275828f14ad5cc29fe1c3b578a (diff)
downloadgunmake-63888b91f62a9c126c1cfa61ec3ffac35a6a36f1.tar.gz
Support jobserver capability on Windows systems.
Implementation contributed by Troy Runkel <Troy.Runkel@mathworks.com>
Diffstat (limited to 'job.c')
-rw-r--r--job.c57
1 files changed, 53 insertions, 4 deletions
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? */