Merge branch 'js/windows'

* js/windows:
  Do not use date.c:tm_to_time_t() from compat/mingw.c
  MSVC: Windows-native implementation for subset of Pthreads API
  MSVC: Fix an "incompatible pointer types" compiler warning
  Windows: avoid the "dup dance" when spawning a child process
  Windows: simplify the pipe(2) implementation
  Windows: boost startup by avoiding a static dependency on shell32.dll
  Windows: disable Python
This commit is contained in:
Junio C Hamano 2010-01-18 18:12:49 -08:00
commit 3cd02df46a
8 changed files with 328 additions and 132 deletions

View File

@ -478,6 +478,7 @@ LIB_H += commit.h
LIB_H += compat/bswap.h LIB_H += compat/bswap.h
LIB_H += compat/cygwin.h LIB_H += compat/cygwin.h
LIB_H += compat/mingw.h LIB_H += compat/mingw.h
LIB_H += compat/win32/pthread.h
LIB_H += csum-file.h LIB_H += csum-file.h
LIB_H += decorate.h LIB_H += decorate.h
LIB_H += delta.h LIB_H += delta.h
@ -995,15 +996,16 @@ ifeq ($(uname_S),Windows)
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
NO_REGEX = YesPlease NO_REGEX = YesPlease
NO_CURL = YesPlease NO_CURL = YesPlease
NO_PTHREADS = YesPlease NO_PYTHON = YesPlease
BLK_SHA1 = YesPlease BLK_SHA1 = YesPlease
THREADED_DELTA_SEARCH = YesPlease
CC = compat/vcbuild/scripts/clink.pl CC = compat/vcbuild/scripts/clink.pl
AR = compat/vcbuild/scripts/lib.pl AR = compat/vcbuild/scripts/lib.pl
CFLAGS = CFLAGS =
BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE
COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.o compat/win32/pthread.o
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -DSTRIP_EXTENSION=\".exe\" COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/fnmatch -Icompat/regex -Icompat/fnmatch -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib
lib = lib =
@ -1045,10 +1047,13 @@ ifneq (,$(findstring MINGW,$(uname_S)))
UNRELIABLE_FSTAT = UnfortunatelyYes UNRELIABLE_FSTAT = UnfortunatelyYes
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
NO_REGEX = YesPlease NO_REGEX = YesPlease
NO_PYTHON = YesPlease
BLK_SHA1 = YesPlease BLK_SHA1 = YesPlease
THREADED_DELTA_SEARCH = YesPlease
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
compat/win32/pthread.o
EXTLIBS += -lws2_32 EXTLIBS += -lws2_32
X = .exe X = .exe
ifneq (,$(wildcard ../THIS_IS_MSYSGIT)) ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
@ -1058,10 +1063,8 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
EXTLIBS += /mingw/lib/libz.a EXTLIBS += /mingw/lib/libz.a
NO_R_TO_GCC_LINKER = YesPlease NO_R_TO_GCC_LINKER = YesPlease
INTERNAL_QSORT = YesPlease INTERNAL_QSORT = YesPlease
THREADED_DELTA_SEARCH = YesPlease
else else
NO_CURL = YesPlease NO_CURL = YesPlease
NO_PTHREADS = YesPlease
endif endif
endif endif

View File

