summaryrefslogtreecommitdiff
path: root/libguile/threads.c
diff options
context:
space:
mode:
Diffstat (limited to 'libguile/threads.c')
-rw-r--r--libguile/threads.c56
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;
}