POSIX barrier implementation, take 3
The attached patch should address all of the review comments. Modifed change log: Newlib: * libc/include/sys/features.h (_POSIX_BARRIERS): Define for Cygwin. * libc/include/sys/types.h (pthread_barrier_t) (pthread_barrierattr_t): Do not define for Cygwin. Cygwin: * common.din (pthread_barrierattr_init) (pthread_barrierattr_setpshared, pthread_barrierattr_getpshared) (pthread_barrierattr_destroy, pthread_barrier_init) (pthread_barrier_destroy, pthread_barrier_wait): Export. * include/cygwin/types.h (pthread_barrierattr_t) (pthread_barrier_t): Declare. * include/pthread.h (PTHREAD_BARRIER_SERIAL_THREAD) (pthread_barrierattr_init, pthread_barrierattr_setpshared) (pthread_barrierattr_getpshared, pthread_barrierattr_destroy) (pthread_barrier_init, pthread_barrier_destroy) (pthread_barrier_wait): Declare. * thread.h (PTHREAD_BARRIER_MAGIC) (PTHREAD_BARRIERATTR_MAGIC): Define. (class pthread_barrierattr, class pthread_barrier): Declare. * thread.cc (delete_and_clear): New local helper function. (class pthread_barrierattr, class pthread_barrier): Implement. * miscfuncs.h (likely, unlikely): New macros. -- VH
This commit is contained in:
		
				
					committed by
					
						 Corinna Vinschen
						Corinna Vinschen
					
				
			
			
				
	
			
			
			
						parent
						
							ef64aa4940
						
					
				
				
					commit
					813da84442
				
			| @@ -118,10 +118,10 @@ extern "C" { | ||||
|  | ||||
| #define _POSIX_ADVISORY_INFO			200112L | ||||
| /* #define _POSIX_ASYNCHRONOUS_IO		    -1 */ | ||||
| /* #define _POSIX_BARRIERS			    -1 */ | ||||
| #define _POSIX_BARRIERS				200112L | ||||
| #define _POSIX_CHOWN_RESTRICTED			     1 | ||||
| #define _POSIX_CLOCK_SELECTION			200112L | ||||
| #define _POSIX_CPUTIME			    	200112L | ||||
| #define _POSIX_CPUTIME				200112L | ||||
| #define _POSIX_FSYNC				200112L | ||||
| #define _POSIX_IPV6				200112L | ||||
| #define _POSIX_JOB_CONTROL			     1 | ||||
|   | ||||
| @@ -431,6 +431,7 @@ typedef struct { | ||||
|  | ||||
| /* POSIX Barrier Types */ | ||||
|  | ||||
| #if !defined(__CYGWIN__) | ||||
| #if defined(_POSIX_BARRIERS) | ||||
| typedef __uint32_t pthread_barrier_t;        /* POSIX Barrier Object */ | ||||
| typedef struct { | ||||
| @@ -443,7 +444,6 @@ typedef struct { | ||||
|  | ||||
| /* POSIX Spin Lock Types */ | ||||
|  | ||||
| #if !defined (__CYGWIN__) | ||||
| #if defined(_POSIX_SPIN_LOCKS) | ||||
| typedef __uint32_t pthread_spinlock_t;        /* POSIX Spin Lock Object */ | ||||
| #endif /* defined(_POSIX_SPIN_LOCKS) */ | ||||
|   | ||||
| @@ -869,6 +869,13 @@ pthread_attr_setscope SIGFE | ||||
| pthread_attr_setstack SIGFE | ||||
| pthread_attr_setstackaddr SIGFE | ||||
| pthread_attr_setstacksize SIGFE | ||||
| pthread_barrierattr_init SIGFE | ||||
| pthread_barrierattr_setpshared SIGFE | ||||
| pthread_barrierattr_getpshared SIGFE | ||||
| pthread_barrierattr_destroy SIGFE | ||||
| pthread_barrier_init SIGFE | ||||
| pthread_barrier_destroy SIGFE | ||||
| pthread_barrier_wait SIGFE | ||||
| pthread_cancel SIGFE | ||||
| pthread_cond_broadcast SIGFE | ||||
| pthread_cond_destroy SIGFE | ||||
|   | ||||
| @@ -184,6 +184,8 @@ typedef struct __pthread_attr_t {char __dummy;} *pthread_attr_t; | ||||
| typedef struct __pthread_mutexattr_t {char __dummy;} *pthread_mutexattr_t; | ||||
| typedef struct __pthread_condattr_t {char __dummy;} *pthread_condattr_t; | ||||
| typedef struct __pthread_cond_t {char __dummy;} *pthread_cond_t; | ||||
| typedef struct __pthread_barrierattr_t {char __dummy;} *pthread_barrierattr_t; | ||||
| typedef struct __pthread_barrier_t {char __dummy;} *pthread_barrier_t; | ||||
|  | ||||
|   /* These variables are not user alterable. This means you!. */ | ||||
| typedef struct | ||||
| @@ -207,6 +209,8 @@ typedef class pthread_attr *pthread_attr_t; | ||||
| typedef class pthread_mutexattr *pthread_mutexattr_t; | ||||
| typedef class pthread_condattr *pthread_condattr_t; | ||||
| typedef class pthread_cond *pthread_cond_t; | ||||
| typedef class pthread_barrier *pthread_barrier_t; | ||||
| typedef class pthread_barrierattr *pthread_barrierattr_t; | ||||
| typedef class pthread_once pthread_once_t; | ||||
| typedef class pthread_spinlock *pthread_spinlock_t; | ||||
| typedef class pthread_rwlock *pthread_rwlock_t; | ||||
|   | ||||
| @@ -62,6 +62,7 @@ extern "C" | ||||
| /* process is the default */ | ||||
| #define PTHREAD_SCOPE_PROCESS 0 | ||||
| #define PTHREAD_SCOPE_SYSTEM 1 | ||||
| #define PTHREAD_BARRIER_SERIAL_THREAD (-1) | ||||
|  | ||||
| /* Register Fork Handlers */ | ||||
| int pthread_atfork (void (*)(void), void (*)(void), void (*)(void)); | ||||
| @@ -133,6 +134,17 @@ int pthread_condattr_init (pthread_condattr_t *); | ||||
| int pthread_condattr_setclock (pthread_condattr_t *, clockid_t); | ||||
| int pthread_condattr_setpshared (pthread_condattr_t *, int); | ||||
|  | ||||
| /* Barriers */ | ||||
| int pthread_barrierattr_init (pthread_barrierattr_t *); | ||||
| int pthread_barrierattr_setpshared (pthread_barrierattr_t *, int); | ||||
| int pthread_barrierattr_getpshared (const pthread_barrierattr_t *, int *); | ||||
| int pthread_barrierattr_destroy (pthread_barrierattr_t *); | ||||
| int pthread_barrier_init (pthread_barrier_t *, | ||||
|                           const pthread_barrierattr_t *, unsigned); | ||||
| int pthread_barrier_destroy (pthread_barrier_t *); | ||||
| int pthread_barrier_wait (pthread_barrier_t *); | ||||
|  | ||||
| /* Threads */ | ||||
| int pthread_create (pthread_t *, const pthread_attr_t *, | ||||
| 		    void *(*)(void *), void *); | ||||
| int pthread_detach (pthread_t); | ||||
|   | ||||
| @@ -11,6 +11,10 @@ details. */ | ||||
|  | ||||
| #ifndef _MISCFUNCS_H | ||||
| #define _MISCFUNCS_H | ||||
|  | ||||
| #define likely(X) __builtin_expect (!!(X), 1) | ||||
| #define unlikely(X) __builtin_expect (!!(X), 0) | ||||
|  | ||||
| int __reg1 winprio_to_nice (DWORD); | ||||
| DWORD __reg1 nice_to_winprio (int &); | ||||
|  | ||||
|   | ||||
| @@ -50,6 +50,17 @@ const pthread_t pthread_mutex::_new_mutex = (pthread_t) 1; | ||||
| const pthread_t pthread_mutex::_unlocked_mutex = (pthread_t) 2; | ||||
| const pthread_t pthread_mutex::_destroyed_mutex = (pthread_t) 3; | ||||
|  | ||||
|  | ||||
| template <typename T> | ||||
| static inline | ||||
| void | ||||
| delete_and_clear (T * * const ptr) | ||||
| { | ||||
|   delete *ptr; | ||||
|   *ptr = 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| inline bool | ||||
| pthread_mutex::no_owner() | ||||
| { | ||||
| @@ -267,6 +278,23 @@ pthread_cond::is_initializer_or_object (pthread_cond_t const *cond) | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool | ||||
| pthread_barrierattr::is_good_object (pthread_barrierattr_t const *cond) | ||||
| { | ||||
|   if (verifyable_object_isvalid (cond, PTHREAD_BARRIERATTR_MAGIC) | ||||
|       != VALID_OBJECT) | ||||
|     return false; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| inline bool | ||||
| pthread_barrier::is_good_object (pthread_barrier_t const *cond) | ||||
| { | ||||
|   if (verifyable_object_isvalid (cond, PTHREAD_BARRIER_MAGIC) != VALID_OBJECT) | ||||
|     return false; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| /* RW locks */ | ||||
| inline bool | ||||
| pthread_rwlock::is_good_object (pthread_rwlock_t const *rwlock) | ||||
| @@ -1300,6 +1328,25 @@ pthread_cond::_fixup_after_fork () | ||||
|     api_fatal ("pthread_cond::_fixup_after_fork () failed to recreate win32 semaphore"); | ||||
| } | ||||
|  | ||||
| pthread_barrierattr::pthread_barrierattr () | ||||
|   : verifyable_object (PTHREAD_BARRIERATTR_MAGIC) | ||||
|   , shared (PTHREAD_PROCESS_PRIVATE) | ||||
| { | ||||
| } | ||||
|  | ||||
| pthread_barrierattr::~pthread_barrierattr () | ||||
| { | ||||
| } | ||||
|  | ||||
| pthread_barrier::pthread_barrier () | ||||
|   : verifyable_object (PTHREAD_BARRIER_MAGIC) | ||||
| { | ||||
| } | ||||
|  | ||||
| pthread_barrier::~pthread_barrier () | ||||
| { | ||||
| } | ||||
|  | ||||
| pthread_rwlockattr::pthread_rwlockattr ():verifyable_object | ||||
|   (PTHREAD_RWLOCKATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE) | ||||
| { | ||||
| @@ -3869,3 +3916,218 @@ pthread_null::getsequence_np () | ||||
| } | ||||
|  | ||||
| pthread_null pthread_null::_instance; | ||||
|  | ||||
|  | ||||
| extern "C" | ||||
| int | ||||
| pthread_barrierattr_init (pthread_barrierattr_t * battr) | ||||
| { | ||||
|   if (unlikely (battr == NULL)) | ||||
|     return EINVAL; | ||||
|  | ||||
|   *battr = new pthread_barrierattr; | ||||
|   (*battr)->shared = PTHREAD_PROCESS_PRIVATE; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| extern "C" | ||||
| int | ||||
| pthread_barrierattr_setpshared (pthread_barrierattr_t * battr, int shared) | ||||
| { | ||||
|   if (unlikely (! pthread_barrierattr::is_good_object (battr))) | ||||
|     return EINVAL; | ||||
|  | ||||
|   if (unlikely (shared != PTHREAD_PROCESS_SHARED | ||||
|                 && shared != PTHREAD_PROCESS_PRIVATE)) | ||||
|     return EINVAL; | ||||
|  | ||||
|   (*battr)->shared = shared; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| extern "C" | ||||
| int | ||||
| pthread_barrierattr_getpshared (const pthread_barrierattr_t * battr, | ||||
|                                 int * shared) | ||||
| { | ||||
|   if (unlikely (! pthread_barrierattr::is_good_object (battr) | ||||
|                 || shared == NULL)) | ||||
|     return EINVAL; | ||||
|  | ||||
|   *shared = (*battr)->shared; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| extern "C" | ||||
| int | ||||
| pthread_barrierattr_destroy (pthread_barrierattr_t * battr) | ||||
| { | ||||
|   if (unlikely (! pthread_barrierattr::is_good_object (battr))) | ||||
|     return EINVAL; | ||||
|  | ||||
|   delete_and_clear (battr); | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| extern "C" | ||||
| int | ||||
| pthread_barrier_init (pthread_barrier_t * bar, | ||||
|                       const pthread_barrierattr_t * attr, unsigned count) | ||||
| { | ||||
|   if (unlikely (bar == NULL)) | ||||
|     return EINVAL; | ||||
|  | ||||
|   *bar = new pthread_barrier; | ||||
|   return (*bar)->init (attr, count); | ||||
| } | ||||
|  | ||||
|  | ||||
| int | ||||
| pthread_barrier::init (const pthread_barrierattr_t * attr, unsigned count) | ||||
| { | ||||
|   pthread_mutex_t * mutex = NULL; | ||||
|  | ||||
|   if (unlikely ((attr != NULL | ||||
|                  && (! pthread_barrierattr::is_good_object (attr) | ||||
|                      || (*attr)->shared == PTHREAD_PROCESS_SHARED)) | ||||
|                 || count == 0)) | ||||
|     return EINVAL; | ||||
|  | ||||
|   int retval = pthread_mutex_init (&mtx, NULL); | ||||
|   if (unlikely (retval != 0)) | ||||
|     return retval; | ||||
|  | ||||
|   retval = pthread_cond_init (&cond, NULL); | ||||
|   if (unlikely (retval != 0)) | ||||
|     { | ||||
|       int ret = pthread_mutex_destroy (mutex); | ||||
|       if (ret != 0) | ||||
|         api_fatal ("pthread_mutex_destroy (%p) = %d", mutex, ret); | ||||
|  | ||||
|       mtx = NULL; | ||||
|       return retval; | ||||
|     } | ||||
|  | ||||
|   cnt = count; | ||||
|   cyc = 0; | ||||
|   wt = 0; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| extern "C" | ||||
| int | ||||
| pthread_barrier_destroy (pthread_barrier_t * bar) | ||||
| { | ||||
|   if (unlikely (! pthread_barrier::is_good_object (bar))) | ||||
|     return EINVAL; | ||||
|  | ||||
|   int ret; | ||||
|   ret = (*bar)->destroy (); | ||||
|   if (ret == 0) | ||||
|     delete_and_clear (bar); | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
|  | ||||
| int | ||||
| pthread_barrier::destroy () | ||||
| { | ||||
|   if (unlikely (wt != 0)) | ||||
|     return EBUSY; | ||||
|  | ||||
|   int retval = pthread_cond_destroy (&cond); | ||||
|   if (unlikely (retval != 0)) | ||||
|     return retval; | ||||
|   else | ||||
|     cond = NULL; | ||||
|  | ||||
|   retval = pthread_mutex_destroy (&mtx); | ||||
|   if (unlikely (retval != 0)) | ||||
|     return retval; | ||||
|   else | ||||
|     mtx = NULL; | ||||
|  | ||||
|   cnt = 0; | ||||
|   cyc = 0; | ||||
|   wt = 0; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| extern "C" | ||||
| int | ||||
| pthread_barrier_wait (pthread_barrier_t * bar) | ||||
| { | ||||
|   if (unlikely (! pthread_barrier::is_good_object (bar))) | ||||
|     return EINVAL; | ||||
|  | ||||
|   return (*bar)->wait (); | ||||
| } | ||||
|  | ||||
|  | ||||
| int | ||||
| pthread_barrier::wait () | ||||
| { | ||||
|   int retval = pthread_mutex_lock (&mtx); | ||||
|   if (unlikely (retval != 0)) | ||||
|     return retval; | ||||
|  | ||||
|   if (unlikely (wt >= cnt)) | ||||
|     { | ||||
|       api_fatal ("wt >= cnt (%u >= %u)", wt, cnt); | ||||
|       return EINVAL; | ||||
|     } | ||||
|  | ||||
|   if (unlikely (++wt == cnt)) | ||||
|     { | ||||
|       ++cyc; | ||||
|       /* This is the last thread to reach the barrier. Signal the waiting | ||||
|          threads to wake up and continue.  */ | ||||
|       retval = pthread_cond_broadcast (&cond); | ||||
|       if (unlikely (retval != 0)) | ||||
|         goto cond_error; | ||||
|  | ||||
|       wt = 0; | ||||
|       retval = pthread_mutex_unlock (&mtx); | ||||
|       if (unlikely (retval != 0)) | ||||
|         abort (); | ||||
|  | ||||
|       return PTHREAD_BARRIER_SERIAL_THREAD; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       uint64_t cycle = cyc; | ||||
|       do | ||||
|         { | ||||
|           retval = pthread_cond_wait (&cond, &mtx); | ||||
|           if (unlikely (retval != 0)) | ||||
|             goto cond_error; | ||||
|         } | ||||
|       while (unlikely (cycle == cyc)); | ||||
|  | ||||
|       retval = pthread_mutex_unlock (&mtx); | ||||
|       if (unlikely (retval != 0)) | ||||
|         api_fatal ("pthread_mutex_unlock (%p) = %d", &mtx, retval); | ||||
|  | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|  cond_error: | ||||
|   { | ||||
|     --wt; | ||||
|     int ret = pthread_mutex_unlock (&mtx); | ||||
|     if (unlikely (ret != 0)) | ||||
|         api_fatal ("pthread_mutex_unlock (%p) = %d", &mtx, ret); | ||||
|  | ||||
|     return retval; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| // -*- C++ -*- | ||||
| /* thread.h: Locking and threading module definitions | ||||
|  | ||||
|    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, | ||||
| @@ -84,6 +85,8 @@ class pinfo; | ||||
| #define PTHREAD_RWLOCK_MAGIC PTHREAD_MAGIC+9 | ||||
| #define PTHREAD_RWLOCKATTR_MAGIC PTHREAD_MAGIC+10 | ||||
| #define PTHREAD_SPINLOCK_MAGIC PTHREAD_MAGIC+11 | ||||
| #define PTHREAD_BARRIER_MAGIC PTHREAD_MAGIC+12 | ||||
| #define PTHREAD_BARRIERATTR_MAGIC PTHREAD_MAGIC+13 | ||||
|  | ||||
| #define MUTEX_OWNER_ANONYMOUS ((pthread_t) -1) | ||||
|  | ||||
| @@ -520,6 +523,38 @@ private: | ||||
|   static fast_mutex cond_initialization_lock; | ||||
| }; | ||||
|  | ||||
|  | ||||
| class pthread_barrierattr: public verifyable_object | ||||
| { | ||||
| public: | ||||
|   static bool is_good_object(pthread_barrierattr_t const *); | ||||
|   int shared; | ||||
|  | ||||
|   pthread_barrierattr (); | ||||
|   ~pthread_barrierattr (); | ||||
| }; | ||||
|  | ||||
|  | ||||
| class pthread_barrier: public verifyable_object | ||||
| { | ||||
| public: | ||||
|   static bool is_good_object(pthread_barrier_t const *); | ||||
|  | ||||
|   pthread_mutex_t mtx; /* Mutex protecting everything below. */ | ||||
|   pthread_cond_t cond; /* Conditional variable to wait on. */ | ||||
|   unsigned cnt; /* Barrier count. Threads to wait for. */ | ||||
|   uint64_t cyc; /* Cycle count. */ | ||||
|   unsigned wt; /* Already waiting threads count. */ | ||||
|  | ||||
|   int init (const pthread_barrierattr_t *, unsigned); | ||||
|   int wait(); | ||||
|   int destroy (); | ||||
|  | ||||
|   pthread_barrier (); | ||||
|   ~pthread_barrier (); | ||||
| }; | ||||
|  | ||||
|  | ||||
| class pthread_rwlockattr: public verifyable_object | ||||
| { | ||||
| public: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user