From 5e066df1065f8397daaca5f19f1fefd981acaa08 Mon Sep 17 00:00:00 2001 From: Ben Lynn Date: Fri, 12 Sep 2008 19:10:33 -0700 Subject: [PATCH] Converted one condition variable to semaphore. --- cf.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/cf.c b/cf.c index 1f32f56..1700bbc 100644 --- a/cf.c +++ b/cf.c @@ -6,6 +6,7 @@ #include #include #include +#include #include struct channel_s { @@ -21,7 +22,7 @@ struct cf_s { // Helgrind prints warnings for these condition variables. // Rewrite with semaphores? // When queue is empty, and there is demand for the next term. - pthread_cond_t demand; + sem_t demand_sem; // When the queue was empty, and we just added to it. pthread_cond_t read_cond; pthread_mutex_t chan_mu; @@ -37,26 +38,34 @@ void *cf_data(cf_t cf) { return cf->data; } +// A bit like cooperative multitasking. Continued fractions are expected +// to call this as often as practical, and on a return value of 0, +// to drop everything and stop. int cf_wait(cf_t cf) { - pthread_mutex_lock(&cf->chan_mu); - if (cf->chan) { - // If there is still unread output, wait for 'demand' signal. - pthread_cond_wait(&cf->demand, &cf->chan_mu); + for (;;) { + sem_wait(&cf->demand_sem); + // The wait is over! + if (cf->quitflag) { + return 0; + } + pthread_mutex_lock(&cf->chan_mu); + // ... but we keep waiting unless the channel is empty. + if (!cf->chan) break; + pthread_mutex_unlock(&cf->chan_mu); + // The channel could be emptied in the meantime, but that + // implies at least one sem_post() call, so we'll notice next iteration. } pthread_mutex_unlock(&cf->chan_mu); - if (cf->quitflag) { - return 0; - } return 1; } void cf_free(cf_t cf) { + // These two statements force a thread out of its next/current cf_wait. cf->quitflag = 1; - pthread_mutex_lock(&cf->chan_mu); - pthread_cond_signal(&cf->demand); - pthread_mutex_unlock(&cf->chan_mu); + sem_post(&cf->demand_sem); + pthread_join(cf->thread, NULL); - pthread_cond_destroy(&cf->demand); + pthread_mutex_lock(&cf->chan_mu); channel_ptr c = cf->chan; while (c) { channel_ptr cnext = c->next; @@ -64,6 +73,8 @@ void cf_free(cf_t cf) { free(c); c = cnext; } + pthread_mutex_unlock(&cf->chan_mu); + sem_destroy(&cf->demand_sem); free(cf); } @@ -102,7 +113,7 @@ void cf_get(mpz_t z, cf_t cf) { pthread_mutex_lock(&cf->chan_mu); if (!cf->chan) { // If channel is empty, send demand signal and wait for read signal. - pthread_cond_signal(&cf->demand); + sem_post(&cf->demand_sem); pthread_cond_wait(&cf->read_cond, &cf->chan_mu); } channel_ptr c = cf->chan; @@ -129,7 +140,7 @@ cf_t cf_new(void *(*func)(cf_t), void *data) { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_mutex_init(&cf->chan_mu, NULL); - pthread_cond_init(&cf->demand, NULL); + sem_init(&cf->demand_sem, 0, 0); pthread_cond_init(&cf->read_cond, NULL); pthread_create(&cf->thread, &attr, (void*(*)(void *)) func, cf); pthread_attr_destroy(&attr); -- 2.11.4.GIT