Browse Source
This patch implements native to Windows subset of pthreads API used by Git. It allows to remove Pthreads for Win32 dependency for MSVC, msysgit and Cygwin. [J6t: If the MinGW build was built as part of the msysgit build environment, then threading was already enabled because the pthreads-win32 package is available in msysgit. With this patch, we can now enable threaded code unconditionally.] Signed-off-by: Andrzej K. Haczewski <ahaczewski@gmail.com> Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
Andrzej K. Haczewski
15 years ago
committed by
Junio C Hamano
6 changed files with 217 additions and 11 deletions
@ -0,0 +1,110 @@
@@ -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; |
||||
} |
@ -0,0 +1,67 @@
@@ -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 */ |
Loading…
Reference in new issue