aboutsummaryrefslogtreecommitdiffstats
path: root/src/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/thread.c')
-rw-r--r--src/thread.c43
1 files changed, 41 insertions, 2 deletions
diff --git a/src/thread.c b/src/thread.c
index 01e8aa736ce..5498fe5efcb 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -128,6 +128,20 @@ lisp_mutex_init (lisp_mutex_t *mutex)
128 sys_cond_init (&mutex->condition); 128 sys_cond_init (&mutex->condition);
129} 129}
130 130
131/* Lock MUTEX setting its count to COUNT, if non-zero, or to 1
132 otherwise.
133
134 If MUTEX is locked by the current thread, COUNT must be zero, and
135 the MUTEX's lock count will be incremented.
136
137 If MUTEX is locked by another thread, this function will release
138 the global lock, giving other threads a chance to run, and will
139 wait for the MUTEX to become unlocked; when MUTEX becomes unlocked,
140 and will then re-acquire the global lock.
141
142 Return value is 1 if the function waited for the MUTEX to become
143 unlocked (meaning other threads could have run during the wait),
144 zero otherwise. */
131static int 145static int
132lisp_mutex_lock (lisp_mutex_t *mutex, int new_count) 146lisp_mutex_lock (lisp_mutex_t *mutex, int new_count)
133{ 147{
@@ -162,6 +176,12 @@ lisp_mutex_lock (lisp_mutex_t *mutex, int new_count)
162 return 1; 176 return 1;
163} 177}
164 178
179/* Decrement MUTEX's lock count. If the lock count becomes zero after
180 decrementing it, meaning the mutex is now unlocked, broadcast that
181 to all the threads that might be waiting to lock the mutex. This
182 function signals an error if MUTEX is locked by a thread other than
183 the current one. Return value is 1 if the mutex becomes unlocked,
184 zero otherwise. */
165static int 185static int
166lisp_mutex_unlock (lisp_mutex_t *mutex) 186lisp_mutex_unlock (lisp_mutex_t *mutex)
167{ 187{
@@ -177,6 +197,8 @@ lisp_mutex_unlock (lisp_mutex_t *mutex)
177 return 1; 197 return 1;
178} 198}
179 199
200/* Like lisp_mutex_unlock, but sets MUTEX's lock count to zero
201 regardless of its value. Return the previous lock count. */
180static unsigned int 202static unsigned int
181lisp_mutex_unlock_for_wait (lisp_mutex_t *mutex) 203lisp_mutex_unlock_for_wait (lisp_mutex_t *mutex)
182{ 204{
@@ -241,6 +263,10 @@ mutex_lock_callback (void *arg)
241 struct Lisp_Mutex *mutex = arg; 263 struct Lisp_Mutex *mutex = arg;
242 struct thread_state *self = current_thread; 264 struct thread_state *self = current_thread;
243 265
266 /* Calling lisp_mutex_lock might yield to other threads while this
267 one waits for the mutex to become unlocked, so we need to
268 announce us as the current thread by calling
269 post_acquire_global_lock. */
244 if (lisp_mutex_lock (&mutex->mutex, 0)) 270 if (lisp_mutex_lock (&mutex->mutex, 0))
245 post_acquire_global_lock (self); 271 post_acquire_global_lock (self);
246} 272}
@@ -280,7 +306,7 @@ mutex_unlock_callback (void *arg)
280 struct thread_state *self = current_thread; 306 struct thread_state *self = current_thread;
281 307
282 if (lisp_mutex_unlock (&mutex->mutex)) 308 if (lisp_mutex_unlock (&mutex->mutex))
283 post_acquire_global_lock (self); 309 post_acquire_global_lock (self); /* FIXME: is this call needed? */
284} 310}
285 311
286DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0, 312DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0,
@@ -367,12 +393,21 @@ condition_wait_callback (void *arg)
367 if (NILP (self->error_symbol)) 393 if (NILP (self->error_symbol))
368 { 394 {
369 self->wait_condvar = &cvar->cond; 395 self->wait_condvar = &cvar->cond;
396 /* This call could switch to another thread. */
370 sys_cond_wait (&cvar->cond, &global_lock); 397 sys_cond_wait (&cvar->cond, &global_lock);
371 self->wait_condvar = NULL; 398 self->wait_condvar = NULL;
372 } 399 }
373 lisp_mutex_lock (&mutex->mutex, saved_count);
374 self->event_object = Qnil; 400 self->event_object = Qnil;
401 /* Since sys_cond_wait could switch threads, we need to re-establish
402 ourselves as the current thread, otherwise lisp_mutex_lock will
403 record the wrong thread as the owner of the mutex lock. */
375 post_acquire_global_lock (self); 404 post_acquire_global_lock (self);
405 /* Calling lisp_mutex_lock might yield to other threads while this
406 one waits for the mutex to become unlocked, so we need to
407 announce us as the current thread by calling
408 post_acquire_global_lock. */
409 if (lisp_mutex_lock (&mutex->mutex, saved_count))
410 post_acquire_global_lock (self);
376} 411}
377 412
378DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, 413DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0,
@@ -425,6 +460,10 @@ condition_notify_callback (void *arg)
425 sys_cond_broadcast (&na->cvar->cond); 460 sys_cond_broadcast (&na->cvar->cond);
426 else 461 else
427 sys_cond_signal (&na->cvar->cond); 462 sys_cond_signal (&na->cvar->cond);
463 /* Calling lisp_mutex_lock might yield to other threads while this
464 one waits for the mutex to become unlocked, so we need to
465 announce us as the current thread by calling
466 post_acquire_global_lock. */
428 lisp_mutex_lock (&mutex->mutex, saved_count); 467 lisp_mutex_lock (&mutex->mutex, saved_count);
429 post_acquire_global_lock (self); 468 post_acquire_global_lock (self);
430} 469}