@ -1256,15 +1256,15 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
#ifdef THREADED_DELTA_SEARCH #ifdef THREADED_DELTA_SEARCH
static pthread_mutex_t read_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t read_mutex;
#define read_lock() pthread_mutex_lock(&read_mutex) #define read_lock() pthread_mutex_lock(&read_mutex)
#define read_unlock() pthread_mutex_unlock(&read_mutex) #define read_unlock() pthread_mutex_unlock(&read_mutex)
static pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t cache_mutex;
#define cache_lock() pthread_mutex_lock(&cache_mutex) #define cache_lock() pthread_mutex_lock(&cache_mutex)
#define cache_unlock() pthread_mutex_unlock(&cache_mutex) #define cache_unlock() pthread_mutex_unlock(&cache_mutex)
static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t progress_mutex;
#define progress_lock() pthread_mutex_lock(&progress_mutex) #define progress_lock() pthread_mutex_lock(&progress_mutex)
#define progress_unlock() pthread_mutex_unlock(&progress_mutex) #define progress_unlock() pthread_mutex_unlock(&progress_mutex)
@ -1591,7 +1591,26 @@ struct thread_params {
unsigned *processed; unsigned *processed;
}; };
static pthread_cond_t progress_cond = PTHREAD_COND_INITIALIZER; static pthread_cond_t progress_cond;
/*
* Mutex and conditional variable can't be statically-initialized on Windows.
*/
static void init_threaded_search(void)
{
pthread_mutex_init(&read_mutex, NULL);
pthread_mutex_init(&cache_mutex, NULL);
pthread_mutex_init(&progress_mutex, NULL);
pthread_cond_init(&progress_cond, NULL);
}
static void cleanup_threaded_search(void)
{
pthread_cond_destroy(&progress_cond);
pthread_mutex_destroy(&read_mutex);
pthread_mutex_destroy(&cache_mutex);
pthread_mutex_destroy(&progress_mutex);
}
static void *threaded_find_deltas(void *arg) static void *threaded_find_deltas(void *arg)
{ {
@ -1630,10 +1649,13 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
struct thread_params *p; struct thread_params *p;
int i, ret, active_threads = 0; int i, ret, active_threads = 0;
init_threaded_search();
if (!delta_search_threads) /* --threads=0 means autodetect */ if (!delta_search_threads) /* --threads=0 means autodetect */
delta_search_threads = online_cpus(); delta_search_threads = online_cpus();
if (delta_search_threads <= 1) { if (delta_search_threads <= 1) {
find_deltas(list, &list_size, window, depth, processed); find_deltas(list, &list_size, window, depth, processed);
cleanup_threaded_search();
return; return;
} }
if (progress > pack_to_stdout) if (progress > pack_to_stdout)
@ -1748,6 +1770,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
active_threads--; active_threads--;
} }
} }
cleanup_threaded_search();
free(p); free(p);
} }

View File

