aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2013-08-31 14:29:05 +0300
committerEli Zaretskii2013-08-31 14:29:05 +0300
commite57df8f77901a3964d21c3d57fb6769cf4511dc2 (patch)
tree1a748293f62f70a786b9f6c51662e1c132650528 /src
parentdbe17fefccbff010bbbf6c4d0dccc7b2f3a5e201 (diff)
downloademacs-e57df8f77901a3964d21c3d57fb6769cf4511dc2.tar.gz
emacs-e57df8f77901a3964d21c3d57fb6769cf4511dc2.zip
Improve MS-Windows implementation of threads.
src/systhread.c (sys_cond_init): Set the 'initialized' member to true only if initialization is successful. Initialize wait_count and wait_count_lock. (sys_cond_wait, sys_cond_signal, sys_cond_broadcast): If 'initialized' is false, do nothing. (sys_cond_wait): Fix the implementation to avoid the "missed wakeup" bug: count the waiting threads, and reset the broadcast event once the last thread was released. (sys_cond_signal, sys_cond_broadcast): Use SetEvent instead of PulseEvent. Don't signal the event if no threads are waiting. (sys_cond_destroy): Only close non-NULL handles. (sys_thread_create): Return zero if unsuccessful, 1 if successful. src/systhread.h (w32thread_cond_t): New member 'initialized'. Rename waiters_count and waiters_count_lock to wait_count and wait_count_lock, respectively.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog19
-rw-r--r--src/process.c3
-rw-r--r--src/systhread.c82
-rw-r--r--src/systhread.h8
4 files changed, 98 insertions, 14 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 0aef16d34e3..3e901d84db9 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,22 @@
12013-08-31 Eli Zaretskii <eliz@gnu.org>
2
3 * systhread.c (sys_cond_init): Set the 'initialized' member to
4 true only if initialization is successful. Initialize wait_count
5 and wait_count_lock.
6 (sys_cond_wait, sys_cond_signal, sys_cond_broadcast): If
7 'initialized' is false, do nothing.
8 (sys_cond_wait): Fix the implementation to avoid the "missed
9 wakeup" bug: count the waiting threads, and reset the broadcast
10 event once the last thread was released.
11 (sys_cond_signal, sys_cond_broadcast): Use SetEvent instead of
12 PulseEvent. Don't signal the event if no threads are waiting.
13 (sys_cond_destroy): Only close non-NULL handles.
14 (sys_thread_create): Return zero if unsuccessful, 1 if successful.
15
16 * systhread.h (w32thread_cond_t): New member 'initialized'.
17 Rename waiters_count and waiters_count_lock to wait_count and
18 wait_count_lock, respectively.
19
12013-08-30 Eli Zaretskii <eliz@gnu.org> 202013-08-30 Eli Zaretskii <eliz@gnu.org>
2 21
3 * systhread.h (w32thread_critsect, w32thread_cond_t, sys_mutex_t) 22 * systhread.h (w32thread_critsect, w32thread_cond_t, sys_mutex_t)
diff --git a/src/process.c b/src/process.c
index 94ca3d4b1a0..899c0035866 100644
--- a/src/process.c
+++ b/src/process.c
@@ -497,7 +497,6 @@ void
497delete_read_fd (int fd) 497delete_read_fd (int fd)
498{ 498{
499 eassert (fd < MAXDESC); 499 eassert (fd < MAXDESC);
500 eassert (fd <= max_desc);
501 delete_keyboard_wait_descriptor (fd); 500 delete_keyboard_wait_descriptor (fd);
502 501
503 if (fd_callback_info[fd].flags == 0) 502 if (fd_callback_info[fd].flags == 0)
@@ -559,7 +558,6 @@ delete_write_fd (int fd)
559 int lim = max_desc; 558 int lim = max_desc;
560 559
561 eassert (fd < MAXDESC); 560 eassert (fd < MAXDESC);
562 eassert (fd <= max_desc);
563 561
564#ifdef NON_BLOCKING_CONNECT 562#ifdef NON_BLOCKING_CONNECT
565 if ((fd_callback_info[fd].flags & NON_BLOCKING_CONNECT_FD) != 0) 563 if ((fd_callback_info[fd].flags & NON_BLOCKING_CONNECT_FD) != 0)
@@ -6942,7 +6940,6 @@ delete_keyboard_wait_descriptor (int desc)
6942 int lim = max_desc; 6940 int lim = max_desc;
6943 6941
6944 eassert (desc >= 0 && desc < MAXDESC); 6942 eassert (desc >= 0 && desc < MAXDESC);
6945 eassert (desc <= max_desc);
6946 6943
6947 fd_callback_info[desc].flags &= ~(FOR_READ | KEYBOARD_FD | PROCESS_FD); 6944 fd_callback_info[desc].flags &= ~(FOR_READ | KEYBOARD_FD | PROCESS_FD);
6948 6945
diff --git a/src/systhread.c b/src/systhread.c
index b154abaecd6..bde0f027e78 100644
--- a/src/systhread.c
+++ b/src/systhread.c
@@ -243,37 +243,101 @@ sys_mutex_destroy (sys_mutex_t *mutex)
243void 243void
244sys_cond_init (sys_cond_t *cond) 244sys_cond_init (sys_cond_t *cond)
245{ 245{
246 cond->initialized = false;
247 cond->wait_count = 0;
248 /* Auto-reset event for signal. */
246 cond->events[CONDV_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL); 249 cond->events[CONDV_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL);
250 /* Manual-reset event for broadcast. */
247 cond->events[CONDV_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL); 251 cond->events[CONDV_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL);
252 if (!cond->events[CONDV_SIGNAL] || !cond->events[CONDV_BROADCAST])
253 return;
254 InitializeCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
255 cond->initialized = true;
248} 256}
249 257
250void 258void
251sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) 259sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
252{ 260{
253 /* FIXME: This implementation is simple, but incorrect. Stay tuned 261 DWORD wait_result;
254 for better and more complicated implementation. */ 262 bool last_thread_waiting;
263
264 if (!cond->initialized)
265 return;
266
267 /* Increment the wait count avoiding race conditions. */
268 EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
269 cond->wait_count++;
270 LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
271
272 /* Release the mutex and wait for either the signal or the broadcast
273 event. */
255 LeaveCriticalSection ((LPCRITICAL_SECTION)mutex); 274 LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
256 WaitForMultipleObjects (2, cond->events, FALSE, INFINITE); 275 wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
276
277 /* Decrement the wait count and see if we are the last thread
278 waiting on the condition variable. */
279 EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
280 cond->wait_count--;
281 last_thread_waiting =
282 wait_result == WAIT_OBJECT_0 + CONDV_BROADCAST
283 && cond->wait_count == 0;
284 LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
285
286 /* Broadcast uses a manual-reset event, so when the last thread is
287 released, we must manually reset that event. */
288 if (last_thread_waiting)
289 ResetEvent (cond->events[CONDV_BROADCAST]);
290
291 /* Per the API, re-acquire the mutex. */
257 EnterCriticalSection ((LPCRITICAL_SECTION)mutex); 292 EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
258} 293}
259 294
260void 295void
261sys_cond_signal (sys_cond_t *cond) 296sys_cond_signal (sys_cond_t *cond)
262{ 297{
263 PulseEvent (cond->events[CONDV_SIGNAL]); 298 bool threads_waiting;
299
300 if (!cond->initialized)
301 return;
302
303 EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
304 threads_waiting = cond->wait_count > 0;
305 LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
306
307 if (threads_waiting)
308 SetEvent (cond->events[CONDV_SIGNAL]);
264} 309}
265 310
266void 311void
267sys_cond_broadcast (sys_cond_t *cond) 312sys_cond_broadcast (sys_cond_t *cond)
268{ 313{
269 PulseEvent (cond->events[CONDV_BROADCAST]); 314 bool threads_waiting;
315
316 if (!cond->initialized)
317 return;
318
319 EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
320 threads_waiting = cond->wait_count > 0;
321 LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
322
323 if (threads_waiting)
324 SetEvent (cond->events[CONDV_BROADCAST]);
270} 325}
271 326
272void 327void
273sys_cond_destroy (sys_cond_t *cond) 328sys_cond_destroy (sys_cond_t *cond)
274{ 329{
275 CloseHandle (cond->events[CONDV_SIGNAL]); 330 if (cond->events[CONDV_SIGNAL])
276 CloseHandle (cond->events[CONDV_BROADCAST]); 331 CloseHandle (cond->events[CONDV_SIGNAL]);
332 if (cond->events[CONDV_BROADCAST])
333 CloseHandle (cond->events[CONDV_BROADCAST]);
334
335 if (!cond->initialized)
336 return;
337
338 /* FIXME: What if wait_count is non-zero, i.e. there are still
339 threads waiting on this condition variable? */
340 DeleteCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
277} 341}
278 342
279sys_thread_t 343sys_thread_t
@@ -322,7 +386,7 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name,
322 rule in many places... */ 386 rule in many places... */
323 thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg); 387 thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg);
324 if (thandle == (uintptr_t)-1L) 388 if (thandle == (uintptr_t)-1L)
325 return errno; 389 return 0;
326 390
327 /* Kludge alert! We use the Windows thread ID, an unsigned 32-bit 391 /* 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 392 number, as the sys_thread_t type, because that ID is the only
@@ -337,7 +401,7 @@ sys_thread_create (sys_thread_t *thread_ptr, const char *name,
337 Therefore, we return some more or less arbitrary value of the 401 Therefore, we return some more or less arbitrary value of the
338 thread ID from this function. */ 402 thread ID from this function. */
339 *thread_ptr = thandle & 0xFFFFFFFF; 403 *thread_ptr = thandle & 0xFFFFFFFF;
340 return 0; 404 return 1;
341} 405}
342 406
343void 407void
diff --git a/src/systhread.h b/src/systhread.h
index 52735449a5e..b38fd8ffd45 100644
--- a/src/systhread.h
+++ b/src/systhread.h
@@ -56,9 +56,13 @@ typedef struct {
56enum { CONDV_SIGNAL = 0, CONDV_BROADCAST = 1, CONDV_MAX = 2 }; 56enum { CONDV_SIGNAL = 0, CONDV_BROADCAST = 1, CONDV_MAX = 2 };
57 57
58typedef struct { 58typedef struct {
59 unsigned waiters_count; 59 /* Count of threads that are waiting for this condition variable. */
60 w32thread_critsect waiters_count_lock; 60 unsigned wait_count;
61 /* Critical section to protect changes to the count above. */
62 w32thread_critsect wait_count_lock;
63 /* Handles of events used for signal and broadcast. */
61 void *events[CONDV_MAX]; 64 void *events[CONDV_MAX];
65 bool initialized;
62} w32thread_cond_t; 66} w32thread_cond_t;
63 67
64typedef w32thread_critsect sys_mutex_t; 68typedef w32thread_critsect sys_mutex_t;