Track mutex/rwlock/condvar status. This allows us to get rid of

the pthread_np calls which will not likely exist on other platforms.
This commit is contained in:
pooka 2009-01-10 22:28:42 +00:00
parent f8474b32a7
commit a25e3b17bc
1 changed files with 111 additions and 14 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rumpuser_pth.c,v 1.23 2009/01/07 22:50:08 pooka Exp $ */
/* $NetBSD: rumpuser_pth.c,v 1.24 2009/01/10 22:28:42 pooka Exp $ */
/*
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
@ -30,7 +30,7 @@
#include <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: rumpuser_pth.c,v 1.23 2009/01/07 22:50:08 pooka Exp $");
__RCSID("$NetBSD: rumpuser_pth.c,v 1.24 2009/01/10 22:28:42 pooka Exp $");
#endif /* !lint */
#ifdef __linux__
@ -65,16 +65,51 @@ do { \
} \
} while (/*CONSTCOND*/0)
#define RUMTX_INCRECURSION(mtx) ((mtx)->recursion++)
#define RUMTX_DECRECURSION(mtx) ((mtx)->recursion--)
struct rumpuser_mtx {
pthread_mutex_t pthmtx;
pthread_t owner;
unsigned recursion;
};
#define RURW_SETWRITE(rw) \
do { \
assert(rw->readers == 0 && rw->writer == NULL); \
rw->writer = pthread_self(); \
} while (/*CONSTCOND*/0)
#define RURW_CLRWRITE(rw) \
do { \
assert(rw->readers == 0 && rw->writer != NULL); \
rw->writer = NULL; \
} while (/*CONSTCOND*/0)
#define RURW_INCREAD(rw) \
do { \
assert(rw->writer == NULL); \
pthread_spin_lock(&rw->spin); \
((rw)->readers++); \
pthread_spin_unlock(&rw->spin); \
} while (/*CONSTCOND*/0)
#define RURW_DECREAD(rw) \
do { \
assert(rw->readers > 0 && rw->writer == NULL); \
pthread_spin_lock(&rw->spin); \
((rw)->readers--); \
pthread_spin_unlock(&rw->spin); \
} while (/*CONSTCOND*/0)
#define RURW_AMWRITER(rw) (rw->writer == pthread_self())
#define RURW_HASREAD(rw) (rw->readers != 0)
struct rumpuser_rw {
pthread_rwlock_t pthrw;
pthread_spinlock_t spin;
unsigned readers;
pthread_t writer;
};
struct rumpuser_cv {
pthread_cond_t pthcv;
int nwaiters;
};
struct rumpuser_mtx rumpuser_aio_mtx;
@ -181,6 +216,8 @@ rumpuser_mutex_init(struct rumpuser_mtx **mtx)
{
NOFAIL(*mtx = malloc(sizeof(struct rumpuser_mtx)));
NOFAIL_ERRNO(pthread_mutex_init(&((*mtx)->pthmtx), NULL));
(*mtx)->owner = NULL;
(*mtx)->recursion = 0;
}
void
@ -193,28 +230,59 @@ rumpuser_mutex_recursive_init(struct rumpuser_mtx **mtx)
NOFAIL(*mtx = malloc(sizeof(struct rumpuser_mtx)));
NOFAIL_ERRNO(pthread_mutex_init(&((*mtx)->pthmtx), &mattr));
(*mtx)->owner = NULL;
(*mtx)->recursion = 0;
pthread_mutexattr_destroy(&mattr);
}
static void
mtxenter(struct rumpuser_mtx *mtx)
{
if (mtx->recursion++ == 0) {
assert(mtx->owner == NULL);
mtx->owner = pthread_self();
} else {
assert(mtx->owner == pthread_self());
}
}
static void
mtxexit(struct rumpuser_mtx *mtx)
{
assert(mtx->owner != NULL);
if (--mtx->recursion == 0)
mtx->owner = NULL;
}
void
rumpuser_mutex_enter(struct rumpuser_mtx *mtx)
{
KLOCK_WRAP(NOFAIL_ERRNO(pthread_mutex_lock(&mtx->pthmtx)));
mtxenter(mtx);
}
int
rumpuser_mutex_tryenter(struct rumpuser_mtx *mtx)
{
int rv;
return pthread_mutex_trylock(&mtx->pthmtx) == 0;
rv = pthread_mutex_trylock(&mtx->pthmtx);
if (rv == 0) {
mtxenter(mtx);
}
return rv == 0;
}
void
rumpuser_mutex_exit(struct rumpuser_mtx *mtx)
{
mtxexit(mtx);
NOFAIL_ERRNO(pthread_mutex_unlock(&mtx->pthmtx));
}
@ -230,7 +298,7 @@ int
rumpuser_mutex_held(struct rumpuser_mtx *mtx)
{
return pthread_mutex_held_np(&mtx->pthmtx);
return mtx->owner == pthread_self();
}
void
@ -239,32 +307,50 @@ rumpuser_rw_init(struct rumpuser_rw **rw)
NOFAIL(*rw = malloc(sizeof(struct rumpuser_rw)));
NOFAIL_ERRNO(pthread_rwlock_init(&((*rw)->pthrw), NULL));
NOFAIL_ERRNO(pthread_spin_init(&((*rw)->spin), PTHREAD_PROCESS_SHARED));
(*rw)->readers = 0;
(*rw)->writer = NULL;
}
void
rumpuser_rw_enter(struct rumpuser_rw *rw, int write)
{
if (write)
if (write) {
KLOCK_WRAP(NOFAIL_ERRNO(pthread_rwlock_wrlock(&rw->pthrw)));
else
RURW_SETWRITE(rw);
} else {
KLOCK_WRAP(NOFAIL_ERRNO(pthread_rwlock_rdlock(&rw->pthrw)));
RURW_INCREAD(rw);
}
}
int
rumpuser_rw_tryenter(struct rumpuser_rw *rw, int write)
{
int rv;
if (write)
return pthread_rwlock_trywrlock(&rw->pthrw) == 0;
else
return pthread_rwlock_tryrdlock(&rw->pthrw) == 0;
if (write) {
rv = pthread_rwlock_trywrlock(&rw->pthrw);
if (rv == 0)
RURW_SETWRITE(rw);
} else {
rv = pthread_rwlock_tryrdlock(&rw->pthrw);
if (rv == 0)
RURW_INCREAD(rw);
}
return rv == 0;
}
void
rumpuser_rw_exit(struct rumpuser_rw *rw)
{
if (RURW_AMWRITER(rw))
RURW_CLRWRITE(rw);
else
RURW_DECREAD(rw);
NOFAIL_ERRNO(pthread_rwlock_unlock(&rw->pthrw));
}
@ -273,6 +359,7 @@ rumpuser_rw_destroy(struct rumpuser_rw *rw)
{
NOFAIL_ERRNO(pthread_rwlock_destroy(&rw->pthrw));
NOFAIL_ERRNO(pthread_spin_destroy(&rw->spin));
free(rw);
}
@ -280,21 +367,21 @@ int
rumpuser_rw_held(struct rumpuser_rw *rw)
{
return pthread_rwlock_held_np(&rw->pthrw);
return rw->readers || rw->writer;
}
int
rumpuser_rw_rdheld(struct rumpuser_rw *rw)
{
return pthread_rwlock_rdheld_np(&rw->pthrw);
return RURW_HASREAD(rw);
}
int
rumpuser_rw_wrheld(struct rumpuser_rw *rw)
{
return pthread_rwlock_wrheld_np(&rw->pthrw);
return RURW_AMWRITER(rw);
}
void
@ -303,6 +390,7 @@ rumpuser_cv_init(struct rumpuser_cv **cv)
NOFAIL(*cv = malloc(sizeof(struct rumpuser_cv)));
NOFAIL_ERRNO(pthread_cond_init(&((*cv)->pthcv), NULL));
(*cv)->nwaiters = 0;
}
void
@ -317,7 +405,12 @@ void
rumpuser_cv_wait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx)
{
cv->nwaiters++;
assert(mtx->recursion == 1);
mtxexit(mtx);
KLOCK_WRAP(NOFAIL_ERRNO(pthread_cond_wait(&cv->pthcv, &mtx->pthmtx)));
mtxenter(mtx);
cv->nwaiters--;
}
int
@ -333,7 +426,11 @@ rumpuser_cv_timedwait(struct rumpuser_cv *cv, struct rumpuser_mtx *mtx,
ts.tv_sec += ts.tv_nsec / 1000000000;
ts.tv_nsec %= 1000000000;
cv->nwaiters++;
mtxexit(mtx);
KLOCK_WRAP(rv = pthread_cond_timedwait(&cv->pthcv, &mtx->pthmtx, &ts));
mtxenter(mtx);
cv->nwaiters--;
if (rv != 0 && rv != ETIMEDOUT)
abort();
@ -360,7 +457,7 @@ int
rumpuser_cv_has_waiters(struct rumpuser_cv *cv)
{
return pthread_cond_has_waiters_np(&cv->pthcv);
return cv->nwaiters;
}
/*