@ -3,9 +3,7 @@
#include <conio.h> #include <conio.h>
#include "../strbuf.h" #include "../strbuf.h"
#include <shellapi.h> int err_win_to_posix(DWORD winerr)
static int err_win_to_posix(DWORD winerr)
{ {
int error = ENOSYS; int error = ENOSYS;
switch(winerr) { switch(winerr) {
@ -142,12 +140,20 @@ int mingw_open (const char *filename, int oflags, ...)
return fd; return fd;
} }
static inline time_t filetime_to_time_t(const FILETIME *ft) /*
* The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
* Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
*/
static inline long long filetime_to_hnsec(const FILETIME *ft)
{ {
long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ /* Windows to Unix Epoch conversion */
winTime /= 10000000; /* Nano to seconds resolution */ return winTime - 116444736000000000LL;
return (time_t)winTime; }
static inline time_t filetime_to_time_t(const FILETIME *ft)
{
return (time_t)(filetime_to_hnsec(ft) / 10000000);
} }
/* We keep the do_lstat code in a separate function to avoid recursion. /* We keep the do_lstat code in a separate function to avoid recursion.
@ -283,64 +289,37 @@ int mkstemp(char *template)
int gettimeofday(struct timeval *tv, void *tz) int gettimeofday(struct timeval *tv, void *tz)
{ {
SYSTEMTIME st; FILETIME ft;
struct tm tm; long long hnsec;
GetSystemTime(&st);
tm.tm_year = st.wYear-1900; GetSystemTimeAsFileTime(&ft);
tm.tm_mon = st.wMonth-1; hnsec = filetime_to_hnsec(&ft);
tm.tm_mday = st.wDay; tv->tv_sec = hnsec / 10000000;
tm.tm_hour = st.wHour; tv->tv_usec = (hnsec % 10000000) / 10;
tm.tm_min = st.wMinute;
tm.tm_sec = st.wSecond;
tv->tv_sec = tm_to_time_t(&tm);
if (tv->tv_sec < 0)
return -1;
tv->tv_usec = st.wMilliseconds*1000;
return 0; return 0;
} }
int pipe(int filedes[2]) int pipe(int filedes[2])
{ {
int fd; HANDLE h[2];
HANDLE h[2], parent;
if (_pipe(filedes, 8192, 0) < 0) /* this creates non-inheritable handles */
return -1; if (!CreatePipe(&h[0], &h[1], NULL, 8192)) {
errno = err_win_to_posix(GetLastError());
parent = GetCurrentProcess();
if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[0]),
parent, &h[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) {
close(filedes[0]);
close(filedes[1]);
return -1; return -1;
} }
if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[1]), filedes[0] = _open_osfhandle((int)h[0], O_NOINHERIT);
parent, &h[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) { if (filedes[0] < 0) {
close(filedes[0]);
close(filedes[1]);
CloseHandle(h[0]);
return -1;
}
fd = _open_osfhandle((int)h[0], O_NOINHERIT);
if (fd < 0) {
close(filedes[0]);
close(filedes[1]);
CloseHandle(h[0]); CloseHandle(h[0]);
CloseHandle(h[1]); CloseHandle(h[1]);
return -1; return -1;
} }
close(filedes[0]); filedes[1] = _open_osfhandle((int)h[1], O_NOINHERIT);
filedes[0] = fd; if (filedes[0] < 0) {
fd = _open_osfhandle((int)h[1], O_NOINHERIT);
if (fd < 0) {
close(filedes[0]); close(filedes[0]);
close(filedes[1]);
CloseHandle(h[1]); CloseHandle(h[1]);
return -1; return -1;
} }
close(filedes[1]);
filedes[1] = fd;
return 0; return 0;
} }
@ -638,8 +617,8 @@ static int env_compare(const void *a, const void *b)
return strcasecmp(*ea, *eb); return strcasecmp(*ea, *eb);
} }
static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
int prepend_cmd) int prepend_cmd, int fhin, int fhout, int fherr)
{ {
STARTUPINFO si; STARTUPINFO si;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
@ -675,9 +654,9 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
memset(&si, 0, sizeof(si)); memset(&si, 0, sizeof(si));
si.cb = sizeof(si); si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES; si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = (HANDLE) _get_osfhandle(0); si.hStdInput = (HANDLE) _get_osfhandle(fhin);
si.hStdOutput = (HANDLE) _get_osfhandle(1); si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
si.hStdError = (HANDLE) _get_osfhandle(2); si.hStdError = (HANDLE) _get_osfhandle(fherr);
/* concatenate argv, quoting args as we go */ /* concatenate argv, quoting args as we go */
strbuf_init(&args, 0); strbuf_init(&args, 0);
@ -732,7 +711,14 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
return (pid_t)pi.hProcess; return (pid_t)pi.hProcess;
} }
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
int prepend_cmd)
{
return mingw_spawnve_fd(cmd, argv, env, prepend_cmd, 0, 1, 2);
}
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
int fhin, int fhout, int fherr)
{ {
pid_t pid; pid_t pid;
char **path = get_path_split(); char **path = get_path_split();
@ -754,13 +740,15 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env)
pid = -1; pid = -1;
} }
else { else {
pid = mingw_spawnve(iprog, argv, env, 1); pid = mingw_spawnve_fd(iprog, argv, env, 1,
fhin, fhout, fherr);
free(iprog); free(iprog);
} }
argv[0] = argv0; argv[0] = argv0;
} }
else else
pid = mingw_spawnve(prog, argv, env, 0); pid = mingw_spawnve_fd(prog, argv, env, 0,
fhin, fhout, fherr);
free(prog); free(prog);
} }
free_path_split(path); free_path_split(path);
@ -1338,8 +1326,22 @@ static const char *make_backslash_path(const char *path)
void mingw_open_html(const char *unixpath) void mingw_open_html(const char *unixpath)
{ {
const char *htmlpath = make_backslash_path(unixpath); const char *htmlpath = make_backslash_path(unixpath);
typedef HINSTANCE (WINAPI *T)(HWND, const char *,
const char *, const char *, const char *, INT);
T ShellExecute;
HMODULE shell32;
shell32 = LoadLibrary("shell32.dll");
if (!shell32)
die("cannot load shell32.dll");
ShellExecute = (T)GetProcAddress(shell32, "ShellExecuteA");
if (!ShellExecute)
die("cannot run browser");
printf("Launching default browser to display HTML ...\n"); printf("Launching default browser to display HTML ...\n");
ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0);
FreeLibrary(shell32);
} }
int link(const char *oldpath, const char *newpath) int link(const char *oldpath, const char *newpath)

