1 /*
2 * Code for simulating pthreads API on Windows. This is Git-specific,
3 * but it is enough for Numexpr needs too.
4 *
5 * Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 *
25 * DISCLAIMER: The implementation is Git-specific, it is subset of original
26 * Pthreads API, without lots of other features that Git doesn't use.
27 * Git also makes sure that the passed arguments are valid, so there's
28 * no need for double-checking.
29 */
30
31 #include "pthread.h"
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <process.h>
36 #include <errno.h>
37 #include <limits.h>
38
39
die(const char * err,...)40 void die(const char *err, ...)
41 {
42 printf("%s", err);
43 exit(-1);
44 }
45
win32_start_routine(void * arg)46 static unsigned __stdcall win32_start_routine(void *arg)
47 {
48 pthread_t *thread = (pthread_t*)arg;
49 thread->arg = thread->start_routine(thread->arg);
50 return 0;
51 }
52
pthread_create(pthread_t * thread,const void * unused,void * (* start_routine)(void *),void * arg)53 int pthread_create(pthread_t *thread, const void *unused,
54 void *(*start_routine)(void*), void *arg)
55 {
56 thread->arg = arg;
57 thread->start_routine = start_routine;
58 thread->handle = (HANDLE)
59 _beginthreadex(NULL, 0, win32_start_routine, thread, 0, NULL);
60
61 if (!thread->handle)
62 return errno;
63 else
64 return 0;
65 }
66
win32_pthread_join(pthread_t * thread,void ** value_ptr)67 int win32_pthread_join(pthread_t *thread, void **value_ptr)
68 {
69 DWORD result = WaitForSingleObject(thread->handle, INFINITE);
70 switch (result) {
71 case WAIT_OBJECT_0:
72 if (value_ptr)
73 *value_ptr = thread->arg;
74 return 0;
75 case WAIT_ABANDONED:
76 return EINVAL;
77 default:
78 return GetLastError();
79 }
80 }
81
pthread_cond_init(pthread_cond_t * cond,const void * unused)82 int pthread_cond_init(pthread_cond_t *cond, const void *unused)
83 {
84 cond->waiters = 0;
85 cond->was_broadcast = 0;
86 InitializeCriticalSection(&cond->waiters_lock);
87
88 cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
89 if (!cond->sema)
90 die("CreateSemaphore() failed");
91
92 cond->continue_broadcast = CreateEvent(NULL, /* security */
93 FALSE, /* auto-reset */
94 FALSE, /* not signaled */
95 NULL); /* name */
96 if (!cond->continue_broadcast)
97 die("CreateEvent() failed");
98
99 return 0;
100 }
101
pthread_cond_destroy(pthread_cond_t * cond)102 int pthread_cond_destroy(pthread_cond_t *cond)
103 {
104 CloseHandle(cond->sema);
105 CloseHandle(cond->continue_broadcast);
106 DeleteCriticalSection(&cond->waiters_lock);
107 return 0;
108 }
109
pthread_cond_wait(pthread_cond_t * cond,CRITICAL_SECTION * mutex)110 int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex)
111 {
112 int last_waiter;
113
114 EnterCriticalSection(&cond->waiters_lock);
115 cond->waiters++;
116 LeaveCriticalSection(&cond->waiters_lock);
117
118 /*
119 * Unlock external mutex and wait for signal.
120 * NOTE: we've held mutex locked long enough to increment
121 * waiters count above, so there's no problem with
122 * leaving mutex unlocked before we wait on semaphore.
123 */
124 LeaveCriticalSection(mutex);
125
126 /* let's wait - ignore return value */
127 WaitForSingleObject(cond->sema, INFINITE);
128
129 /*
130 * Decrease waiters count. If we are the last waiter, then we must
131 * notify the broadcasting thread that it can continue.
132 * But if we continued due to cond_signal, we do not have to do that
133 * because the signaling thread knows that only one waiter continued.
134 */
135 EnterCriticalSection(&cond->waiters_lock);
136 cond->waiters--;
137 last_waiter = cond->was_broadcast && cond->waiters == 0;
138 LeaveCriticalSection(&cond->waiters_lock);
139
140 if (last_waiter) {
141 /*
142 * cond_broadcast was issued while mutex was held. This means
143 * that all other waiters have continued, but are contending
144 * for the mutex at the end of this function because the
145 * broadcasting thread did not leave cond_broadcast, yet.
146 * (This is so that it can be sure that each waiter has
147 * consumed exactly one slice of the semaphore.)
148 * The last waiter must tell the broadcasting thread that it
149 * can go on.
150 */
151 SetEvent(cond->continue_broadcast);
152 /*
153 * Now we go on to contend with all other waiters for
154 * the mutex. Auf in den Kampf!
155 */
156 }
157 /* lock external mutex again */
158 EnterCriticalSection(mutex);
159
160 return 0;
161 }
162
163 /*
164 * IMPORTANT: This implementation requires that pthread_cond_signal
165 * is called while the mutex is held that is used in the corresponding
166 * pthread_cond_wait calls!
167 */
pthread_cond_signal(pthread_cond_t * cond)168 int pthread_cond_signal(pthread_cond_t *cond)
169 {
170 int have_waiters;
171
172 EnterCriticalSection(&cond->waiters_lock);
173 have_waiters = cond->waiters > 0;
174 LeaveCriticalSection(&cond->waiters_lock);
175
176 /*
177 * Signal only when there are waiters
178 */
179 if (have_waiters)
180 return ReleaseSemaphore(cond->sema, 1, NULL) ?
181 0 : GetLastError();
182 else
183 return 0;
184 }
185
186 /*
187 * DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast
188 * is called while the mutex is held that is used in the corresponding
189 * pthread_cond_wait calls!
190 */
pthread_cond_broadcast(pthread_cond_t * cond)191 int pthread_cond_broadcast(pthread_cond_t *cond)
192 {
193 EnterCriticalSection(&cond->waiters_lock);
194
195 if ((cond->was_broadcast = cond->waiters > 0)) {
196 /* wake up all waiters */
197 ReleaseSemaphore(cond->sema, cond->waiters, NULL);
198 LeaveCriticalSection(&cond->waiters_lock);
199 /*
200 * At this point all waiters continue. Each one takes its
201 * slice of the semaphore. Now it's our turn to wait: Since
202 * the external mutex is held, no thread can leave cond_wait,
203 * yet. For this reason, we can be sure that no thread gets
204 * a chance to eat *more* than one slice. OTOH, it means
205 * that the last waiter must send us a wake-up.
206 */
207 WaitForSingleObject(cond->continue_broadcast, INFINITE);
208 /*
209 * Since the external mutex is held, no thread can enter
210 * cond_wait, and, hence, it is safe to reset this flag
211 * without cond->waiters_lock held.
212 */
213 cond->was_broadcast = 0;
214 } else {
215 LeaveCriticalSection(&cond->waiters_lock);
216 }
217 return 0;
218 }
219