diff options
Diffstat (limited to 'src/thread.c')
| -rw-r--r-- | src/thread.c | 43 |
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. */ | ||
| 131 | static int | 145 | static int |
| 132 | lisp_mutex_lock (lisp_mutex_t *mutex, int new_count) | 146 | lisp_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. */ | ||
| 165 | static int | 185 | static int |
| 166 | lisp_mutex_unlock (lisp_mutex_t *mutex) | 186 | lisp_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. */ | ||
| 180 | static unsigned int | 202 | static unsigned int |
| 181 | lisp_mutex_unlock_for_wait (lisp_mutex_t *mutex) | 203 | lisp_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 | ||
| 286 | DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0, | 312 | DEFUN ("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 | ||
| 378 | DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, | 413 | DEFUN ("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 | } |