View File

@ -209,18 +209,21 @@ int mingw_getpagesize(void);
* mingw_fstat() instead of fstat() on Windows. * mingw_fstat() instead of fstat() on Windows.
*/ */
#define off_t off64_t #define off_t off64_t
#define stat _stati64
#define lseek _lseeki64 #define lseek _lseeki64
#ifndef ALREADY_DECLARED_STAT_FUNCS
#define stat _stati64
int mingw_lstat(const char *file_name, struct stat *buf); int mingw_lstat(const char *file_name, struct stat *buf);
int mingw_fstat(int fd, struct stat *buf); int mingw_fstat(int fd, struct stat *buf);
#define fstat mingw_fstat #define fstat mingw_fstat
#define lstat mingw_lstat #define lstat mingw_lstat
#define _stati64(x,y) mingw_lstat(x,y) #define _stati64(x,y) mingw_lstat(x,y)
#endif
int mingw_utime(const char *file_name, const struct utimbuf *times); int mingw_utime(const char *file_name, const struct utimbuf *times);
#define utime mingw_utime #define utime mingw_utime
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env); pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
int fhin, int fhout, int fherr);
void mingw_execvp(const char *cmd, char *const *argv); void mingw_execvp(const char *cmd, char *const *argv);
#define execvp mingw_execvp #define execvp mingw_execvp
@ -307,3 +310,8 @@ struct mingw_dirent
#define readdir(x) mingw_readdir(x) #define readdir(x) mingw_readdir(x)
struct dirent *mingw_readdir(DIR *dir); struct dirent *mingw_readdir(DIR *dir);
#endif // !NO_MINGW_REPLACE_READDIR #endif // !NO_MINGW_REPLACE_READDIR
/*
* Used by Pthread API implementation for Windows
*/
extern int err_win_to_posix(DWORD winerr);

View File

@ -21,30 +21,22 @@ static __inline int strcasecmp (const char *s1, const char *s2)
} }
#undef ERROR #undef ERROR
#undef stat
#undef _stati64
#include "compat/mingw.h"
#undef stat
#define stat _stati64
#define _stat64(x,y) mingw_lstat(x,y)
/* /* Use mingw_lstat() instead of lstat()/stat() and mingw_fstat() instead
Even though _stati64 is normally just defined at _stat64 * of fstat(). We add the declaration of these functions here, suppressing
on Windows, we specify it here as a proper struct to avoid * the corresponding declarations in mingw.h, so that we can use the
compiler warnings about macro redefinition due to magic in * appropriate structure type (and function) names from the msvc headers.
mingw.h. Struct taken from ReactOS (GNU GPL license). */
*/ #define stat _stat64
struct _stati64 { int mingw_lstat(const char *file_name, struct stat *buf);
_dev_t st_dev; int mingw_fstat(int fd, struct stat *buf);
_ino_t st_ino; #define fstat mingw_fstat
unsigned short st_mode; #define lstat mingw_lstat
short st_nlink; #define _stat64(x,y) mingw_lstat(x,y)
short st_uid; #define ALREADY_DECLARED_STAT_FUNCS
short st_gid;
_dev_t st_rdev; #include "compat/mingw.h"
__int64 st_size;
time_t st_atime; #undef ALREADY_DECLARED_STAT_FUNCS
time_t st_mtime;
time_t st_ctime;
};
#endif #endif

