aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2017-01-18 18:06:42 +0200
committerEli Zaretskii2017-01-18 18:06:42 +0200
commit5fefaaa8c0696ba4b7b6e1e89267aa10fff88b31 (patch)
treea6206b902d88eefec0fbed6644d3a6648fcae448 /src
parent571532605bc0db221c76e36067435e4355e0d1a1 (diff)
downloademacs-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.c41
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. */
145static int 145static int
146lisp_mutex_lock (lisp_mutex_t *mutex, int new_count) 146lisp_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
180static int
181lisp_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
413DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, 420DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0,