| /* | 
 |  * Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com> | 
 |  * | 
 |  * DISCLAIMER: 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->tid = GetCurrentThreadId(); | 
 | 	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()); | 
 | 	} | 
 | } | 
 |  | 
 | pthread_t pthread_self(void) | 
 | { | 
 | 	pthread_t t = { 0 }; | 
 | 	t.tid = GetCurrentThreadId(); | 
 | 	return t; | 
 | } | 
 |  | 
 | int pthread_cond_init(pthread_cond_t *cond, const void *unused) | 
 | { | 
 | 	cond->waiters = 0; | 
 | 	cond->was_broadcast = 0; | 
 | 	InitializeCriticalSection(&cond->waiters_lock); | 
 |  | 
 | 	cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL); | 
 | 	if (!cond->sema) | 
 | 		die("CreateSemaphore() failed"); | 
 |  | 
 | 	cond->continue_broadcast = CreateEvent(NULL,	/* security */ | 
 | 				FALSE,			/* auto-reset */ | 
 | 				FALSE,			/* not signaled */ | 
 | 				NULL);			/* name */ | 
 | 	if (!cond->continue_broadcast) | 
 | 		die("CreateEvent() failed"); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int pthread_cond_destroy(pthread_cond_t *cond) | 
 | { | 
 | 	CloseHandle(cond->sema); | 
 | 	CloseHandle(cond->continue_broadcast); | 
 | 	DeleteCriticalSection(&cond->waiters_lock); | 
 | 	return 0; | 
 | } | 
 |  | 
 | int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) | 
 | { | 
 | 	int last_waiter; | 
 |  | 
 | 	EnterCriticalSection(&cond->waiters_lock); | 
 | 	cond->waiters++; | 
 | 	LeaveCriticalSection(&cond->waiters_lock); | 
 |  | 
 | 	/* | 
 | 	 * 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); | 
 |  | 
 | 	/* | 
 | 	 * Decrease waiters count. If we are the last waiter, then we must | 
 | 	 * notify the broadcasting thread that it can continue. | 
 | 	 * But if we continued due to cond_signal, we do not have to do that | 
 | 	 * because the signaling thread knows that only one waiter continued. | 
 | 	 */ | 
 | 	EnterCriticalSection(&cond->waiters_lock); | 
 | 	cond->waiters--; | 
 | 	last_waiter = cond->was_broadcast && cond->waiters == 0; | 
 | 	LeaveCriticalSection(&cond->waiters_lock); | 
 |  | 
 | 	if (last_waiter) { | 
 | 		/* | 
 | 		 * cond_broadcast was issued while mutex was held. This means | 
 | 		 * that all other waiters have continued, but are contending | 
 | 		 * for the mutex at the end of this function because the | 
 | 		 * broadcasting thread did not leave cond_broadcast, yet. | 
 | 		 * (This is so that it can be sure that each waiter has | 
 | 		 * consumed exactly one slice of the semaphor.) | 
 | 		 * The last waiter must tell the broadcasting thread that it | 
 | 		 * can go on. | 
 | 		 */ | 
 | 		SetEvent(cond->continue_broadcast); | 
 | 		/* | 
 | 		 * Now we go on to contend with all other waiters for | 
 | 		 * the mutex. Auf in den Kampf! | 
 | 		 */ | 
 | 	} | 
 | 	/* lock external mutex again */ | 
 | 	EnterCriticalSection(mutex); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* | 
 |  * IMPORTANT: This implementation requires that pthread_cond_signal | 
 |  * is called while the mutex is held that is used in the corresponding | 
 |  * pthread_cond_wait calls! | 
 |  */ | 
 | int pthread_cond_signal(pthread_cond_t *cond) | 
 | { | 
 | 	int have_waiters; | 
 |  | 
 | 	EnterCriticalSection(&cond->waiters_lock); | 
 | 	have_waiters = cond->waiters > 0; | 
 | 	LeaveCriticalSection(&cond->waiters_lock); | 
 |  | 
 | 	/* | 
 | 	 * Signal only when there are waiters | 
 | 	 */ | 
 | 	if (have_waiters) | 
 | 		return ReleaseSemaphore(cond->sema, 1, NULL) ? | 
 | 			0 : err_win_to_posix(GetLastError()); | 
 | 	else | 
 | 		return 0; | 
 | } | 
 |  | 
 | /* | 
 |  * DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast | 
 |  * is called while the mutex is held that is used in the corresponding | 
 |  * pthread_cond_wait calls! | 
 |  */ | 
 | int pthread_cond_broadcast(pthread_cond_t *cond) | 
 | { | 
 | 	EnterCriticalSection(&cond->waiters_lock); | 
 |  | 
 | 	if ((cond->was_broadcast = cond->waiters > 0)) { | 
 | 		/* wake up all waiters */ | 
 | 		ReleaseSemaphore(cond->sema, cond->waiters, NULL); | 
 | 		LeaveCriticalSection(&cond->waiters_lock); | 
 | 		/* | 
 | 		 * At this point all waiters continue. Each one takes its | 
 | 		 * slice of the semaphor. Now it's our turn to wait: Since | 
 | 		 * the external mutex is held, no thread can leave cond_wait, | 
 | 		 * yet. For this reason, we can be sure that no thread gets | 
 | 		 * a chance to eat *more* than one slice. OTOH, it means | 
 | 		 * that the last waiter must send us a wake-up. | 
 | 		 */ | 
 | 		WaitForSingleObject(cond->continue_broadcast, INFINITE); | 
 | 		/* | 
 | 		 * Since the external mutex is held, no thread can enter | 
 | 		 * cond_wait, and, hence, it is safe to reset this flag | 
 | 		 * without cond->waiters_lock held. | 
 | 		 */ | 
 | 		cond->was_broadcast = 0; | 
 | 	} else { | 
 | 		LeaveCriticalSection(&cond->waiters_lock); | 
 | 	} | 
 | 	return 0; | 
 | } |