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); 21 return 0; 22} 23 24int pthread_create(pthread_t *thread, const void *unused, 25 void *(*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 32 if (!thread->handle) 33 return errno; 34 else 35 return 0; 36} 37 38int win32_pthread_join(pthread_t *thread, void **value_ptr) 39{ 40 DWORD result = WaitForSingleObject(thread->handle, INFINITE); 41 switch (result) { 42 case WAIT_OBJECT_0: 43 if (value_ptr) 44 *value_ptr = thread->arg; 45 return 0; 46 case WAIT_ABANDONED: 47 return EINVAL; 48 default: 49 return err_win_to_posix(GetLastError()); 50 } 51} 52 53pthread_t pthread_self(void) 54{ 55 pthread_t t = { NULL }; 56 t.tid = GetCurrentThreadId(); 57 return t; 58} 59 60int pthread_cond_init(pthread_cond_t *cond, const void *unused) 61{ 62 cond->waiters = 0; 63 cond->was_broadcast = 0; 64 InitializeCriticalSection(&cond->waiters_lock); 65 66 cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL); 67 if (!cond->sema) 68 die("CreateSemaphore() failed"); 69 70 cond->continue_broadcast = CreateEvent(NULL, /* security */ 71 FALSE, /* auto-reset */ 72 FALSE, /* not signaled */ 73 NULL); /* name */ 74 if (!cond->continue_broadcast) 75 die("CreateEvent() failed"); 76 77 return 0; 78} 79 80int pthread_cond_destroy(pthread_cond_t *cond) 81{ 82 CloseHandle(cond->sema); 83 CloseHandle(cond->continue_broadcast); 84 DeleteCriticalSection(&cond->waiters_lock); 85 return 0; 86} 87 88int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) 89{ 90 int last_waiter; 91 92 EnterCriticalSection(&cond->waiters_lock); 93 cond->waiters++; 94 LeaveCriticalSection(&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 */ 102 LeaveCriticalSection(mutex); 103 104 /* let's wait - ignore return value */ 105 WaitForSingleObject(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 */ 113 EnterCriticalSection(&cond->waiters_lock); 114 cond->waiters--; 115 last_waiter = cond->was_broadcast && cond->waiters == 0; 116 LeaveCriticalSection(&cond->waiters_lock); 117 118 if (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 */ 129 SetEvent(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 */ 136 EnterCriticalSection(mutex); 137 138 return 0; 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 */ 146int pthread_cond_signal(pthread_cond_t *cond) 147{ 148 int have_waiters; 149 150 EnterCriticalSection(&cond->waiters_lock); 151 have_waiters = cond->waiters > 0; 152 LeaveCriticalSection(&cond->waiters_lock); 153 154 /* 155 * Signal only when there are waiters 156 */ 157 if (have_waiters) 158 return ReleaseSemaphore(cond->sema, 1, NULL) ? 159 0 : err_win_to_posix(GetLastError()); 160 else 161 return 0; 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 */ 169int pthread_cond_broadcast(pthread_cond_t *cond) 170{ 171 EnterCriticalSection(&cond->waiters_lock); 172 173 if ((cond->was_broadcast = cond->waiters > 0)) { 174 /* wake up all waiters */ 175 ReleaseSemaphore(cond->sema, cond->waiters, NULL); 176 LeaveCriticalSection(&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 */ 185 WaitForSingleObject(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 { 193 LeaveCriticalSection(&cond->waiters_lock); 194 } 195 return 0; 196}