110
compat/win32/pthread.c Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com>
*
* DISCLAMER: The implementation is Git-specific, it is subset of original
* Pthreads API, without lots of other features that Git doesn't use.
* Git also makes sure that the passed arguments are valid, so there's
* no need for double-checking.
*/
#include "../../git-compat-util.h"
#include "pthread.h"
#include <errno.h>
#include <limits.h>
static unsigned __stdcall win32_start_routine(void *arg)
{
pthread_t *thread = arg;
thread->arg = thread->start_routine(thread->arg);
return 0;
}
int pthread_create(pthread_t *thread, const void *unused,
void *(*start_routine)(void*), void *arg)
{
thread->arg = arg;
thread->start_routine = start_routine;
thread->handle = (HANDLE)
_beginthreadex(NULL, 0, win32_start_routine, thread, 0, NULL);
if (!thread->handle)
return errno;
else
return 0;
}
int win32_pthread_join(pthread_t *thread, void **value_ptr)
{
DWORD result = WaitForSingleObject(thread->handle, INFINITE);
switch (result) {
case WAIT_OBJECT_0:
if (value_ptr)
*value_ptr = thread->arg;
return 0;
case WAIT_ABANDONED:
return EINVAL;
default:
return err_win_to_posix(GetLastError());
}
}
int pthread_cond_init(pthread_cond_t *cond, const void *unused)
{
cond->waiters = 0;
cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
if (!cond->sema)
die("CreateSemaphore() failed");
return 0;
}
int pthread_cond_destroy(pthread_cond_t *cond)
{
CloseHandle(cond->sema);
cond->sema = NULL;
return 0;
}
int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex)
{
InterlockedIncrement(&cond->waiters);
/*
* Unlock external mutex and wait for signal.
* NOTE: we've held mutex locked long enough to increment
* waiters count above, so there's no problem with
* leaving mutex unlocked before we wait on semaphore.
*/
LeaveCriticalSection(mutex);
/* let's wait - ignore return value */
WaitForSingleObject(cond->sema, INFINITE);
/* we're done waiting, so make sure we decrease waiters count */
InterlockedDecrement(&cond->waiters);
/* lock external mutex again */
EnterCriticalSection(mutex);
return 0;
}
int pthread_cond_signal(pthread_cond_t *cond)
{
/*
* Access to waiters count is atomic; see "Interlocked Variable Access"
* http://msdn.microsoft.com/en-us/library/ms684122(VS.85).aspx
*/
int have_waiters = cond->waiters > 0;
/*
* Signal only when there are waiters
*/
if (have_waiters)
return ReleaseSemaphore(cond->sema, 1, NULL) ?
0 : err_win_to_posix(GetLastError());
else
return 0;
}

67
compat/win32/pthread.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Header used to adapt pthread-based POSIX code to Windows API threads.
*
* Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com>
*/
#ifndef PTHREAD_H
#define PTHREAD_H
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
/*
* Defines that adapt Windows API threads to pthreads API
*/
#define pthread_mutex_t CRITICAL_SECTION
#define pthread_mutex_init(a,b) InitializeCriticalSection((a))
#define pthread_mutex_destroy(a) DeleteCriticalSection((a))
#define pthread_mutex_lock EnterCriticalSection
#define pthread_mutex_unlock LeaveCriticalSection
/*
* Implement simple condition variable for Windows threads, based on ACE
* implementation.
*
* See original implementation: http://bit.ly/1vkDjo
* ACE homepage: http://www.cse.wustl.edu/~schmidt/ACE.html
* See also: http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
*/
typedef struct {
volatile LONG waiters;
HANDLE sema;
} pthread_cond_t;
extern int pthread_cond_init(pthread_cond_t *cond, const void *unused);
extern int pthread_cond_destroy(pthread_cond_t *cond);
extern int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex);
extern int pthread_cond_signal(pthread_cond_t *cond);
/*
* Simple thread creation implementation using pthread API
*/
typedef struct {
HANDLE handle;
void *(*start_routine)(void*);
void *arg;
} pthread_t;
extern int pthread_create(pthread_t *thread, const void *unused,
void *(*start_routine)(void*), void *arg);
/*
* To avoid the need of copying a struct, we use small macro wrapper to pass
* pointer to win32_pthread_join instead.
*/
#define pthread_join(a, b) win32_pthread_join(&(a), (b))
extern int win32_pthread_join(pthread_t *thread, void **value_ptr);
#endif /* PTHREAD_H */

