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 #ifndef PTHREAD_C
32 #define PTHREAD_C
33
34 #include "pthread.h"
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <process.h>
39 #include <errno.h>
40 #include <limits.h>
41
42
43 #define PTHREAD_UNUSED_PARAM(x) ((void)(x))
44
die(const char * err,...)45 void die(const char *err, ...)
46 {
47 printf("%s", err);
48 exit(-1);
49 }
50
win32_start_routine(void * arg)51 static unsigned __stdcall win32_start_routine(void *arg)
52 {
53 pthread_t *thread = (pthread_t*)arg;
54 thread->arg = thread->start_routine(thread->arg);
55 return 0;
56 }
57
pthread_create(pthread_t * thread,const void * unused,void * (* start_routine)(void *),void * arg)58 int pthread_create(pthread_t *thread, const void *unused,
59 void *(*start_routine)(void*), void *arg)
60 {
61 PTHREAD_UNUSED_PARAM(unused);
62 thread->arg = arg;
63 thread->start_routine = start_routine;
64 thread->handle = (HANDLE)
65 _beginthreadex(NULL, 0, win32_start_routine, thread, 0, NULL);
66
67 if (!thread->handle)
68 return errno;
69 else
70 return 0;
71 }
72
win32_pthread_join(pthread_t * thread,void ** value_ptr)73 int win32_pthread_join(pthread_t *thread, void **value_ptr)
74 {
75 DWORD result = WaitForSingleObject(thread->handle, INFINITE);
76 switch (result) {
77 case WAIT_OBJECT_0:
78 if (value_ptr)
79 *value_ptr = thread->arg;
80 return 0;
81 case WAIT_ABANDONED:
82 return EINVAL;
83 default:
84 return GetLastError();
85 }
86 }
87
pthread_cond_init(pthread_cond_t * cond,const void * unused)88 int pthread_cond_init(pthread_cond_t *cond, const void *unused)
89 {
90 PTHREAD_UNUSED_PARAM(unused);
91 cond->waiters = 0;
92 cond->was_broadcast = 0;
93 InitializeCriticalSection(&cond->waiters_lock);
94
95 cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
96 if (!cond->sema)
97 die("CreateSemaphore() failed");
98
99 cond->continue_broadcast = CreateEvent(NULL, /* security */
100 FALSE, /* auto-reset */
101 FALSE, /* not signaled */
102 NULL); /* name */
103 if (!cond->continue_broadcast)
104 die("CreateEvent() failed");
105
106 return 0;
107 }
108
pthread_cond_destroy(pthread_cond_t * cond)109 int pthread_cond_destroy(pthread_cond_t *cond)
110 {
111 CloseHandle(cond->sema);
112 CloseHandle(cond->continue_broadcast);
113 DeleteCriticalSection(&cond->waiters_lock);
114 return 0;
115 }
116
pthread_cond_wait(pthread_cond_t * cond,CRITICAL_SECTION * mutex)117 int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex)
118 {
119 int last_waiter;
120
121 EnterCriticalSection(&cond->waiters_lock);
122 cond->waiters++;
123 LeaveCriticalSection(&cond->waiters_lock);
124
125 /*
126 * Unlock external mutex and wait for signal.
127 * NOTE: we've held mutex locked long enough to increment
128 * waiters count above, so there's no problem with
129 * leaving mutex unlocked before we wait on semaphore.
130 */
131 LeaveCriticalSection(mutex);
132
133 /* let's wait - ignore return value */
134 WaitForSingleObject(cond->sema, INFINITE);
135
136 /*
137 * Decrease waiters count. If we are the last waiter, then we must
138 * notify the broadcasting thread that it can continue.
139 * But if we continued due to cond_signal, we do not have to do that
140 * because the signaling thread knows that only one waiter continued.
141 */
142 EnterCriticalSection(&cond->waiters_lock);
143 cond->waiters--;
144 last_waiter = cond->was_broadcast && cond->waiters == 0;
145 LeaveCriticalSection(&cond->waiters_lock);
146
147 if (last_waiter) {
148 /*
149 * cond_broadcast was issued while mutex was held. This means
150 * that all other waiters have continued, but are contending
151 * for the mutex at the end of this function because the
152 * broadcasting thread did not leave cond_broadcast, yet.
153 * (This is so that it can be sure that each waiter has
154 * consumed exactly one slice of the semaphor.)
155 * The last waiter must tell the broadcasting thread that it
156 * can go on.
157 */
158 SetEvent(cond->continue_broadcast);
159 /*
160 * Now we go on to contend with all other waiters for
161 * the mutex. Auf in den Kampf!
162 */
163 }
164 /* lock external mutex again */
165 EnterCriticalSection(mutex);
166
167 return 0;
168 }
169
170 /*
171 * IMPORTANT: This implementation requires that pthread_cond_signal
172 * is called while the mutex is held that is used in the corresponding
173 * pthread_cond_wait calls!
174 */
pthread_cond_signal(pthread_cond_t * cond)175 int pthread_cond_signal(pthread_cond_t *cond)
176 {
177 int have_waiters;
178
179 EnterCriticalSection(&cond->waiters_lock);
180 have_waiters = cond->waiters > 0;
181 LeaveCriticalSection(&cond->waiters_lock);
182
183 /*
184 * Signal only when there are waiters
185 */
186 if (have_waiters)
187 return ReleaseSemaphore(cond->sema, 1, NULL) ?
188 0 : GetLastError();
189 else
190 return 0;
191 }
192
193 /*
194 * DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast
195 * is called while the mutex is held that is used in the corresponding
196 * pthread_cond_wait calls!
197 */
pthread_cond_broadcast(pthread_cond_t * cond)198 int pthread_cond_broadcast(pthread_cond_t *cond)
199 {
200 EnterCriticalSection(&cond->waiters_lock);
201
202 if ((cond->was_broadcast = cond->waiters > 0)) {
203 /* wake up all waiters */
204 ReleaseSemaphore(cond->sema, cond->waiters, NULL);
205 LeaveCriticalSection(&cond->waiters_lock);
206 /*
207 * At this point all waiters continue. Each one takes its
208 * slice of the semaphor. Now it's our turn to wait: Since
209 * the external mutex is held, no thread can leave cond_wait,
210 * yet. For this reason, we can be sure that no thread gets
211 * a chance to eat *more* than one slice. OTOH, it means
212 * that the last waiter must send us a wake-up.
213 */
214 WaitForSingleObject(cond->continue_broadcast, INFINITE);
215 /*
216 * Since the external mutex is held, no thread can enter
217 * cond_wait, and, hence, it is safe to reset this flag
218 * without cond->waiters_lock held.
219 */
220 cond->was_broadcast = 0;
221 } else {
222 LeaveCriticalSection(&cond->waiters_lock);
223 }
224 return 0;
225 }
226
227 #endif /* PTHREAD_C */
228