From 1bd24490937347b6dd227b6a9c3b1aeb7a3fec4d Mon Sep 17 00:00:00 2001 From: bje Date: Fri, 17 Jul 1998 14:25:42 +0000 Subject: 1998-07-18 Ben Elliston * condvar.c (pthread_condattr_init): Do not attempt to malloc any storage; none is needed now that condattr_t is an empty struct. (pthread_condattr_destory): Likewise; do not free storage. (pthread_condattr_setpshared): No longer supported; return ENOSYS. (pthread_condattr_getpshared): Likewise. (pthread_cond_init): Implement with help from Douglas Schmidt. Remember to initialise the cv's internal mutex. (pthread_cond_wait): Likewise. (pthread_cond_signal): Likewise. (pthread_cond_broadcast): Likewise. (pthread_cond_timedwait): Preliminary implementation, but I need to see some API documentation for `WaitForMultipleObject'. (pthread_destory): Implement. --- condvar.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 137 insertions(+), 21 deletions(-) (limited to 'condvar.c') diff --git a/condvar.c b/condvar.c index bcda8cb..e8f858c 100644 --- a/condvar.c +++ b/condvar.c @@ -10,56 +10,172 @@ int pthread_condattr_init(pthread_condattr_t *attr) { - if (attr == NULL) + return (attr == NULL) ? EINVAL : 0; +} + +int +pthread_condattr_destroy(pthread_condattr_t *attr) +{ + return (attr == NULL) ? EINVAL : 0; +} + +int +pthread_condattr_setpshared(pthread_condattr_t *attr, + int pshared) +{ + return (attr == NULL) ? EINVAL : ENOSYS; +} + +int +pthread_condattr_getpshared(pthread_condattr_t *attr, + int *pshared) +{ + return (attr == NULL) ? EINVAL : ENOSYS; +} + +int +pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *attr) +{ + /* Ensure we have a valid cond_t variable. */ + if (cv == NULL) + { + return EINVAL; + } + + /* Initialize the count to 0. */ + cv->waiters_count = 0; + + /* Initialize the "mutex". */ + pthread_mutex_init(cv->waiters_count_lock); + + /* Create an auto-reset event. */ + cv->events[SIGNAL] = CreateEvent (NULL, /* no security */ + FALSE, /* auto-reset event */ + FALSE, /* non-signaled initially */ + NULL); /* unnamed */ + + /* Create a manual-reset event. */ + cv->events[BROADCAST] = CreateEvent (NULL, /* no security */ + TRUE, /* manual-reset */ + FALSE, /* non-signaled initially */ + NULL); /* unnamed */ + + return 0; +} + +int +pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) +{ + int result, last_waiter; + + /* Ensure we have a valid cond_t variable. */ + if (cv == NULL) { - /* This is disallowed. */ return EINVAL; } - attr->ptr = malloc(sizeof(_pthread_condattr_t)); - if (attr->ptr == NULL) + /* Avoid race conditions. */ + EnterCriticalSection (&cv->waiters_count_lock); + cv->waiters_count_++; + LeaveCriticalSection (&cv->waiters_count_lock); + + /* It's okay to release the mutex here since Win32 manual-reset + events maintain state when used with SetEvent(). This avoids the + "lost wakeup" bug. */ + + pthread_mutex_unlock(mutex); + + /* Wait for either event to become signaled due to + pthread_cond_signal() being called or pthread_cond_broadcast() + being called. */ + + result = WaitForMultipleObjects (2, ev->events, FALSE, INFINITE); + + EnterCriticalSection (&cv->waiters_count_lock); + cv->waiters_count--; + last_waiter = cv->waiters_count == 0; + LeaveCriticalSection (&cv->waiters_count_lock); + + /* Some thread called pthread_cond_broadcast(). */ + if ((result = WAIT_OBJECT_0 + BROADCAST) && last_waiter) { - return ENOMEM; + /* We're the last waiter to be notified, so reset the manual + event. */ + ResetEvent(cv->events[BROADCAST]); } - /* FIXME: fill out the structure with default values. */ + /* Reacquire the mutex. */ + pthread_mutex_lock(mutex); + return 0; } int -pthread_condattr_destroy(pthread_condattr_t *attr) +pthread_cond_timedwait(pthread_cond_t *cv, + pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + /* Yet to be implemented. This will be identical to cond_wait(), + but we will need to get the timeout parameter in the call to + WaitForMultipleObject() as close to the time specified in + `abstime' as possible. */ + + return 0; +} + +int +pthread_cond_broadcast (pthread_cond_t *cv) { - if (is_attr(attr) != 0) + int have_waiters; + + /* Ensure we have a valid cond_t variable. */ + if (cv == NULL) { return EINVAL; } - - free(attr->ptr); + + /* Avoid race conditions. */ + EnterCriticalSection (&cv->waiters_count_lock_); + have_waiters = (cv->waiters_count > 0); + LeaveCriticalSection (&cv->waiters_count_lock_); + + if (have_waiters) { + SetEvent(cv->events[BROADCAST]); + } + return 0; } -int -pthread_condattr_setpshared(pthread_condattr_t *attr, - int pshared) +int +pthread_cond_signal (pthread_cond_t *cv) { - if (is_attr(attr) != 0) + int have_waiters; + + /* Ensure we have a valid cond_t variable. */ + if (cv == NULL) { return EINVAL; } - (_pthread_condattr_t *) (attr->ptr)->pshared = pshared; + /* Avoid race conditions. */ + EnterCriticalSection (&cv->waiters_count_lock); + have_waiters = (cv->waiters_count > 0); + LeaveCriticalSection (&cv->waiters_count_lock); + + if (have_waiters) { + SetEvent(cv->events[SIGNAL]); + } + return 0; } int -pthread_condattr_getpshared(pthread_condattr_t *attr, - int *pshared) +pthread_cond_destroy(pthread_cond_t *cv) { - if (is_attr(attr) != 0) + if (cv == NULL) { - return EINVAL; + return EINVAL; } - *pshared = (_pthread_condattr_t *) (attr->ptr)->pshared; - return 0; + return pthread_mutex_destroy(cv->waiters_count_lock); } -- cgit v1.2.3