View File

@ -8,12 +8,14 @@ static inline void close_pair(int fd[2])
close(fd[1]); close(fd[1]);
} }
#ifndef WIN32
static inline void dup_devnull(int to) static inline void dup_devnull(int to)
{ {
int fd = open("/dev/null", O_RDWR); int fd = open("/dev/null", O_RDWR);
dup2(fd, to); dup2(fd, to);
close(fd); close(fd);
} }
#endif
static const char **prepare_shell_cmd(const char **argv) static const char **prepare_shell_cmd(const char **argv)
{ {
@ -181,42 +183,30 @@ fail_pipe:
strerror(failed_errno = errno)); strerror(failed_errno = errno));
#else #else
{ {
int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ int fhin = 0, fhout = 1, fherr = 2;
const char **sargv = cmd->argv; const char **sargv = cmd->argv;
char **env = environ; char **env = environ;
if (cmd->no_stdin) { if (cmd->no_stdin)
s0 = dup(0); fhin = open("/dev/null", O_RDWR);
dup_devnull(0); else if (need_in)
} else if (need_in) { fhin = dup(fdin[0]);
s0 = dup(0); else if (cmd->in)
dup2(fdin[0], 0); fhin = dup(cmd->in);
} else if (cmd->in) {
s0 = dup(0);
dup2(cmd->in, 0);
}
if (cmd->no_stderr) { if (cmd->no_stderr)
s2 = dup(2); fherr = open("/dev/null", O_RDWR);
dup_devnull(2); else if (need_err)
} else if (need_err) { fherr = dup(fderr[1]);
s2 = dup(2);
dup2(fderr[1], 2);
}
if (cmd->no_stdout) { if (cmd->no_stdout)
s1 = dup(1); fhout = open("/dev/null", O_RDWR);
dup_devnull(1); else if (cmd->stdout_to_stderr)
} else if (cmd->stdout_to_stderr) { fhout = dup(fherr);
s1 = dup(1); else if (need_out)
dup2(2, 1); fhout = dup(fdout[1]);
} else if (need_out) { else if (cmd->out > 1)
s1 = dup(1); fhout = dup(cmd->out);
dup2(fdout[1], 1);
} else if (cmd->out > 1) {
s1 = dup(1);
dup2(cmd->out, 1);
}
if (cmd->dir) if (cmd->dir)
die("chdir in start_command() not implemented"); die("chdir in start_command() not implemented");
@ -229,7 +219,8 @@ fail_pipe:
cmd->argv = prepare_shell_cmd(cmd->argv); cmd->argv = prepare_shell_cmd(cmd->argv);
} }
cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env,
fhin, fhout, fherr);
failed_errno = errno; failed_errno = errno;
if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT)) if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
error("cannot spawn %s: %s", cmd->argv[0], strerror(errno)); error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
@ -240,12 +231,12 @@ fail_pipe:
free(cmd->argv); free(cmd->argv);
cmd->argv = sargv; cmd->argv = sargv;
if (s0 >= 0) if (fhin != 0)
dup2(s0, 0), close(s0); close(fhin);
if (s1 >= 0) if (fhout != 1)
dup2(s1, 1), close(s1); close(fhout);
if (s2 >= 0) if (fherr != 2)
dup2(s2, 2), close(s2); close(fherr);
} }
#endif #endif