diff --git a/src/systhread.c b/src/systhread.c index 6f4de536fb..77603fcbcd 100644 --- a/src/systhread.c +++ b/src/systhread.c @@ -51,7 +51,7 @@ sys_cond_init (sys_cond_t *c) } void -sys_cond_wait (sys_cond_t *c, sys_mutex_t *m) +sys_cond_wait (sys_cond_t *c, sys_mutex_t *m, int max_seconds) { } @@ -158,10 +158,20 @@ sys_cond_init (sys_cond_t *cond) } void -sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) +sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex, int max_seconds) { - int error = pthread_cond_wait (cond, mutex); - eassert (error == 0); + int error; + + if (max_seconds < 0) + error = pthread_cond_wait (cond, mutex); + else + { + struct timespec timeout; + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += max_seconds; + error = pthread_cond_timedwait (cond, mutex, &timeout); + } + eassert (error == 0 || error != ETIMEDOUT); } void @@ -294,9 +304,10 @@ sys_cond_init (sys_cond_t *cond) } void -sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) +sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex, int max_seconds) { DWORD wait_result; + DWORD max_millis = max_seconds < 0 ? INFINITE : 1000 * max_seconds; bool last_thread_waiting; if (!cond->initialized) @@ -310,7 +321,7 @@ sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) /* Release the mutex and wait for either the signal or the broadcast event. */ LeaveCriticalSection ((LPCRITICAL_SECTION)mutex); - wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE); + wait_result = WaitForMultipleObjects (2, cond->events, FALSE, max_millis); /* Decrement the wait count and see if we are the last thread waiting on the condition variable. */ diff --git a/src/systhread.h b/src/systhread.h index 8070bcde75..7a1ca615d7 100644 --- a/src/systhread.h +++ b/src/systhread.h @@ -32,6 +32,7 @@ along with GNU Emacs. If not, see . */ #ifdef HAVE_PTHREAD #include +#include /* A system mutex is just a pthread mutex. This is only used for the GIL. */ @@ -102,7 +103,7 @@ extern void sys_mutex_lock (sys_mutex_t *); extern void sys_mutex_unlock (sys_mutex_t *); extern void sys_cond_init (sys_cond_t *); -extern void sys_cond_wait (sys_cond_t *, sys_mutex_t *); +extern void sys_cond_wait (sys_cond_t *, sys_mutex_t *, int); extern void sys_cond_signal (sys_cond_t *); extern void sys_cond_broadcast (sys_cond_t *); extern void sys_cond_destroy (sys_cond_t *); diff --git a/src/thread.c b/src/thread.c index e2deadd7a8..92fd6188ec 100644 --- a/src/thread.c +++ b/src/thread.c @@ -193,7 +193,7 @@ lisp_mutex_lock_for_thread (lisp_mutex_t *mutex, struct thread_state *locker, self->wait_condvar = &mutex->condition; while (mutex->owner != NULL && (new_count != 0 || NILP (self->error_symbol))) - sys_cond_wait (&mutex->condition, &global_lock); + sys_cond_wait (&mutex->condition, &global_lock, -1); self->wait_condvar = NULL; if (new_count == 0 && !NILP (self->error_symbol)) @@ -404,10 +404,18 @@ informational only. */) return result; } +struct wait_args +{ + struct Lisp_CondVar *cvar; + int max_seconds; +}; + static void -condition_wait_callback (void *arg) +condition_wait_callback (void *wait_arg) { - struct Lisp_CondVar *cvar = arg; + struct wait_args *arg = wait_arg; + struct Lisp_CondVar *cvar = arg->cvar; + int max_seconds = arg->max_seconds; struct Lisp_Mutex *mutex = XMUTEX (cvar->mutex); struct thread_state *self = current_thread; unsigned int saved_count; @@ -421,7 +429,7 @@ condition_wait_callback (void *arg) { self->wait_condvar = &cvar->cond; /* This call could switch to another thread. */ - sys_cond_wait (&cvar->cond, &global_lock); + sys_cond_wait (&cvar->cond, &global_lock, max_seconds); self->wait_condvar = NULL; } self->event_object = Qnil; @@ -437,9 +445,26 @@ condition_wait_callback (void *arg) post_acquire_global_lock (self); } -DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, +#define MAIN_THREAD_CONDITION_WAIT_MAX 16 + +static int +condition_wait_get_timeout (Lisp_Object specified) +{ + if (NILP (specified)) + XSETINT(specified, -1); + else + CHECK_INTEGER (specified); + + if (main_thread_p (current_thread)) + return max (MAIN_THREAD_CONDITION_WAIT_MAX, XFIXNUM (specified)); + + return XFIXNUM (specified); +} + +DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 2, 0, doc: /* Wait for the condition variable COND to be notified. -COND is the condition variable to wait on. +COND is the condition variable to wait on. Wait at most SECONDS +seconds. If SECONDS is negative, wait without limit. The mutex associated with COND must be held when this is called. It is an error if it is not held. @@ -448,10 +473,11 @@ This releases the mutex and waits for COND to be notified or for this thread to be signaled with `thread-signal'. When `condition-wait' returns, COND's mutex will again be locked by this thread. */) - (Lisp_Object cond) + (Lisp_Object cond, Lisp_Object seconds) { struct Lisp_CondVar *cvar; struct Lisp_Mutex *mutex; + struct wait_args args; CHECK_CONDVAR (cond); cvar = XCONDVAR (cond); @@ -460,7 +486,9 @@ this thread. */) if (!lisp_mutex_owned_p (&mutex->mutex)) error ("Condition variable's mutex is not held by current thread"); - flush_stack_call_func (condition_wait_callback, cvar); + args.cvar = cvar; + args.max_seconds = condition_wait_get_timeout (seconds); + flush_stack_call_func (condition_wait_callback, &args); return Qnil; } @@ -961,7 +989,7 @@ thread_join_callback (void *arg) self->event_object = thread; self->wait_condvar = &tstate->thread_condvar; while (thread_live_p (tstate) && NILP (self->error_symbol)) - sys_cond_wait (self->wait_condvar, &global_lock); + sys_cond_wait (self->wait_condvar, &global_lock, -1); self->wait_condvar = NULL; self->event_object = Qnil;