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 | |
| 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.
| -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);  } | 
