mirror of
https://salsa.debian.org/ha-team/libqb
synced 2026-01-26 02:16:14 +00:00
don't block completely on the sem_wait(), but chop the waits into 1 sec blocks so the destroy can have an opertunity to complete. fixes bug #55 Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
215 lines
4.2 KiB
C
215 lines
4.2 KiB
C
/*
|
|
* 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 <asalkeld@redhat.com>
|
|
* 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 <pthread.h>
|
|
#include "rpl_sem.h"
|
|
#include <qb/qbdefs.h>
|
|
#include <qb/qbutil.h>
|
|
|
|
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);
|
|
if (rc != 0) {
|
|
goto cleanup;
|
|
}
|
|
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;
|
|
}
|
|
|
|
static int
|
|
_rpl_sem_timedwait(rpl_sem_t * sem, const struct timespec *timeout)
|
|
{
|
|
int retval = pthread_mutex_lock(&sem->mutex);
|
|
if (retval != 0) {
|
|
return -errno;
|
|
}
|
|
if (sem->destroy_request) {
|
|
retval = -EINVAL;
|
|
goto unlock_it;
|
|
}
|
|
|
|
/* wait for sem->count to be not zero, or error
|
|
*/
|
|
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:
|
|
break;
|
|
}
|
|
|
|
unlock_it:
|
|
pthread_mutex_unlock(&sem->mutex);
|
|
return retval;
|
|
}
|
|
|
|
int
|
|
rpl_sem_wait(rpl_sem_t * sem)
|
|
{
|
|
|
|
struct timespec ts_timeout;
|
|
int32_t rc;
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
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)
|
|
{
|
|
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;
|
|
}
|