aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog11
-rw-r--r--src/systhread.c149
-rw-r--r--src/systhread.h34
3 files changed, 194 insertions, 0 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index a0682bdfd48..0aef16d34e3 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,14 @@
12013-08-30 Eli Zaretskii <eliz@gnu.org>
2
3 * systhread.h (w32thread_critsect, w32thread_cond_t, sys_mutex_t)
4 (sys_cond_t, sys_thread_t) [WINDOWSNT]: New data types.
5
6 * systhread.c (sys_mutex_init, sys_mutex_lock, sys_mutex_unlock)
7 (sys_mutex_destroy, sys_cond_init, sys_cond_wait)
8 (sys_cond_signal, sys_cond_broadcast, sys_cond_destroy)
9 (sys_thread_self, sys_thread_equal, w32_beginthread_wrapper)
10 (sys_thread_create, sys_thread_yield) [WINDOWSNT]: New functions.
11
12013-08-26 Eli Zaretskii <eliz@gnu.org> 122013-08-26 Eli Zaretskii <eliz@gnu.org>
2 13
3 * callproc.c: 14 * callproc.c:
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
diff --git a/src/systhread.h b/src/systhread.h
index eb9cde78b61..52735449a5e 100644
--- a/src/systhread.h
+++ b/src/systhread.h
@@ -36,8 +36,42 @@ typedef pthread_t sys_thread_t;
36 36
37#else /* HAVE_PTHREAD */ 37#else /* HAVE_PTHREAD */
38 38
39#ifdef WINDOWSNT
40
41/* This header is indirectly included in every source file. We don't
42 want to include windows.h in every source file, so we repeat
43 declarations of the few necessary data types here (under different
44 names, to avoid conflicts with files that do include
45 windows.h). */
46
47typedef struct {
48 struct _CRITICAL_SECTION_DEBUG *DebugInfo;
49 long LockCount;
50 long RecursionCount;
51 void *OwningThread;
52 void *LockSemaphore;
53 unsigned long SpinCount;
54} w32thread_critsect;
55
56enum { CONDV_SIGNAL = 0, CONDV_BROADCAST = 1, CONDV_MAX = 2 };
57
58typedef struct {
59 unsigned waiters_count;
60 w32thread_critsect waiters_count_lock;
61 void *events[CONDV_MAX];
62} w32thread_cond_t;
63
64typedef w32thread_critsect sys_mutex_t;
65
66typedef w32thread_cond_t sys_cond_t;
67
68typedef unsigned long sys_thread_t;
69
70#else /* !WINDOWSNT */
71
39#error port me 72#error port me
40 73
74#endif /* WINDOWSNT */
41#endif /* HAVE_PTHREAD */ 75#endif /* HAVE_PTHREAD */
42 76
43#else /* THREADS_ENABLED */ 77#else /* THREADS_ENABLED */