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