aboutsummaryrefslogtreecommitdiffstats
path: root/src/systhread.c
diff options
context:
space:
mode:
authorEli Zaretskii2013-08-30 17:19:16 +0300
committerEli Zaretskii2013-08-30 17:19:16 +0300
commitdbe17fefccbff010bbbf6c4d0dccc7b2f3a5e201 (patch)
treed6844a441dc78f6a18610e9f88d82e0c8f12f6db /src/systhread.c
parent0e82377a2d9d8f815d2ef4ec09dc914f37fc87ac (diff)
downloademacs-dbe17fefccbff010bbbf6c4d0dccc7b2f3a5e201.tar.gz
emacs-dbe17fefccbff010bbbf6c4d0dccc7b2f3a5e201.zip
Enable thread support in the MS-Windows build.
src/systhread.h (w32thread_critsect, w32thread_cond_t, sys_mutex_t) (sys_cond_t, sys_thread_t) [WINDOWSNT]: New data types. src/systhread.c (sys_mutex_init, sys_mutex_lock, sys_mutex_unlock) (sys_mutex_destroy, sys_cond_init, sys_cond_wait) (sys_cond_signal, sys_cond_broadcast, sys_cond_destroy) (sys_thread_self, sys_thread_equal, w32_beginthread_wrapper) (sys_thread_create, sys_thread_yield) [WINDOWSNT]: New functions. configure.ac (THREADS_ENABLED): Enable threads for MinGW, even if pthreads is not available.
Diffstat (limited to 'src/systhread.c')
-rw-r--r--src/systhread.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/systhread.c b/src/systhread.c
index 8c9ec438d96..b154abaecd6 100644
--- a/src/systhread.c
+++ b/src/systhread.c
@@ -197,6 +197,155 @@ sys_thread_yield (void)
197 sched_yield (); 197 sched_yield ();
198} 198}
199 199
200#elif defined (WINDOWSNT)
201
202#include <windows.h>
203
204/* Cannot include <process.h> because of the local header by the same
205 name, sigh. */
206uintptr_t _beginthread (void (__cdecl *)(void *), unsigned, void *);
207
208/* Mutexes are implemented as critical sections, because they are
209 faster than Windows mutex objects (implemented in userspace), and
210 satisfy the requirements, since we only needto synchronize within a
211 single process. */
212void
213sys_mutex_init (sys_mutex_t *mutex)
214{
215 InitializeCriticalSection ((LPCRITICAL_SECTION)mutex);
216}
217
218void
219sys_mutex_lock (sys_mutex_t *mutex)
220{
221 /* FIXME: What happens if the owning thread exits without releasing
222 the mutex? Accoding to MSDN, the result is undefined behavior. */
223 EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
224}
225
226void
227sys_mutex_unlock (sys_mutex_t *mutex)
228{
229 LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
230}
231
232void
233sys_mutex_destroy (sys_mutex_t *mutex)
234{
235 /* FIXME: According to MSDN, deleting a critical session that is
236 owned by a thread leaves the other threads waiting for the
237 critical session in an undefined state. Posix docs seems to say
238 the same about pthread_mutex_destroy. Do we need to protect
239 against such calamities? */
240 DeleteCriticalSection ((LPCRITICAL_SECTION)mutex);
241}
242
243void
244sys_cond_init (sys_cond_t *cond)
245{
246 cond->events[CONDV_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL);
247 cond->events[CONDV_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL);
248}
249
250void
251sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
252{
253 /* FIXME: This implementation is simple, but incorrect. Stay tuned
254 for better and more complicated implementation. */
255 LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
256 WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
257 EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
258}
259
260void
261sys_cond_signal (sys_cond_t *cond)
262{
263 PulseEvent (cond->events[CONDV_SIGNAL]);
264}
265
266void
267sys_cond_broadcast (sys_cond_t *cond)
268{
269 PulseEvent (cond->events[CONDV_BROADCAST]);
270}
271
272void
273sys_cond_destroy (sys_cond_t *cond)
274{
275 CloseHandle (cond->events[CONDV_SIGNAL]);
276 CloseHandle (cond->events[CONDV_BROADCAST]);
277}
278
279sys_thread_t
280sys_thread_self (void)
281{
282 return (sys_thread_t) GetCurrentThreadId ();
283}
284
285int
286sys_thread_equal (sys_thread_t one, sys_thread_t two)
287{
288 return one == two;
289}
290
291static thread_creation_function *thread_start_address;
292
293static void
294w32_beginthread_wrapper (void *arg)
295{
296 (void)thread_start_address (arg);
297}
298
299int
300sys_thread_create (sys_thread_t *thread_ptr, const char *name,
301 thread_creation_function *func, void *arg)
302{
303 /* FIXME: Do threads that run Lisp require some minimum amount of
304 stack? Zero here means each thread will get the same amount as
305 the main program. On GNU/Linux, it seems like the stack is 2MB
306 by default, overridden by RLIMIT_STACK at program start time.
307 Not sure what to do with this. See also the comment in
308 w32proc"new_child. */
309 const unsigned stack_size = 0;
310 uintptr_t thandle;
311
312 /* _beginthread wants a void function, while we are passed a
313 function that returns a pointer. So we use a wrapper. */
314 thread_start_address = func;
315
316 /* We use _beginthread rather than CreateThread because the former
317 arranges for the thread handle to be automatically closed when
318 the thread exits, thus preventing handle leaks and/or the need to
319 track all the threads and close their handles when they exit.
320 Also, MSDN seems to imply that code which uses CRT _must_ call
321 _beginthread, although if that is true, we already violate that
322 rule in many places... */
323 thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg);
324 if (thandle == (uintptr_t)-1L)
325 return errno;
326
327 /* Kludge alert! We use the Windows thread ID, an unsigned 32-bit
328 number, as the sys_thread_t type, because that ID is the only
329 unique identifier of a thread on Windows. But _beginthread
330 returns a handle of the thread, and there's no easy way of
331 getting the thread ID given a handle (GetThreadId is available
332 only since Vista, so we cannot use it portably). Fortunately,
333 the value returned by sys_thread_create is not used by its
334 callers; instead, run_thread, which runs in the context of the
335 new thread, calls sys_thread_self and uses its return value;
336 sys_thread_self in this implementation calls GetCurrentThreadId.
337 Therefore, we return some more or less arbitrary value of the
338 thread ID from this function. */
339 *thread_ptr = thandle & 0xFFFFFFFF;
340 return 0;
341}
342
343void
344sys_thread_yield (void)
345{
346 Sleep (0);
347}
348
200#else 349#else
201 350
202#error port me 351#error port me