mirror of
https://github.com/mirror/make.git
synced 2025-01-23 10:40:13 +08:00
da7df54309
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 <sync_mutex>: New static variable. <switches>: 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 <sync_handle>: Change type to sync_handle_t. (FD_NOT_EMPTY): Seek to the file's end. Suggested by Frank Heckenbach <f.heckenbach@fh-soft.de>. (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 <f.heckenbach@fh-soft.de>: job.c (sync_output): Don't discard the output if acquire_semaphore fails; instead, dump the output unsynchronized.
259 lines
6.5 KiB
C
259 lines
6.5 KiB
C
/* Replacements for Posix functions and Posix functionality for MS-Windows.
|
|
|
|
Copyright (C) 2013 Free Software Foundation, Inc.
|
|
This file is part of GNU Make.
|
|
|
|
GNU Make is free software; you can redistribute it and/or modify it under the
|
|
terms of the GNU General Public License as published by the Free Software
|
|
Foundation; either version 3 of the License, or (at your option) any later
|
|
version.
|
|
|
|
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include <string.h>
|
|
#include <io.h>
|
|
#include <stdarg.h>
|
|
#include <errno.h>
|
|
#include <windows.h>
|
|
|
|
#include "makeint.h"
|
|
#include "job.h"
|
|
|
|
#ifdef OUTPUT_SYNC
|
|
/* Support for OUTPUT_SYNC and related functionality. */
|
|
|
|
/* Emulation of fcntl that supports only F_GETFD and F_SETLKW. */
|
|
int
|
|
fcntl (intptr_t fd, int cmd, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start (ap, cmd);
|
|
|
|
switch (cmd)
|
|
{
|
|
case F_GETFD:
|
|
va_end (ap);
|
|
/* Could have used GetHandleInformation, but that isn't
|
|
supported on Windows 9X. */
|
|
if (_get_osfhandle (fd) == -1)
|
|
return -1;
|
|
return 0;
|
|
case F_SETLKW:
|
|
{
|
|
void *buf = va_arg (ap, void *);
|
|
struct flock *fl = (struct flock *)buf;
|
|
HANDLE hmutex = (HANDLE)fd;
|
|
static struct flock last_fl;
|
|
short last_type = last_fl.l_type;
|
|
|
|
va_end (ap);
|
|
|
|
if (hmutex == INVALID_HANDLE_VALUE || !hmutex)
|
|
return -1;
|
|
|
|
last_fl = *fl;
|
|
|
|
switch (fl->l_type)
|
|
{
|
|
|
|
case F_WRLCK:
|
|
{
|
|
DWORD result;
|
|
|
|
if (last_type == F_WRLCK)
|
|
{
|
|
/* Don't call WaitForSingleObject if we already
|
|
own the mutex, because doing so will require
|
|
us to call ReleaseMutex an equal number of
|
|
times, before the mutex is actually
|
|
released. */
|
|
return 0;
|
|
}
|
|
|
|
result = WaitForSingleObject (hmutex, INFINITE);
|
|
switch (result)
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
/* We don't care if the mutex owner crashed or
|
|
exited. */
|
|
case WAIT_ABANDONED:
|
|
return 0;
|
|
case WAIT_FAILED:
|
|
case WAIT_TIMEOUT: /* cannot happen, really */
|
|
{
|
|
DWORD err = GetLastError ();
|
|
|
|
/* Invalidate the last command. */
|
|
memset (&last_fl, 0, sizeof (last_fl));
|
|
|
|
switch (err)
|
|
{
|
|
case ERROR_INVALID_HANDLE:
|
|
case ERROR_INVALID_FUNCTION:
|
|
errno = EINVAL;
|
|
return -1;
|
|
default:
|
|
errno = EDEADLOCK;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case F_UNLCK:
|
|
{
|
|
/* FIXME: Perhaps we should call ReleaseMutex
|
|
repatedly until it errors out, to make sure the
|
|
mutext is released even if we somehow managed to
|
|
to take ownership multiple times? */
|
|
BOOL status = ReleaseMutex (hmutex);
|
|
|
|
if (status)
|
|
return 0;
|
|
else
|
|
{
|
|
DWORD err = GetLastError ();
|
|
|
|
if (err == ERROR_NOT_OWNER)
|
|
errno = EPERM;
|
|
else
|
|
{
|
|
memset (&last_fl, 0, sizeof (last_fl));
|
|
errno = EINVAL;
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
default:
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
}
|
|
default:
|
|
errno = ENOSYS;
|
|
va_end (ap);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static intptr_t mutex_handle = -1;
|
|
|
|
/* Record in a static variable the mutex handle we were requested to
|
|
use. That nameless mutex was created by the top-level Make, and
|
|
its handle was passed to us via inheritance. The value of that
|
|
handle is passed via the command-line arguments, so that we know
|
|
which handle to use. */
|
|
void
|
|
record_sync_mutex (const char *str)
|
|
{
|
|
char *endp;
|
|
intptr_t hmutex = strtol (str, &endp, 16);
|
|
|
|
if (*endp == '\0')
|
|
mutex_handle = hmutex;
|
|
else
|
|
{
|
|
mutex_handle = -1;
|
|
errno = EINVAL;
|
|
}
|
|
}
|
|
|
|
/* Create a new mutex or reuse one created by our parent. */
|
|
intptr_t
|
|
create_mutex (void)
|
|
{
|
|
SECURITY_ATTRIBUTES secattr;
|
|
intptr_t hmutex = -1;
|
|
|
|
/* If we have a mutex handle passed from the parent Make, just use
|
|
that. */
|
|
if (mutex_handle > 0)
|
|
return mutex_handle;
|
|
|
|
/* We are the top-level Make, and we want the handle to be inherited
|
|
by our child processes. */
|
|
secattr.nLength = sizeof (secattr);
|
|
secattr.lpSecurityDescriptor = NULL; /* use default security descriptor */
|
|
secattr.bInheritHandle = TRUE;
|
|
|
|
hmutex = (intptr_t)CreateMutex (&secattr, FALSE, NULL);
|
|
if (!hmutex)
|
|
{
|
|
DWORD err = GetLastError ();
|
|
|
|
fprintf (stderr, "CreateMutex: error %lu\n", err);
|
|
errno = ENOLCK;
|
|
hmutex = -1;
|
|
}
|
|
|
|
mutex_handle = hmutex;
|
|
return hmutex;
|
|
}
|
|
|
|
/* Return non-zero if F1 and F2 are 2 streams representing the same
|
|
file or pipe or device. */
|
|
int
|
|
same_stream (FILE *f1, FILE *f2)
|
|
{
|
|
HANDLE fh1 = (HANDLE)_get_osfhandle (fileno (f1));
|
|
HANDLE fh2 = (HANDLE)_get_osfhandle (fileno (f2));
|
|
|
|
/* Invalid file descriptors get treated as different streams. */
|
|
if (fh1 && fh1 != INVALID_HANDLE_VALUE
|
|
&& fh2 && fh2 != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (fh1 == fh2)
|
|
return 1;
|
|
else
|
|
{
|
|
DWORD ftyp1 = GetFileType (fh1), ftyp2 = GetFileType (fh2);
|
|
|
|
if (ftyp1 != ftyp2
|
|
|| ftyp1 == FILE_TYPE_UNKNOWN || ftyp2 == FILE_TYPE_UNKNOWN)
|
|
return 0;
|
|
else if (ftyp1 == FILE_TYPE_CHAR)
|
|
{
|
|
/* For character devices, check if they both refer to a
|
|
console. This loses if both handles refer to the
|
|
null device (FIXME!), but in that case we don't care
|
|
in the context of Make. */
|
|
DWORD conmode1, conmode2;
|
|
|
|
/* Each process on Windows can have at most 1 console,
|
|
so if both handles are for the console device, they
|
|
are the same. We also compare the console mode to
|
|
distinguish between tsdin and stdout/stderr. */
|
|
if (GetConsoleMode (fh1, &conmode1)
|
|
&& GetConsoleMode (fh2, &conmode2)
|
|
&& conmode1 == conmode2)
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
/* For disk files and pipes, compare their unique
|
|
attributes. */
|
|
BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
|
|
|
|
/* Pipes get zero in the volume serial number, but do
|
|
appear to have meaningful information in file index
|
|
attributes. We test file attributes as well, for a
|
|
good measure. */
|
|
if (GetFileInformationByHandle (fh1, &bhfi1)
|
|
&& GetFileInformationByHandle (fh2, &bhfi2))
|
|
return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
|
|
&& bhfi1.nFileIndexLow == bhfi2.nFileIndexLow
|
|
&& bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
|
|
&& bhfi1.dwFileAttributes == bhfi2.dwFileAttributes);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif /* OUTPUT_SYNC */
|