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