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