#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "rthread.h"
#include "cancel.h"
#include "synch.h"
int
pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr)
{
pthread_cond_t cond;
cond = calloc(1, sizeof(*cond));
if (cond == NULL)
return (ENOMEM);
if (attr == NULL)
cond->clock = CLOCK_REALTIME;
else
cond->clock = (*attr)->ca_clock;
*condp = cond;
return (0);
}
DEF_STRONG(pthread_cond_init);
int
pthread_cond_destroy(pthread_cond_t *condp)
{
pthread_cond_t cond;
cond = *condp;
if (cond != NULL) {
if (cond->mutex != NULL) {
#define MSG "pthread_cond_destroy on condvar with waiters!\n"
write(2, MSG, sizeof(MSG) - 1);
#undef MSG
return (EBUSY);
}
free(cond);
}
*condp = NULL;
return (0);
}
int
_rthread_cond_timedwait(pthread_cond_t cond, pthread_mutex_t *mutexp,
const struct timespec *abs)
{
struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp;
struct tib *tib = TIB_GET();
pthread_t self = tib->tib_thread;
int error, rv = 0, canceled = 0, mutex_count = 0;
clockid_t clock = cond->clock;
int seq = cond->seq;
PREP_CANCEL_POINT(tib);
_rthread_debug(5, "%p: cond_timed %p,%p (%p)\n", self,
(void *)cond, (void *)mutex, (void *)mutex->owner);
ENTER_DELAYED_CANCEL_POINT(tib, self);
#if notyet
if (cond->mutex == NULL)
atomic_cas_ptr(&cond->mutex, NULL, mutex);
if (cond->mutex != mutex) {
LEAVE_CANCEL_POINT_INNER(tib, 1);
return (EINVAL);
}
#endif
if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
mutex_count = mutex->count;
pthread_mutex_unlock(mutexp);
do {
error = _twait(&cond->seq, seq, clock, abs);
} while ((error == EINTR) &&
(tib->tib_canceled == 0 || (tib->tib_cantcancel & CANCEL_DISABLED)));
if (error == ETIMEDOUT)
rv = ETIMEDOUT;
else if (error == EINTR)
canceled = 1;
pthread_mutex_lock(mutexp);
if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
mutex->count = mutex_count;
LEAVE_CANCEL_POINT_INNER(tib, canceled);
return rv;
}
int
pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp,
const struct timespec *abs)
{
pthread_cond_t cond;
int error;
if (*condp == NULL) {
if ((error = pthread_cond_init(condp, NULL)))
return (error);
}
cond = *condp;
if (abs == NULL || abs->tv_nsec < 0 || abs->tv_nsec >= 1000000000)
return (EINVAL);
return (_rthread_cond_timedwait(cond, mutexp, abs));
}
int
pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp)
{
pthread_cond_t cond;
int error;
if (*condp == NULL) {
if ((error = pthread_cond_init(condp, NULL)))
return (error);
}
cond = *condp;
return (_rthread_cond_timedwait(cond, mutexp, NULL));
}
int
pthread_cond_signal(pthread_cond_t *condp)
{
pthread_cond_t cond;
int count;
if (*condp == NULL)
return (0);
cond = *condp;
atomic_inc_int(&cond->seq);
count = _wake(&cond->seq, 1);
_rthread_debug(5, "%p: cond_signal %p, %d awaken\n", pthread_self(),
(void *)cond, count);
return (0);
}
int
pthread_cond_broadcast(pthread_cond_t *condp)
{
pthread_cond_t cond;
int count;
if (*condp == NULL)
return (0);
cond = *condp;
atomic_inc_int(&cond->seq);
#if notyet
count = _requeue(&cond->seq, 1, INT_MAX, &cond->mutex->lock);
#else
count = _wake(&cond->seq, INT_MAX);
#endif
_rthread_debug(5, "%p: cond_broadcast %p, %d awaken\n", pthread_self(),
(void *)cond, count);
return (0);
}