diff --git a/lib/rpl_sem.c b/lib/rpl_sem.c index 37cc830..7daeb4f 100644 --- a/lib/rpl_sem.c +++ b/lib/rpl_sem.c @@ -1,190 +1,214 @@ /* * Copyright (C) 2007 Pingtel Corp., certain elements licensed under a Contributor Agreement. * Contributors retain copyright to elements licensed under a Contributor Agreement. * Licensed to the User under the LGPL license. * * Modified by: Angus Salkeld * Copyright (C) 2012 Red Hat, Inc. * To conform to posix API and support process shared semaphores. * * The bsd posix semaphore implementation does not have support for timing * out while waiting for a synchronization object. This uses the * pthread_cond_timedwait function and a mutex to build all the other * synchronization objecs with timeout capabilities. */ #include "os_base.h" #include #include "rpl_sem.h" +#include +#include int rpl_sem_init(rpl_sem_t * sem, int pshared, unsigned int count) { int rc; pthread_mutexattr_t mattr; pthread_condattr_t cattr; #ifndef HAVE_RPL_PSHARED_SEMAPHORE if (pshared) { errno = ENOSYS; return -1; } #endif /* HAVE_RPL_PSHARED_SEMAPHORE */ sem->count = count; + sem->destroy_request = QB_FALSE; (void)pthread_mutexattr_init(&mattr); (void)pthread_condattr_init(&cattr); #ifdef HAVE_RPL_PSHARED_SEMAPHORE if (pshared) { - rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED); + rc = pthread_mutexattr_setpshared(&mattr, + PTHREAD_PROCESS_SHARED); if (rc != 0) { goto cleanup; } - rc = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED); + rc = pthread_condattr_setpshared(&cattr, + PTHREAD_PROCESS_SHARED); if (rc != 0) { goto cleanup; } } #endif /* HAVE_RPL_PSHARED_SEMAPHORE */ rc = pthread_mutex_init(&sem->mutex, &mattr); if (rc != 0) { goto cleanup; } rc = pthread_cond_init(&sem->cond, &cattr); if (rc != 0) { goto cleanup_mutex; } return 0; cleanup_mutex: pthread_mutex_destroy(&sem->mutex); cleanup: pthread_mutexattr_destroy(&mattr); pthread_condattr_destroy(&cattr); return rc; } -int -rpl_sem_wait(rpl_sem_t * sem) +static int +_rpl_sem_timedwait(rpl_sem_t * sem, const struct timespec *timeout) { int retval = pthread_mutex_lock(&sem->mutex); if (retval != 0) { - errno = retval; - return -1; + return -errno; + } + if (sem->destroy_request) { + retval = -EINVAL; + goto unlock_it; } /* wait for sem->count to be not zero, or error */ - while (retval == 0 && !sem->count) { - retval = pthread_cond_wait(&sem->cond, &sem->mutex); + while (0 == retval && !sem->count) { + retval = -pthread_cond_timedwait(&sem->cond, + &sem->mutex, timeout); } + if (sem->destroy_request) { + retval = -EINVAL; + goto unlock_it; + } + switch (retval) { case 0: /* retval is 0 and sem->count is not, the sem is ours */ sem->count--; break; + case ETIMEDOUT: + /* timedout waiting for count to be not zero + */ + retval = -EAGAIN; + break; + default: - errno = retval; - retval = -1; + break; } +unlock_it: pthread_mutex_unlock(&sem->mutex); return retval; } int -rpl_sem_timedwait(rpl_sem_t * sem, const struct timespec *timeout) +rpl_sem_wait(rpl_sem_t * sem) { - int retval = pthread_mutex_lock(&sem->mutex); - if (retval != 0) { - errno = retval; - return -1; - } - /* wait for sem->count to be not zero, or error - */ - while (0 == retval && !sem->count) { - retval = pthread_cond_timedwait(&sem->cond, &sem->mutex, timeout); - } + struct timespec ts_timeout; + int32_t rc; - switch (retval) { - case 0: - /* retval is 0 and sem->count is not, the sem is ours - */ - sem->count--; - break; - - case ETIMEDOUT: - /* timedout waiting for count to be not zero - */ - errno = EAGAIN; - retval = -1; - break; + do { + qb_util_timespec_from_epoch_get(&ts_timeout); + qb_timespec_add_ms(&ts_timeout, 1000); + rc = _rpl_sem_timedwait(sem, &ts_timeout); + } while (rc == -EAGAIN); + if (rc < 0) { + errno = -rc; + return -1; + } + return 0; +} - default: - errno = retval; - retval = -1; +int +rpl_sem_timedwait(rpl_sem_t * sem, const struct timespec *timeout) +{ + int rc = _rpl_sem_timedwait(sem, timeout); + if (rc < 0) { + errno = -rc; + return -1; } - pthread_mutex_unlock(&sem->mutex); - return retval; + return 0; } int rpl_sem_trywait(rpl_sem_t * sem) { int retval = pthread_mutex_lock(&sem->mutex); if (retval != 0) { errno = retval; return -1; } if (sem->count) { sem->count--; pthread_mutex_unlock(&sem->mutex); return 0; } errno = EAGAIN; pthread_mutex_unlock(&sem->mutex); return -1; } int rpl_sem_post(rpl_sem_t * sem) { int retval = pthread_mutex_lock(&sem->mutex); if (retval != 0) { errno = retval; return -1; } sem->count++; retval = pthread_cond_broadcast(&sem->cond); pthread_mutex_unlock(&sem->mutex); if (retval != 0) { errno = retval; return -1; } return 0; } int rpl_sem_getvalue(rpl_sem_t * sem, int *sval) { int retval = pthread_mutex_lock(&sem->mutex); if (retval != 0) { errno = retval; return -1; } *sval = sem->count; pthread_mutex_unlock(&sem->mutex); return 0; } int rpl_sem_destroy(rpl_sem_t * sem) { - return pthread_mutex_destroy(&sem->mutex) | - pthread_cond_destroy(&sem->cond); + int retval = pthread_mutex_lock(&sem->mutex); + if (retval != 0) { + errno = retval; + return -1; + } + sem->destroy_request = QB_TRUE; + pthread_mutex_unlock(&sem->mutex); + (void)pthread_cond_broadcast(&sem->cond); + + (void)pthread_cond_destroy(&sem->cond); + (void)pthread_mutex_destroy(&sem->mutex); + + return 0; } diff --git a/lib/rpl_sem.h b/lib/rpl_sem.h index 23724e4..fb8005e 100644 --- a/lib/rpl_sem.h +++ b/lib/rpl_sem.h @@ -1,64 +1,64 @@ /* * Copyright (C) 2007 Pingtel Corp., certain elements licensed under a Contributor Agreement. * Contributors retain copyright to elements licensed under a Contributor Agreement. * Licensed to the User under the LGPL license. * * Modified by: Angus Salkeld * Copyright (C) 2012 Red Hat, Inc. * To conform to official implementation and support process shared semaphores. * * The bsd posix semaphore implementation does not have support for timing * out while waiting for a synchronization object. This uses the * pthread_cond_timedwait function and a mutex to build all the other * synchronization objecs with timeout capabilities. */ #ifndef _RPL_SEM_H #define _RPL_SEM_H #include "os_base.h" #include #include #ifdef __cplusplus extern "C" { #endif #ifdef HAVE_SEM_TIMEDWAIT #define rpl_sem_t sem_t #define rpl_sem_init sem_init #define rpl_sem_wait sem_wait #define rpl_sem_timedwait sem_timedwait #define rpl_sem_post sem_post #define rpl_sem_getvalue sem_getvalue #define rpl_sem_destroy sem_destroy #define rpl_sem_trywait sem_trywait #else typedef struct rpl_sem { - unsigned int count; - pthread_mutex_t mutex; - pthread_cond_t cond; + unsigned int count; + uint32_t destroy_request; + pthread_mutex_t mutex; + pthread_cond_t cond; } rpl_sem_t; int rpl_sem_init(rpl_sem_t * sem, int pshared, unsigned int count); -int rpl_sem_wait(rpl_sem_t *sem); +int rpl_sem_wait(rpl_sem_t * sem); -int rpl_sem_timedwait(rpl_sem_t *sem,const struct timespec *timeout); +int rpl_sem_timedwait(rpl_sem_t * sem, const struct timespec *timeout); -int rpl_sem_trywait(rpl_sem_t *sem); +int rpl_sem_trywait(rpl_sem_t * sem); -int rpl_sem_post(rpl_sem_t *sem); +int rpl_sem_post(rpl_sem_t * sem); int rpl_sem_getvalue(rpl_sem_t * sem, int *sval); -int rpl_sem_destroy(rpl_sem_t *sem); +int rpl_sem_destroy(rpl_sem_t * sem); #endif /* HAVE_SEM_TIMEDWAIT */ #ifdef __cplusplus } #endif - #endif /* _RPL_SEM_H */