diff options
author | bje <bje> | 1998-07-17 14:25:42 +0000 |
---|---|---|
committer | bje <bje> | 1998-07-17 14:25:42 +0000 |
commit | 1bd24490937347b6dd227b6a9c3b1aeb7a3fec4d (patch) | |
tree | 7a37aaabee85b7b4331baa380d9f2798fc3dad92 /condvar.c | |
parent | bac0be47a6821c2e9fde1e051a1a529153b44175 (diff) |
1998-07-18 Ben Elliston <bje@cygnus.com>
* 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.
Diffstat (limited to 'condvar.c')
-rw-r--r-- | condvar.c | 158 |
1 files changed, 137 insertions, 21 deletions
@@ -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); } |