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->arg = thread->start_routine(thread->arg); 20 return 0; 21} 22 23int pthread_create(pthread_t *thread, const void *unused, 24 void *(*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 31 if (!thread->handle) 32 return errno; 33 else 34 return 0; 35} 36 37int win32_pthread_join(pthread_t *thread, void **value_ptr) 38{ 39 DWORD result = WaitForSingleObject(thread->handle, INFINITE); 40 switch (result) { 41 case WAIT_OBJECT_0: 42 if (value_ptr) 43 *value_ptr = thread->arg; 44 return 0; 45 case WAIT_ABANDONED: 46 return EINVAL; 47 default: 48 return err_win_to_posix(GetLastError()); 49 } 50} 51 52int pthread_cond_init(pthread_cond_t *cond, const void *unused) 53{ 54 cond->waiters = 0; 55 cond->was_broadcast = 0; 56 InitializeCriticalSection(&cond->waiters_lock); 57 58 cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL); 59 if (!cond->sema) 60 die("CreateSemaphore() failed"); 61 62 cond->continue_broadcast = CreateEvent(NULL, /* security */ 63 FALSE, /* auto-reset */ 64 FALSE, /* not signaled */ 65 NULL); /* name */ 66 if (!cond->continue_broadcast) 67 die("CreateEvent() failed"); 68 69 return 0; 70} 71 72int pthread_cond_destroy(pthread_cond_t *cond) 73{ 74 CloseHandle(cond->sema); 75 CloseHandle(cond->continue_broadcast); 76 DeleteCriticalSection(&cond->waiters_lock); 77 return 0; 78} 79 80int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) 81{ 82 int last_waiter; 83 84 EnterCriticalSection(&cond->waiters_lock); 85 cond->waiters++; 86 LeaveCriticalSection(&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 */ 94 LeaveCriticalSection(mutex); 95 96 /* let's wait - ignore return value */ 97 WaitForSingleObject(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 */ 105 EnterCriticalSection(&cond->waiters_lock); 106 cond->waiters--; 107 last_waiter = cond->was_broadcast && cond->waiters == 0; 108 LeaveCriticalSection(&cond->waiters_lock); 109 110 if (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 */ 121 SetEvent(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 */ 128 EnterCriticalSection(mutex); 129 130 return 0; 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 */ 138int pthread_cond_signal(pthread_cond_t *cond) 139{ 140 int have_waiters; 141 142 EnterCriticalSection(&cond->waiters_lock); 143 have_waiters = cond->waiters > 0; 144 LeaveCriticalSection(&cond->waiters_lock); 145 146 /* 147 * Signal only when there are waiters 148 */ 149 if (have_waiters) 150 return ReleaseSemaphore(cond->sema, 1, NULL) ? 151 0 : err_win_to_posix(GetLastError()); 152 else 153 return 0; 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 */ 161int pthread_cond_broadcast(pthread_cond_t *cond) 162{ 163 EnterCriticalSection(&cond->waiters_lock); 164 165 if ((cond->was_broadcast = cond->waiters > 0)) { 166 /* wake up all waiters */ 167 ReleaseSemaphore(cond->sema, cond->waiters, NULL); 168 LeaveCriticalSection(&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 */ 177 WaitForSingleObject(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 { 185 LeaveCriticalSection(&cond->waiters_lock); 186 } 187 return 0; 188}