diff options
| author | Eli Zaretskii | 2017-01-18 18:06:42 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2017-01-18 18:06:42 +0200 |
| commit | 5fefaaa8c0696ba4b7b6e1e89267aa10fff88b31 (patch) | |
| tree | a6206b902d88eefec0fbed6644d3a6648fcae448 /src | |
| parent | 571532605bc0db221c76e36067435e4355e0d1a1 (diff) | |
| download | emacs-5fefaaa8c0696ba4b7b6e1e89267aa10fff88b31.tar.gz emacs-5fefaaa8c0696ba4b7b6e1e89267aa10fff88b31.zip | |
Fix a bug with signaling a thread that waits for condvar
* src/thread.c (lisp_mutex_lock_for_thread): New function,
with all the guts of lisp_mutex_lock.
(lisp_mutex_lock): Call lisp_mutex_lock_for_thread.
(condition_wait_callback): Don't call post_acquire_global_lock
before locking the mutex, as that could cause a signaled thread to
exit prematurely, because the condvar's mutex is recorded to be
not owned by any thread, and with-mutex wants to unlock it as part
of unwinding the stack in response to the signal.
Diffstat (limited to 'src')
| -rw-r--r-- | src/thread.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/src/thread.c b/src/thread.c index 6048516659e..9ea7e121a82 100644 --- a/src/thread.c +++ b/src/thread.c | |||
| @@ -128,11 +128,11 @@ 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 | 131 | /* Lock MUTEX for thread LOCKER, setting its lock count to COUNT, if |
| 132 | otherwise. | 132 | non-zero, or to 1 otherwise. |
| 133 | 133 | ||
| 134 | If MUTEX is locked by the current thread, COUNT must be zero, and | 134 | If MUTEX is locked by LOCKER, COUNT must be zero, and the MUTEX's |
| 135 | the MUTEX's lock count will be incremented. | 135 | lock count will be incremented. |
| 136 | 136 | ||
| 137 | If MUTEX is locked by another thread, this function will release | 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 | 138 | the global lock, giving other threads a chance to run, and will |
| @@ -143,24 +143,25 @@ lisp_mutex_init (lisp_mutex_t *mutex) | |||
| 143 | unlocked (meaning other threads could have run during the wait), | 143 | unlocked (meaning other threads could have run during the wait), |
| 144 | zero otherwise. */ | 144 | zero otherwise. */ |
| 145 | static int | 145 | static int |
| 146 | lisp_mutex_lock (lisp_mutex_t *mutex, int new_count) | 146 | lisp_mutex_lock_for_thread (lisp_mutex_t *mutex, struct thread_state *locker, |
| 147 | int new_count) | ||
| 147 | { | 148 | { |
| 148 | struct thread_state *self; | 149 | struct thread_state *self; |
| 149 | 150 | ||
| 150 | if (mutex->owner == NULL) | 151 | if (mutex->owner == NULL) |
| 151 | { | 152 | { |
| 152 | mutex->owner = current_thread; | 153 | mutex->owner = locker; |
| 153 | mutex->count = new_count == 0 ? 1 : new_count; | 154 | mutex->count = new_count == 0 ? 1 : new_count; |
| 154 | return 0; | 155 | return 0; |
| 155 | } | 156 | } |
| 156 | if (mutex->owner == current_thread) | 157 | if (mutex->owner == locker) |
| 157 | { | 158 | { |
| 158 | eassert (new_count == 0); | 159 | eassert (new_count == 0); |
| 159 | ++mutex->count; | 160 | ++mutex->count; |
| 160 | return 0; | 161 | return 0; |
| 161 | } | 162 | } |
| 162 | 163 | ||
| 163 | self = current_thread; | 164 | self = locker; |
| 164 | self->wait_condvar = &mutex->condition; | 165 | self->wait_condvar = &mutex->condition; |
| 165 | while (mutex->owner != NULL && (new_count != 0 | 166 | while (mutex->owner != NULL && (new_count != 0 |
| 166 | || NILP (self->error_symbol))) | 167 | || NILP (self->error_symbol))) |
| @@ -176,6 +177,12 @@ lisp_mutex_lock (lisp_mutex_t *mutex, int new_count) | |||
| 176 | return 1; | 177 | return 1; |
| 177 | } | 178 | } |
| 178 | 179 | ||
| 180 | static int | ||
| 181 | lisp_mutex_lock (lisp_mutex_t *mutex, int new_count) | ||
| 182 | { | ||
| 183 | return lisp_mutex_lock_for_thread (mutex, current_thread, new_count); | ||
| 184 | } | ||
| 185 | |||
| 179 | /* Decrement MUTEX's lock count. If the lock count becomes zero after | 186 | /* Decrement MUTEX's lock count. If the lock count becomes zero after |
| 180 | decrementing it, meaning the mutex is now unlocked, broadcast that | 187 | decrementing it, meaning the mutex is now unlocked, broadcast that |
| 181 | to all the threads that might be waiting to lock the mutex. This | 188 | to all the threads that might be waiting to lock the mutex. This |
| @@ -398,16 +405,16 @@ condition_wait_callback (void *arg) | |||
| 398 | self->wait_condvar = NULL; | 405 | self->wait_condvar = NULL; |
| 399 | } | 406 | } |
| 400 | self->event_object = Qnil; | 407 | self->event_object = Qnil; |
| 401 | /* Since sys_cond_wait could switch threads, we need to re-establish | 408 | /* Since sys_cond_wait could switch threads, we need to lock the |
| 402 | ourselves as the current thread, otherwise lisp_mutex_lock will | 409 | mutex for the thread which was the current when we were called, |
| 403 | record the wrong thread as the owner of the mutex lock. */ | 410 | otherwise lisp_mutex_lock will record the wrong thread as the |
| 404 | post_acquire_global_lock (self); | 411 | owner of the mutex lock. */ |
| 405 | /* Calling lisp_mutex_lock might yield to other threads while this | 412 | lisp_mutex_lock_for_thread (&mutex->mutex, self, saved_count); |
| 406 | one waits for the mutex to become unlocked, so we need to | 413 | /* Calling lisp_mutex_lock_for_thread might yield to other threads |
| 407 | announce us as the current thread by calling | 414 | while this one waits for the mutex to become unlocked, so we need |
| 415 | to announce us as the current thread by calling | ||
| 408 | post_acquire_global_lock. */ | 416 | post_acquire_global_lock. */ |
| 409 | if (lisp_mutex_lock (&mutex->mutex, saved_count)) | 417 | post_acquire_global_lock (self); |
| 410 | post_acquire_global_lock (self); | ||
| 411 | } | 418 | } |
| 412 | 419 | ||
| 413 | DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, | 420 | DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, |