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:
commit
3cd02df46a
15
Makefile
15
Makefile
@ -478,6 +478,7 @@ LIB_H += commit.h
|
||||
LIB_H += compat/bswap.h
|
||||
LIB_H += compat/cygwin.h
|
||||
LIB_H += compat/mingw.h
|
||||
LIB_H += compat/win32/pthread.h
|
||||
LIB_H += csum-file.h
|
||||
LIB_H += decorate.h
|
||||
LIB_H += delta.h
|
||||
@ -995,15 +996,16 @@ ifeq ($(uname_S),Windows)
|
||||
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
|
||||
NO_REGEX = YesPlease
|
||||
NO_CURL = YesPlease
|
||||
NO_PTHREADS = YesPlease
|
||||
NO_PYTHON = YesPlease
|
||||
BLK_SHA1 = YesPlease
|
||||
THREADED_DELTA_SEARCH = YesPlease
|
||||
|
||||
CC = compat/vcbuild/scripts/clink.pl
|
||||
AR = compat/vcbuild/scripts/lib.pl
|
||||
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
|
||||
COMPAT_OBJS = compat/msvc.o compat/fnmatch/fnmatch.o compat/winansi.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_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 -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
|
||||
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
|
||||
EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib
|
||||
lib =
|
||||
@ -1045,10 +1047,13 @@ ifneq (,$(findstring MINGW,$(uname_S)))
|
||||
UNRELIABLE_FSTAT = UnfortunatelyYes
|
||||
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
|
||||
NO_REGEX = YesPlease
|
||||
NO_PYTHON = YesPlease
|
||||
BLK_SHA1 = YesPlease
|
||||
THREADED_DELTA_SEARCH = YesPlease
|
||||
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch
|
||||
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
|
||||
X = .exe
|
||||
ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
|
||||
@ -1058,10 +1063,8 @@ ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
|
||||
EXTLIBS += /mingw/lib/libz.a
|
||||
NO_R_TO_GCC_LINKER = YesPlease
|
||||
INTERNAL_QSORT = YesPlease
|
||||
THREADED_DELTA_SEARCH = YesPlease
|
||||
else
|
||||
NO_CURL = YesPlease
|
||||
NO_PTHREADS = YesPlease
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -1256,15 +1256,15 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
|
||||
|
||||
#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_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_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_unlock() pthread_mutex_unlock(&progress_mutex)
|
||||
|
||||
@ -1591,7 +1591,26 @@ struct thread_params {
|
||||
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)
|
||||
{
|
||||
@ -1630,10 +1649,13 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
|
||||
struct thread_params *p;
|
||||
int i, ret, active_threads = 0;
|
||||
|
||||
init_threaded_search();
|
||||
|
||||
if (!delta_search_threads) /* --threads=0 means autodetect */
|
||||
delta_search_threads = online_cpus();
|
||||
if (delta_search_threads <= 1) {
|
||||
find_deltas(list, &list_size, window, depth, processed);
|
||||
cleanup_threaded_search();
|
||||
return;
|
||||
}
|
||||
if (progress > pack_to_stdout)
|
||||
@ -1748,6 +1770,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
|
||||
active_threads--;
|
||||
}
|
||||
}
|
||||
cleanup_threaded_search();
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
116
compat/mingw.c
116
compat/mingw.c
@ -3,9 +3,7 @@
|
||||
#include <conio.h>
|
||||
#include "../strbuf.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
static int err_win_to_posix(DWORD winerr)
|
||||
int err_win_to_posix(DWORD winerr)
|
||||
{
|
||||
int error = ENOSYS;
|
||||
switch(winerr) {
|
||||
@ -142,12 +140,20 @@ int mingw_open (const char *filename, int oflags, ...)
|
||||
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;
|
||||
winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
|
||||
winTime /= 10000000; /* Nano to seconds resolution */
|
||||
return (time_t)winTime;
|
||||
/* Windows to Unix Epoch conversion */
|
||||
return winTime - 116444736000000000LL;
|
||||
}
|
||||
|
||||
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.
|
||||
@ -283,64 +289,37 @@ int mkstemp(char *template)
|
||||
|
||||
int gettimeofday(struct timeval *tv, void *tz)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
struct tm tm;
|
||||
GetSystemTime(&st);
|
||||
tm.tm_year = st.wYear-1900;
|
||||
tm.tm_mon = st.wMonth-1;
|
||||
tm.tm_mday = st.wDay;
|
||||
tm.tm_hour = st.wHour;
|
||||
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;
|
||||
FILETIME ft;
|
||||
long long hnsec;
|
||||
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
hnsec = filetime_to_hnsec(&ft);
|
||||
tv->tv_sec = hnsec / 10000000;
|
||||
tv->tv_usec = (hnsec % 10000000) / 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pipe(int filedes[2])
|
||||
{
|
||||
int fd;
|
||||
HANDLE h[2], parent;
|
||||
HANDLE h[2];
|
||||
|
||||
if (_pipe(filedes, 8192, 0) < 0)
|
||||
return -1;
|
||||
|
||||
parent = GetCurrentProcess();
|
||||
|
||||
if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[0]),
|
||||
parent, &h[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
close(filedes[0]);
|
||||
close(filedes[1]);
|
||||
/* this creates non-inheritable handles */
|
||||
if (!CreatePipe(&h[0], &h[1], NULL, 8192)) {
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[1]),
|
||||
parent, &h[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) {
|
||||
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]);
|
||||
filedes[0] = _open_osfhandle((int)h[0], O_NOINHERIT);
|
||||
if (filedes[0] < 0) {
|
||||
CloseHandle(h[0]);
|
||||
CloseHandle(h[1]);
|
||||
return -1;
|
||||
}
|
||||
filedes[1] = _open_osfhandle((int)h[1], O_NOINHERIT);
|
||||
if (filedes[0] < 0) {
|
||||
close(filedes[0]);
|
||||
filedes[0] = fd;
|
||||
fd = _open_osfhandle((int)h[1], O_NOINHERIT);
|
||||
if (fd < 0) {
|
||||
close(filedes[0]);
|
||||
close(filedes[1]);
|
||||
CloseHandle(h[1]);
|
||||
return -1;
|
||||
}
|
||||
close(filedes[1]);
|
||||
filedes[1] = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -638,8 +617,8 @@ static int env_compare(const void *a, const void *b)
|
||||
return strcasecmp(*ea, *eb);
|
||||
}
|
||||
|
||||
static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
|
||||
int prepend_cmd)
|
||||
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
|
||||
int prepend_cmd, int fhin, int fhout, int fherr)
|
||||
{
|
||||
STARTUPINFO si;
|
||||
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));
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.hStdInput = (HANDLE) _get_osfhandle(0);
|
||||
si.hStdOutput = (HANDLE) _get_osfhandle(1);
|
||||
si.hStdError = (HANDLE) _get_osfhandle(2);
|
||||
si.hStdInput = (HANDLE) _get_osfhandle(fhin);
|
||||
si.hStdOutput = (HANDLE) _get_osfhandle(fhout);
|
||||
si.hStdError = (HANDLE) _get_osfhandle(fherr);
|
||||
|
||||
/* concatenate argv, quoting args as we go */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
char **path = get_path_split();
|
||||
@ -754,13 +740,15 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env)
|
||||
pid = -1;
|
||||
}
|
||||
else {
|
||||
pid = mingw_spawnve(iprog, argv, env, 1);
|
||||
pid = mingw_spawnve_fd(iprog, argv, env, 1,
|
||||
fhin, fhout, fherr);
|
||||
free(iprog);
|
||||
}
|
||||
argv[0] = argv0;
|
||||
}
|
||||
else
|
||||
pid = mingw_spawnve(prog, argv, env, 0);
|
||||
pid = mingw_spawnve_fd(prog, argv, env, 0,
|
||||
fhin, fhout, fherr);
|
||||
free(prog);
|
||||
}
|
||||
free_path_split(path);
|
||||
@ -1338,8 +1326,22 @@ static const char *make_backslash_path(const char *path)
|
||||
void mingw_open_html(const char *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");
|
||||
ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0);
|
||||
|
||||
FreeLibrary(shell32);
|
||||
}
|
||||
|
||||
int link(const char *oldpath, const char *newpath)
|
||||
|
@ -209,18 +209,21 @@ int mingw_getpagesize(void);
|
||||
* mingw_fstat() instead of fstat() on Windows.
|
||||
*/
|
||||
#define off_t off64_t
|
||||
#define stat _stati64
|
||||
#define lseek _lseeki64
|
||||
#ifndef ALREADY_DECLARED_STAT_FUNCS
|
||||
#define stat _stati64
|
||||
int mingw_lstat(const char *file_name, struct stat *buf);
|
||||
int mingw_fstat(int fd, struct stat *buf);
|
||||
#define fstat mingw_fstat
|
||||
#define lstat mingw_lstat
|
||||
#define _stati64(x,y) mingw_lstat(x,y)
|
||||
#endif
|
||||
|
||||
int mingw_utime(const char *file_name, const struct utimbuf *times);
|
||||
#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);
|
||||
#define execvp mingw_execvp
|
||||
|
||||
@ -307,3 +310,8 @@ struct mingw_dirent
|
||||
#define readdir(x) mingw_readdir(x)
|
||||
struct dirent *mingw_readdir(DIR *dir);
|
||||
#endif // !NO_MINGW_REPLACE_READDIR
|
||||
|
||||
/*
|
||||
* Used by Pthread API implementation for Windows
|
||||
*/
|
||||
extern int err_win_to_posix(DWORD winerr);
|
||||
|
@ -21,30 +21,22 @@ static __inline int strcasecmp (const char *s1, const char *s2)
|
||||
}
|
||||
|
||||
#undef ERROR
|
||||
#undef stat
|
||||
#undef _stati64
|
||||
#include "compat/mingw.h"
|
||||
#undef stat
|
||||
#define stat _stati64
|
||||
#define _stat64(x,y) mingw_lstat(x,y)
|
||||
|
||||
/*
|
||||
Even though _stati64 is normally just defined at _stat64
|
||||
on Windows, we specify it here as a proper struct to avoid
|
||||
compiler warnings about macro redefinition due to magic in
|
||||
mingw.h. Struct taken from ReactOS (GNU GPL license).
|
||||
*/
|
||||
struct _stati64 {
|
||||
_dev_t st_dev;
|
||||
_ino_t st_ino;
|
||||
unsigned short st_mode;
|
||||
short st_nlink;
|
||||
short st_uid;
|
||||
short st_gid;
|
||||
_dev_t st_rdev;
|
||||
__int64 st_size;
|
||||
time_t st_atime;
|
||||
time_t st_mtime;
|
||||
time_t st_ctime;
|
||||
};
|
||||
/* Use mingw_lstat() instead of lstat()/stat() and mingw_fstat() instead
|
||||
* of fstat(). We add the declaration of these functions here, suppressing
|
||||
* the corresponding declarations in mingw.h, so that we can use the
|
||||
* appropriate structure type (and function) names from the msvc headers.
|
||||
*/
|
||||
#define stat _stat64
|
||||
int mingw_lstat(const char *file_name, struct stat *buf);
|
||||
int mingw_fstat(int fd, struct stat *buf);
|
||||
#define fstat mingw_fstat
|
||||
#define lstat mingw_lstat
|
||||
#define _stat64(x,y) mingw_lstat(x,y)
|
||||
#define ALREADY_DECLARED_STAT_FUNCS
|
||||
|
||||
#include "compat/mingw.h"
|
||||
|
||||
#undef ALREADY_DECLARED_STAT_FUNCS
|
||||
|
||||
#endif
|
||||
|
110
compat/win32/pthread.c
Normal file
110
compat/win32/pthread.c
Normal 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
67
compat/win32/pthread.h
Normal 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 */
|
@ -8,12 +8,14 @@ static inline void close_pair(int fd[2])
|
||||
close(fd[1]);
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
static inline void dup_devnull(int to)
|
||||
{
|
||||
int fd = open("/dev/null", O_RDWR);
|
||||
dup2(fd, to);
|
||||
close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char **prepare_shell_cmd(const char **argv)
|
||||
{
|
||||
@ -181,42 +183,30 @@ fail_pipe:
|
||||
strerror(failed_errno = errno));
|
||||
#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;
|
||||
char **env = environ;
|
||||
|
||||
if (cmd->no_stdin) {
|
||||
s0 = dup(0);
|
||||
dup_devnull(0);
|
||||
} else if (need_in) {
|
||||
s0 = dup(0);
|
||||
dup2(fdin[0], 0);
|
||||
} else if (cmd->in) {
|
||||
s0 = dup(0);
|
||||
dup2(cmd->in, 0);
|
||||
}
|
||||
if (cmd->no_stdin)
|
||||
fhin = open("/dev/null", O_RDWR);
|
||||
else if (need_in)
|
||||
fhin = dup(fdin[0]);
|
||||
else if (cmd->in)
|
||||
fhin = dup(cmd->in);
|
||||
|
||||
if (cmd->no_stderr) {
|
||||
s2 = dup(2);
|
||||
dup_devnull(2);
|
||||
} else if (need_err) {
|
||||
s2 = dup(2);
|
||||
dup2(fderr[1], 2);
|
||||
}
|
||||
if (cmd->no_stderr)
|
||||
fherr = open("/dev/null", O_RDWR);
|
||||
else if (need_err)
|
||||
fherr = dup(fderr[1]);
|
||||
|
||||
if (cmd->no_stdout) {
|
||||
s1 = dup(1);
|
||||
dup_devnull(1);
|
||||
} else if (cmd->stdout_to_stderr) {
|
||||
s1 = dup(1);
|
||||
dup2(2, 1);
|
||||
} else if (need_out) {
|
||||
s1 = dup(1);
|
||||
dup2(fdout[1], 1);
|
||||
} else if (cmd->out > 1) {
|
||||
s1 = dup(1);
|
||||
dup2(cmd->out, 1);
|
||||
}
|
||||
if (cmd->no_stdout)
|
||||
fhout = open("/dev/null", O_RDWR);
|
||||
else if (cmd->stdout_to_stderr)
|
||||
fhout = dup(fherr);
|
||||
else if (need_out)
|
||||
fhout = dup(fdout[1]);
|
||||
else if (cmd->out > 1)
|
||||
fhout = dup(cmd->out);
|
||||
|
||||
if (cmd->dir)
|
||||
die("chdir in start_command() not implemented");
|
||||
@ -229,7 +219,8 @@ fail_pipe:
|
||||
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;
|
||||
if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
|
||||
error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
|
||||
@ -240,12 +231,12 @@ fail_pipe:
|
||||
free(cmd->argv);
|
||||
|
||||
cmd->argv = sargv;
|
||||
if (s0 >= 0)
|
||||
dup2(s0, 0), close(s0);
|
||||
if (s1 >= 0)
|
||||
dup2(s1, 1), close(s1);
|
||||
if (s2 >= 0)
|
||||
dup2(s2, 2), close(s2);
|
||||
if (fhin != 0)
|
||||
close(fhin);
|
||||
if (fhout != 1)
|
||||
close(fhout);
|
||||
if (fherr != 2)
|
||||
close(fherr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user