]>
Commit | Line | Data |
---|---|---|
44626dc7 AH |
1 | /* |
2 | * Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com> | |
3 | * | |
9517e6b8 | 4 | * DISCLAIMER: The implementation is Git-specific, it is subset of original |
44626dc7 AH |
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 | ||
16 | static unsigned __stdcall win32_start_routine(void *arg) | |
17 | { | |
18 | pthread_t *thread = arg; | |
912b2632 | 19 | thread->tid = GetCurrentThreadId(); |
44626dc7 AH |
20 | thread->arg = thread->start_routine(thread->arg); |
21 | return 0; | |
22 | } | |
23 | ||
24 | int 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 | ||
38 | int 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 | ||
912b2632 JS |
53 | pthread_t pthread_self(void) |
54 | { | |
9c3b051f | 55 | pthread_t t = { NULL }; |
912b2632 JS |
56 | t.tid = GetCurrentThreadId(); |
57 | return t; | |
58 | } | |
59 | ||
44626dc7 AH |
60 | int pthread_cond_init(pthread_cond_t *cond, const void *unused) |
61 | { | |
62 | cond->waiters = 0; | |
947c3464 JS |
63 | cond->was_broadcast = 0; |
64 | InitializeCriticalSection(&cond->waiters_lock); | |
44626dc7 AH |
65 | |
66 | cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL); | |
67 | if (!cond->sema) | |
68 | die("CreateSemaphore() failed"); | |
947c3464 JS |
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 | ||
44626dc7 AH |
77 | return 0; |
78 | } | |
79 | ||
80 | int pthread_cond_destroy(pthread_cond_t *cond) | |
81 | { | |
82 | CloseHandle(cond->sema); | |
947c3464 JS |
83 | CloseHandle(cond->continue_broadcast); |
84 | DeleteCriticalSection(&cond->waiters_lock); | |
44626dc7 AH |
85 | return 0; |
86 | } | |
87 | ||
88 | int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex) | |
89 | { | |
947c3464 JS |
90 | int last_waiter; |
91 | ||
92 | EnterCriticalSection(&cond->waiters_lock); | |
93 | cond->waiters++; | |
94 | LeaveCriticalSection(&cond->waiters_lock); | |
44626dc7 AH |
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 | ||
947c3464 JS |
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 | } | |
44626dc7 AH |
135 | /* lock external mutex again */ |
136 | EnterCriticalSection(mutex); | |
137 | ||
138 | return 0; | |
139 | } | |
140 | ||
947c3464 JS |
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 | */ | |
44626dc7 AH |
146 | int pthread_cond_signal(pthread_cond_t *cond) |
147 | { | |
947c3464 JS |
148 | int have_waiters; |
149 | ||
150 | EnterCriticalSection(&cond->waiters_lock); | |
151 | have_waiters = cond->waiters > 0; | |
152 | LeaveCriticalSection(&cond->waiters_lock); | |
44626dc7 AH |
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 | } | |
947c3464 JS |
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 | */ | |
169 | int 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 | } |