Sun May 6 17:05:00 2001 Robert Collins <rbtcollins@hotmail.com>
* thread.h (pthread_cond): New element cond_access to allow atomic broadcasts. * thread.cc (pthread_cond::pthread_cond): Initialise cond_access. (pthread_cond::~pthread_cond): Destroy cond_access. (pthread_cond::Broadcast): Use cond_access. (pthread_cond::Signal): Use cond_access. (pthread_cond_wait): Use cond_access. (pthread_cond_timedwait): Use cond_access.
This commit is contained in:
		| @@ -1,3 +1,12 @@ | |||||||
|  | Sun May  6 17:05:00 2001  Robert Collins <rbtcollins@hotmail.com> | ||||||
|  | 	* thread.h (pthread_cond): New element cond_access to allow atomic broadcasts. | ||||||
|  | 	* thread.cc (pthread_cond::pthread_cond): Initialise cond_access. | ||||||
|  | 	(pthread_cond::~pthread_cond): Destroy cond_access. | ||||||
|  | 	(pthread_cond::Broadcast): Use cond_access. | ||||||
|  | 	(pthread_cond::Signal): Use cond_access. | ||||||
|  | 	(pthread_cond_wait): Use cond_access. | ||||||
|  | 	(pthread_cond_timedwait): Use cond_access. | ||||||
|  |  | ||||||
| Sun May  6 11:55:40 2001  Christopher Faylor <cgf@cygnus.com> | Sun May  6 11:55:40 2001  Christopher Faylor <cgf@cygnus.com> | ||||||
|  |  | ||||||
| 	* string.h (cygwin_strchr): Make 'static inline' so that things will | 	* string.h (cygwin_strchr): Make 'static inline' so that things will | ||||||
|   | |||||||
| @@ -386,6 +386,7 @@ pthread_condattr::~pthread_condattr () | |||||||
|  |  | ||||||
| pthread_cond::pthread_cond (pthread_condattr * attr):verifyable_object (PTHREAD_COND_MAGIC) | pthread_cond::pthread_cond (pthread_condattr * attr):verifyable_object (PTHREAD_COND_MAGIC) | ||||||
| { | { | ||||||
|  |   int temperr; | ||||||
|   this->shared = attr ? attr->shared : PTHREAD_PROCESS_PRIVATE; |   this->shared = attr ? attr->shared : PTHREAD_PROCESS_PRIVATE; | ||||||
|   this->mutex = NULL; |   this->mutex = NULL; | ||||||
|   this->waiting = 0; |   this->waiting = 0; | ||||||
| @@ -393,6 +394,14 @@ pthread_cond::pthread_cond (pthread_condattr * attr):verifyable_object (PTHREAD_ | |||||||
|   this->win32_obj_id =::CreateEvent (&sec_none_nih, false,	/* auto signal reset - which I think is pthreads like ? */ |   this->win32_obj_id =::CreateEvent (&sec_none_nih, false,	/* auto signal reset - which I think is pthreads like ? */ | ||||||
| 				     false,	/* start non signaled */ | 				     false,	/* start non signaled */ | ||||||
| 				     NULL /* no name */); | 				     NULL /* no name */); | ||||||
|  |   /* TODO: make a shared mem mutex if out attributes request shared mem cond */ | ||||||
|  |   cond_access=NULL; | ||||||
|  |   if ((temperr = pthread_mutex_init (&this->cond_access, NULL)))  | ||||||
|  |     { | ||||||
|  |       system_printf ("couldn't init mutex, this %0p errno=%d\n", this, temperr); | ||||||
|  |       /* we need the mutex for correct behaviour */ | ||||||
|  |       magic = 0;	 | ||||||
|  |     } | ||||||
|  |  | ||||||
|   if (!this->win32_obj_id) |   if (!this->win32_obj_id) | ||||||
|     magic = 0; |     magic = 0; | ||||||
| @@ -402,27 +411,38 @@ pthread_cond::~pthread_cond () | |||||||
| { | { | ||||||
|   if (win32_obj_id) |   if (win32_obj_id) | ||||||
|     CloseHandle (win32_obj_id); |     CloseHandle (win32_obj_id); | ||||||
|  |   pthread_mutex_destroy (&cond_access); | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| pthread_cond::BroadCast () | pthread_cond::BroadCast () | ||||||
| { | { | ||||||
|   // This potentially has an unfairness bug. We should |   if (pthread_mutex_lock (&cond_access)) | ||||||
|   // consider preventing the wakeups from resuming until we finish signalling. |     system_printf ("Failed to lock condition variable access mutex, this %0p\n", this); | ||||||
|  |   int count = waiting; | ||||||
|   if (!verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC))  |   if (!verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC))  | ||||||
|  |     { | ||||||
|  |       if (pthread_mutex_unlock (&cond_access)) | ||||||
|  |         system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this); | ||||||
|  |       system_printf ("Broadcast called with invalid mutex\n"); | ||||||
|       return; |       return; | ||||||
|  |     } | ||||||
|  |   while (count--) | ||||||
|     PulseEvent (win32_obj_id); |     PulseEvent (win32_obj_id); | ||||||
|   while (InterlockedDecrement (&waiting) != 0) |   if (pthread_mutex_unlock (&cond_access)) | ||||||
|     PulseEvent (win32_obj_id); |     system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this); | ||||||
|   mutex = NULL; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| pthread_cond::Signal () | pthread_cond::Signal () | ||||||
| { | { | ||||||
|  |   if (pthread_mutex_lock (&cond_access)) | ||||||
|  |     system_printf ("Failed to lock condition variable access mutex, this %0p\n", this); | ||||||
|   if (!verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC)) |   if (!verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC)) | ||||||
|     return; |     return; | ||||||
|   PulseEvent (win32_obj_id); |   PulseEvent (win32_obj_id); | ||||||
|  |   if (pthread_mutex_unlock (&cond_access)) | ||||||
|  |     system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this); | ||||||
| } | } | ||||||
|  |  | ||||||
| int | int | ||||||
| @@ -1608,6 +1628,8 @@ int | |||||||
| __pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, | __pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, | ||||||
| 			  const struct timespec *abstime) | 			  const struct timespec *abstime) | ||||||
| { | { | ||||||
|  | // and yes cond_access here is still open to a race. (we increment, context swap,  | ||||||
|  | // broadcast occurs -  we miss the broadcast. the functions aren't split properly. | ||||||
|   int rv; |   int rv; | ||||||
|   if (!abstime) |   if (!abstime) | ||||||
|     return EINVAL; |     return EINVAL; | ||||||
| @@ -1623,18 +1645,31 @@ __pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, | |||||||
|   if (!verifyable_object_isvalid (*cond, PTHREAD_COND_MAGIC)) |   if (!verifyable_object_isvalid (*cond, PTHREAD_COND_MAGIC)) | ||||||
|     return EINVAL; |     return EINVAL; | ||||||
|  |  | ||||||
|  |   if (pthread_mutex_lock (&(*cond)->cond_access)) | ||||||
|  |     system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond); | ||||||
|  |  | ||||||
|   if ((*cond)->waiting) |   if ((*cond)->waiting) | ||||||
|     if ((*cond)->mutex && ((*cond)->mutex != (*themutex))) |     if ((*cond)->mutex && ((*cond)->mutex != (*themutex))) | ||||||
|  |       { | ||||||
|  |         if (pthread_mutex_unlock (&(*cond)->cond_access)) | ||||||
|  |           system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond); | ||||||
|         return EINVAL; |         return EINVAL; | ||||||
|  |       } | ||||||
|   InterlockedIncrement (&((*cond)->waiting)); |   InterlockedIncrement (&((*cond)->waiting)); | ||||||
|  |  | ||||||
|   (*cond)->mutex = (*themutex); |   (*cond)->mutex = (*themutex); | ||||||
|   InterlockedIncrement (&((*themutex)->condwaits)); |   InterlockedIncrement (&((*themutex)->condwaits)); | ||||||
|  |   if (pthread_mutex_unlock (&(*cond)->cond_access)) | ||||||
|  |     system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond); | ||||||
|   rv = (*cond)->TimedWait (abstime->tv_sec * 1000); |   rv = (*cond)->TimedWait (abstime->tv_sec * 1000); | ||||||
|  |   if (pthread_mutex_lock (&(*cond)->cond_access)) | ||||||
|  |     system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond); | ||||||
|   (*cond)->mutex->Lock (); |   (*cond)->mutex->Lock (); | ||||||
|   if (InterlockedDecrement (&((*cond)->waiting)) == 0) |   if (InterlockedDecrement (&((*cond)->waiting)) == 0) | ||||||
|     (*cond)->mutex = NULL; |     (*cond)->mutex = NULL; | ||||||
|   InterlockedDecrement (&((*themutex)->condwaits)); |   InterlockedDecrement (&((*themutex)->condwaits)); | ||||||
|  |   if (pthread_mutex_unlock (&(*cond)->cond_access)) | ||||||
|  |     system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond); | ||||||
|  |  | ||||||
|   return rv; |   return rv; | ||||||
| } | } | ||||||
| @@ -1642,6 +1677,7 @@ __pthread_cond_timedwait (pthread_cond_t * cond, pthread_mutex_t * mutex, | |||||||
| int | int | ||||||
| __pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex) | __pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex) | ||||||
| { | { | ||||||
|  | // see cond_timedwait for notes | ||||||
|   int rv; |   int rv; | ||||||
|   pthread_mutex_t *themutex = mutex; |   pthread_mutex_t *themutex = mutex; | ||||||
|   if (*mutex == PTHREAD_MUTEX_INITIALIZER) |   if (*mutex == PTHREAD_MUTEX_INITIALIZER) | ||||||
| @@ -1654,19 +1690,31 @@ __pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex) | |||||||
|   if (!verifyable_object_isvalid (*cond, PTHREAD_COND_MAGIC)) |   if (!verifyable_object_isvalid (*cond, PTHREAD_COND_MAGIC)) | ||||||
|     return EINVAL; |     return EINVAL; | ||||||
|  |  | ||||||
|  |   if (pthread_mutex_lock (&(*cond)->cond_access)) | ||||||
|  |     system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond); | ||||||
|  |  | ||||||
|   if ((*cond)->waiting) |   if ((*cond)->waiting) | ||||||
|     if ((*cond)->mutex && ((*cond)->mutex != (*themutex))) |     if ((*cond)->mutex && ((*cond)->mutex != (*themutex))) | ||||||
|  |       { | ||||||
|  |         if (pthread_mutex_unlock (&(*cond)->cond_access)) | ||||||
|  |           system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond); | ||||||
|         return EINVAL; |         return EINVAL; | ||||||
|  |       } | ||||||
|   InterlockedIncrement (&((*cond)->waiting)); |   InterlockedIncrement (&((*cond)->waiting)); | ||||||
|  |  | ||||||
|   (*cond)->mutex = (*themutex); |   (*cond)->mutex = (*themutex); | ||||||
|   InterlockedIncrement (&((*themutex)->condwaits)); |   InterlockedIncrement (&((*themutex)->condwaits)); | ||||||
|  |   if (pthread_mutex_unlock (&(*cond)->cond_access)) | ||||||
|  |     system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond); | ||||||
|   rv = (*cond)->TimedWait (INFINITE); |   rv = (*cond)->TimedWait (INFINITE); | ||||||
|  |   if (pthread_mutex_lock (&(*cond)->cond_access)) | ||||||
|  |     system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond); | ||||||
|   (*cond)->mutex->Lock (); |   (*cond)->mutex->Lock (); | ||||||
|   if (InterlockedDecrement (&((*cond)->waiting)) == 0) |   if (InterlockedDecrement (&((*cond)->waiting)) == 0) | ||||||
|     (*cond)->mutex = NULL; |     (*cond)->mutex = NULL; | ||||||
|   InterlockedDecrement (&((*themutex)->condwaits)); |   InterlockedDecrement (&((*themutex)->condwaits)); | ||||||
|  |   if (pthread_mutex_unlock (&(*cond)->cond_access)) | ||||||
|  |     system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond); | ||||||
|   return rv; |   return rv; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -290,6 +290,8 @@ public: | |||||||
|   int shared; |   int shared; | ||||||
|   LONG waiting; |   LONG waiting; | ||||||
|   pthread_mutex *mutex; |   pthread_mutex *mutex; | ||||||
|  |   /* to allow atomic behaviour for cond_broadcast */ | ||||||
|  |   pthread_mutex_t cond_access; | ||||||
|   HANDLE win32_obj_id; |   HANDLE win32_obj_id; | ||||||
|   int TimedWait (DWORD dwMilliseconds); |   int TimedWait (DWORD dwMilliseconds); | ||||||
|   void BroadCast (); |   void BroadCast (); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user