diff options
Diffstat (limited to 'libguile/threads.c')
-rw-r--r-- | libguile/threads.c | 56 |
1 files changed, 35 insertions, 21 deletions
diff --git a/libguile/threads.c b/libguile/threads.c index ac3a50290..745d03471 100644 --- a/libguile/threads.c +++ b/libguile/threads.c @@ -97,11 +97,13 @@ static SCM enqueue (SCM q, SCM t) { SCM c = scm_cons (t, SCM_EOL); + SCM_CRITICAL_SECTION_START; if (scm_is_null (SCM_CDR (q))) SCM_SETCDR (q, c); else SCM_SETCDR (SCM_CAR (q), c); SCM_SETCAR (q, c); + SCM_CRITICAL_SECTION_END; return c; } @@ -114,6 +116,7 @@ static int remqueue (SCM q, SCM c) { SCM p, prev = q; + SCM_CRITICAL_SECTION_START; for (p = SCM_CDR (q); !scm_is_null (p); p = SCM_CDR (p)) { if (scm_is_eq (p, c)) @@ -121,10 +124,12 @@ remqueue (SCM q, SCM c) if (scm_is_eq (c, SCM_CAR (q))) SCM_SETCAR (q, SCM_CDR (c)); SCM_SETCDR (prev, SCM_CDR (c)); + SCM_CRITICAL_SECTION_END; return 1; } prev = p; } + SCM_CRITICAL_SECTION_END; return 0; } @@ -134,14 +139,20 @@ remqueue (SCM q, SCM c) static SCM dequeue (SCM q) { - SCM c = SCM_CDR (q); + SCM c; + SCM_CRITICAL_SECTION_START; + c = SCM_CDR (q); if (scm_is_null (c)) - return SCM_BOOL_F; + { + SCM_CRITICAL_SECTION_END; + return SCM_BOOL_F; + } else { SCM_SETCDR (q, SCM_CDR (c)); if (scm_is_null (SCM_CDR (q))) SCM_SETCAR (q, SCM_EOL); + SCM_CRITICAL_SECTION_END; return SCM_CAR (c); } } @@ -204,8 +215,7 @@ thread_free (SCM obj) interrupted. Upon return of this function, the current thread is no longer on QUEUE, even when the sleep has been interrupted. - The QUEUE data structure is assumed to be protected by MUTEX and - the caller of block_self must hold MUTEX. It will be atomically + The caller of block_self must hold MUTEX. It will be atomically unlocked while sleeping, just as with scm_i_pthread_cond_wait. SLEEP_OBJECT is an arbitrary SCM value that is kept alive as long @@ -253,9 +263,8 @@ block_self (SCM queue, SCM sleep_object, scm_i_pthread_mutex_t *mutex, return err; } -/* Wake up the first thread on QUEUE, if any. The caller must hold - the mutex that protects QUEUE. The awoken thread is returned, or - #f when the queue was empty. +/* Wake up the first thread on QUEUE, if any. The awoken thread is + returned, or #f if the queue was empty. */ static SCM unblock_from_queue (SCM queue) @@ -420,6 +429,7 @@ guilify_self_1 (SCM_STACKITEM *base) t->result = SCM_BOOL_F; t->cleanup_handler = SCM_BOOL_F; t->mutexes = SCM_EOL; + t->held_mutex = NULL; t->join_queue = SCM_EOL; t->dynamic_state = SCM_BOOL_F; t->dynwinds = SCM_EOL; @@ -564,6 +574,14 @@ on_thread_exit (void *v) /* This handler is executed in non-guile mode. */ scm_i_thread *t = (scm_i_thread *) v, **tp; + /* If this thread was cancelled while doing a cond wait, it will + still have a mutex locked, so we unlock it here. */ + if (t->held_mutex) + { + scm_i_pthread_mutex_unlock (t->held_mutex); + t->held_mutex = NULL; + } + scm_i_pthread_setspecific (scm_i_thread_key, v); /* Ensure the signal handling thread has been launched, because we might be @@ -1437,17 +1455,15 @@ fat_mutex_unlock (SCM mutex, SCM cond, { int brk = 0; - scm_i_scm_pthread_mutex_lock (&c->lock); if (m->level > 0) m->level--; if (m->level == 0) m->owner = unblock_from_queue (m->waiting); - scm_i_pthread_mutex_unlock (&m->lock); - t->block_asyncs++; - err = block_self (c->waiting, cond, &c->lock, waittime); + err = block_self (c->waiting, cond, &m->lock, waittime); + scm_i_pthread_mutex_unlock (&m->lock); if (err == 0) { @@ -1462,7 +1478,6 @@ fat_mutex_unlock (SCM mutex, SCM cond, else if (err != EINTR) { errno = err; - scm_i_pthread_mutex_unlock (&c->lock); scm_syserror (NULL); } @@ -1470,12 +1485,9 @@ fat_mutex_unlock (SCM mutex, SCM cond, { if (relock) scm_lock_mutex_timed (mutex, SCM_UNDEFINED, owner); - scm_i_pthread_mutex_unlock (&c->lock); break; } - scm_i_pthread_mutex_unlock (&c->lock); - t->block_asyncs--; scm_async_click (); @@ -1583,7 +1595,6 @@ static size_t fat_cond_free (SCM mx) { fat_cond *c = SCM_CONDVAR_DATA (mx); - scm_i_pthread_mutex_destroy (&c->lock); scm_gc_free (c, sizeof (fat_cond), "condition-variable"); return 0; } @@ -1607,7 +1618,6 @@ SCM_DEFINE (scm_make_condition_variable, "make-condition-variable", 0, 0, 0, SCM cv; c = scm_gc_malloc (sizeof (fat_cond), "condition variable"); - scm_i_pthread_mutex_init (&c->lock, 0); c->waiting = SCM_EOL; SCM_NEWSMOB (cv, scm_tc16_condvar, (scm_t_bits) c); c->waiting = make_queue (); @@ -1646,9 +1656,7 @@ SCM_DEFINE (scm_timed_wait_condition_variable, "wait-condition-variable", 2, 1, static void fat_cond_signal (fat_cond *c) { - scm_i_scm_pthread_mutex_lock (&c->lock); unblock_from_queue (c->waiting); - scm_i_pthread_mutex_unlock (&c->lock); } SCM_DEFINE (scm_signal_condition_variable, "signal-condition-variable", 1, 0, 0, @@ -1665,10 +1673,8 @@ SCM_DEFINE (scm_signal_condition_variable, "signal-condition-variable", 1, 0, 0, static void fat_cond_broadcast (fat_cond *c) { - scm_i_scm_pthread_mutex_lock (&c->lock); while (scm_is_true (unblock_from_queue (c->waiting))) ; - scm_i_pthread_mutex_unlock (&c->lock); } SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1, 0, 0, @@ -1833,7 +1839,11 @@ scm_dynwind_pthread_mutex_lock (scm_i_pthread_mutex_t *mutex) int scm_pthread_cond_wait (scm_i_pthread_cond_t *cond, scm_i_pthread_mutex_t *mutex) { + scm_t_guile_ticket t = scm_leave_guile (); + ((scm_i_thread *)t)->held_mutex = mutex; int res = scm_i_pthread_cond_wait (cond, mutex); + ((scm_i_thread *)t)->held_mutex = NULL; + scm_enter_guile (t); return res; } @@ -1842,7 +1852,11 @@ scm_pthread_cond_timedwait (scm_i_pthread_cond_t *cond, scm_i_pthread_mutex_t *mutex, const scm_t_timespec *wt) { + scm_t_guile_ticket t = scm_leave_guile (); + ((scm_i_thread *)t)->held_mutex = mutex; int res = scm_i_pthread_cond_timedwait (cond, mutex, wt); + ((scm_i_thread *)t)->held_mutex = NULL; + scm_enter_guile (t); return res; } |