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
parent
ef64aa4940
commit
813da84442
@@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user