1/* 2 * Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com> 3 * 4 * DISCLAMER: The implementation is Git-specific, it is subset of original 5 * Pthreads API, without lots of other features that Git doesn't use. 6 * Git also makes sure that the passed arguments are valid, so there's 7 * no need for double-checking. 8 */ 9 10#include"../../git-compat-util.h" 11#include"pthread.h" 12 13#include <errno.h> 14#include <limits.h> 15 16static unsigned __stdcall win32_start_routine(void*arg) 17{ 18 pthread_t *thread = arg; 19 thread->arg = thread->start_routine(thread->arg); 20return0; 21} 22 23intpthread_create(pthread_t *thread,const void*unused, 24void*(*start_routine)(void*),void*arg) 25{ 26 thread->arg = arg; 27 thread->start_routine = start_routine; 28 thread->handle = (HANDLE) 29_beginthreadex(NULL,0, win32_start_routine, thread,0, NULL); 30 31if(!thread->handle) 32return errno; 33else 34return0; 35} 36 37intwin32_pthread_join(pthread_t *thread,void**value_ptr) 38{ 39 DWORD result =WaitForSingleObject(thread->handle, INFINITE); 40switch(result) { 41case WAIT_OBJECT_0: 42if(value_ptr) 43*value_ptr = thread->arg; 44return0; 45case WAIT_ABANDONED: 46return EINVAL; 47default: 48returnerr_win_to_posix(GetLastError()); 49} 50} 51 52intpthread_cond_init(pthread_cond_t *cond,const void*unused) 53{ 54 cond->waiters =0; 55 cond->was_broadcast =0; 56InitializeCriticalSection(&cond->waiters_lock); 57 58 cond->sema =CreateSemaphore(NULL,0, LONG_MAX, NULL); 59if(!cond->sema) 60die("CreateSemaphore() failed"); 61 62 cond->continue_broadcast =CreateEvent(NULL,/* security */ 63 FALSE,/* auto-reset */ 64 FALSE,/* not signaled */ 65 NULL);/* name */ 66if(!cond->continue_broadcast) 67die("CreateEvent() failed"); 68 69return0; 70} 71 72intpthread_cond_destroy(pthread_cond_t *cond) 73{ 74CloseHandle(cond->sema); 75CloseHandle(cond->continue_broadcast); 76DeleteCriticalSection(&cond->waiters_lock); 77return0; 78} 79 80intpthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) 81{ 82int last_waiter; 83 84EnterCriticalSection(&cond->waiters_lock); 85 cond->waiters++; 86LeaveCriticalSection(&cond->waiters_lock); 87 88/* 89 * Unlock external mutex and wait for signal. 90 * NOTE: we've held mutex locked long enough to increment 91 * waiters count above, so there's no problem with 92 * leaving mutex unlocked before we wait on semaphore. 93 */ 94LeaveCriticalSection(mutex); 95 96/* let's wait - ignore return value */ 97WaitForSingleObject(cond->sema, INFINITE); 98 99/* 100 * Decrease waiters count. If we are the last waiter, then we must 101 * notify the broadcasting thread that it can continue. 102 * But if we continued due to cond_signal, we do not have to do that 103 * because the signaling thread knows that only one waiter continued. 104 */ 105EnterCriticalSection(&cond->waiters_lock); 106 cond->waiters--; 107 last_waiter = cond->was_broadcast && cond->waiters ==0; 108LeaveCriticalSection(&cond->waiters_lock); 109 110if(last_waiter) { 111/* 112 * cond_broadcast was issued while mutex was held. This means 113 * that all other waiters have continued, but are contending 114 * for the mutex at the end of this function because the 115 * broadcasting thread did not leave cond_broadcast, yet. 116 * (This is so that it can be sure that each waiter has 117 * consumed exactly one slice of the semaphor.) 118 * The last waiter must tell the broadcasting thread that it 119 * can go on. 120 */ 121SetEvent(cond->continue_broadcast); 122/* 123 * Now we go on to contend with all other waiters for 124 * the mutex. Auf in den Kampf! 125 */ 126} 127/* lock external mutex again */ 128EnterCriticalSection(mutex); 129 130return0; 131} 132 133/* 134 * IMPORTANT: This implementation requires that pthread_cond_signal 135 * is called while the mutex is held that is used in the corresponding 136 * pthread_cond_wait calls! 137 */ 138intpthread_cond_signal(pthread_cond_t *cond) 139{ 140int have_waiters; 141 142EnterCriticalSection(&cond->waiters_lock); 143 have_waiters = cond->waiters >0; 144LeaveCriticalSection(&cond->waiters_lock); 145 146/* 147 * Signal only when there are waiters 148 */ 149if(have_waiters) 150returnReleaseSemaphore(cond->sema,1, NULL) ? 1510:err_win_to_posix(GetLastError()); 152else 153return0; 154} 155 156/* 157 * DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast 158 * is called while the mutex is held that is used in the corresponding 159 * pthread_cond_wait calls! 160 */ 161intpthread_cond_broadcast(pthread_cond_t *cond) 162{ 163EnterCriticalSection(&cond->waiters_lock); 164 165if((cond->was_broadcast = cond->waiters >0)) { 166/* wake up all waiters */ 167ReleaseSemaphore(cond->sema, cond->waiters, NULL); 168LeaveCriticalSection(&cond->waiters_lock); 169/* 170 * At this point all waiters continue. Each one takes its 171 * slice of the semaphor. Now it's our turn to wait: Since 172 * the external mutex is held, no thread can leave cond_wait, 173 * yet. For this reason, we can be sure that no thread gets 174 * a chance to eat *more* than one slice. OTOH, it means 175 * that the last waiter must send us a wake-up. 176 */ 177WaitForSingleObject(cond->continue_broadcast, INFINITE); 178/* 179 * Since the external mutex is held, no thread can enter 180 * cond_wait, and, hence, it is safe to reset this flag 181 * without cond->waiters_lock held. 182 */ 183 cond->was_broadcast =0; 184}else{ 185LeaveCriticalSection(&cond->waiters_lock); 186} 187return0; 188}