From da7df54309eb759837a289ade900fe8e3d6ddc36 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 27 Apr 2013 14:20:49 +0300 Subject: Support --output-sync on MS-Windows. w32/compat/posixfcn.c: New file, with emulations of Posix functions and Posix functionality for MS-Windows. w32/subproc/sub_proc.c: Include io.h. (process_noinherit): New function, forces a file descriptor to not be inherited by child processes. (process_easy): Accept two additional arguments, and use them to set up the standard output and standard error handles of the child process. w32/include/sub_proc.h (process_easy): Adjust prototype. (process_noinherit): Add prototype. read.c [WINDOWS32]: Include windows.h and sub_proc.h. makeint.h (LOCALEDIR) [WINDOWS32}: Define to NULL if not defined. This is needed because the MS-Windows build doesn't have a canonical place for LOCALEDIR. (WIN32_LEAN_AND_MEAN) [WINDOWS32]: Define, to avoid getting from windows.h header too much stuff that could conflict with the code. main.c : New static variable. : Add support for "--sync-mutex" switch. (decode_output_sync_flags): Decode the --sync-mutex= switch. (prepare_mutex_handle_string) [WINDOWS32]: New function. (main): Add "output-sync" to .FEATURES. job.h (CLOSE_ON_EXEC) [WINDOWS32]: Define to call process_noinherit. (F_GETFD, F_SETLKW, F_WRLCK, F_UNLCK, struct flock) [WINDOWS32]: New macros. (RECORD_SYNC_MUTEX): New macro, a no-op for Posix platforms. (sync_handle_t): New typedef. job.c : Change type to sync_handle_t. (FD_NOT_EMPTY): Seek to the file's end. Suggested by Frank Heckenbach . (pump_from_tmp_fd) [WINDOWS32]: Switch to_fd to binary mode for the duration of this function, and then change back before returning. (start_job_command) [WINDOWS32]: Support output_sync mode on MS-Windows. Use a system-wide mutex instead of locking stdout/stderr. Call process_easy with two additional arguments: child->outfd and child->errfd. (exec_command) [WINDOWS32]: Pass two additional arguments, both -1, to process_easy, to adjust for the changed function signature. function.c (windows32_openpipe) [WINDOWS32]: This function now returns an int, which is -1 if it fails and zero otherwise. It also calls 'error' instead of 'fatal', to avoid exiting prematurely. (func_shell_base) [WINDOWS32]: Call perror_with_name if windows32_openpipe fails, now that it always returns. This avoids a compiler warning that error_prefix is not used in the MS-Windows build. config.h.W32.template (OUTPUT_SYNC): Define. build_w32.bat: Add w32/compat/posixfcn.c to compilation and linking commands. From Frank Heckenbach : job.c (sync_output): Don't discard the output if acquire_semaphore fails; instead, dump the output unsynchronized. --- job.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 10 deletions(-) (limited to 'job.c') diff --git a/job.c b/job.c index d88fc57..18494f6 100644 --- a/job.c +++ b/job.c @@ -246,11 +246,11 @@ unsigned int jobserver_tokens = 0; #ifdef OUTPUT_SYNC /* Semaphore for use in -j mode with output_sync. */ -int sync_handle = -1; +sync_handle_t sync_handle = -1; #define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF)) -#define FD_NOT_EMPTY(_f) ((_f) >= 0 && lseek ((_f), 0, SEEK_CUR) > 0) +#define FD_NOT_EMPTY(_f) ((_f) >= 0 && lseek ((_f), 0, SEEK_END) > 0) #endif /* OUTPUT_SYNC */ #ifdef WINDOWS32 @@ -588,6 +588,14 @@ pump_from_tmp_fd (int from_fd, int to_fd) ssize_t nleft, nwrite; char buffer[8192]; +#ifdef WINDOWS32 + int prev_mode; + + /* from_fd is opened by open_tmpfd, which does it in binary mode, so + we need the mode of to_fd to match that. */ + prev_mode = _setmode (to_fd, _O_BINARY); +#endif + if (lseek (from_fd, 0, SEEK_SET) == -1) perror ("lseek()"); @@ -605,13 +613,20 @@ pump_from_tmp_fd (int from_fd, int to_fd) if (nwrite < 0) { perror ("write()"); - return; + goto finished; } write_buf += nwrite; nleft -= nwrite; } } +finished: + +#ifdef WINDOWS32 + /* Switch to_fd back to its original mode, so that log messages by + Make have the same EOL format as without --output-sync. */ + _setmode (to_fd, prev_mode); +#endif } /* Support routine for sync_output() */ @@ -622,7 +637,7 @@ acquire_semaphore (void) fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; - fl.l_start = 0; /* lock just one byte according to pid */ + fl.l_start = 0; /* lock just one byte */ fl.l_len = 1; if (fcntl (sync_handle, F_SETLKW, &fl) != -1) return &fl; @@ -648,13 +663,15 @@ release_semaphore (void *sem) static void sync_output (struct child *c) { - void *sem; - int outfd_not_empty = FD_NOT_EMPTY (c->outfd); int errfd_not_empty = FD_NOT_EMPTY (c->errfd); - if ((outfd_not_empty || errfd_not_empty) && (sem = acquire_semaphore ())) + if (outfd_not_empty || errfd_not_empty) { + /* Try to acquire the semaphore. If it fails, dump the output + unsynchronized; still better than silently discarding it. */ + void *sem = acquire_semaphore (); + /* We've entered the "critical section" during which a lock is held. We want to keep it as short as possible. */ if (outfd_not_empty) @@ -667,7 +684,8 @@ sync_output (struct child *c) pump_from_tmp_fd (c->errfd, fileno (stderr)); /* Exit the critical section. */ - release_semaphore (sem); + if (sem) + release_semaphore (sem); } if (c->outfd >= 0) @@ -1723,6 +1741,42 @@ start_job_command (struct child *child) HANDLE hPID; char* arg0; +#ifdef OUTPUT_SYNC + if (output_sync) + { + static int combined_output; + /* If output_sync is turned on, create a mutex to + synchronize on. This is done only once. */ + if (sync_handle == -1) + { + if ((!STREAM_OK (stdout) && !STREAM_OK (stderr)) + || (sync_handle = create_mutex ()) == -1) + { + perror_with_name ("output-sync suppressed: ", "stderr"); + output_sync = 0; + } + else + { + combined_output = same_stream (stdout, stderr); + prepare_mutex_handle_string (sync_handle); + } + } + /* If we can synchronize, create a temporary file to hold + child's stdout, and another one for its stderr, if they + are separate. */ + if (output_sync == OUTPUT_SYNC_MAKE + || (output_sync == OUTPUT_SYNC_TARGET + && !(flags & COMMANDS_RECURSE))) + { + if (!assign_child_tempfiles (child, combined_output)) + { + perror_with_name ("output-sync suppressed: ", "stderr"); + output_sync = 0; + } + } + } +#endif /* OUTPUT_SYNC */ + /* make UNC paths safe for CreateProcess -- backslash format */ arg0 = argv[0]; if (arg0 && arg0[0] == '/' && arg0[1] == '/') @@ -1733,7 +1787,14 @@ start_job_command (struct child *child) /* make sure CreateProcess() has Path it needs */ sync_Path_environment(); - hPID = process_easy(argv, child->environment); +#ifdef OUTPUT_SYNC + /* Divert child output into tempfile(s) if output_sync in use. */ + if (output_sync) + hPID = process_easy(argv, child->environment, + child->outfd, child->errfd); + else +#endif + hPID = process_easy(argv, child->environment, -1, -1); if (hPID != INVALID_HANDLE_VALUE) child->pid = (pid_t) hPID; @@ -2417,7 +2478,7 @@ exec_command (char **argv, char **envp) sync_Path_environment(); /* launch command */ - hPID = process_easy(argv, envp); + hPID = process_easy(argv, envp, -1, -1); /* make sure launch ok */ if (hPID == INVALID_HANDLE_VALUE) -- cgit v1.2.3