Push rwlock upgrade and downgrade into the hypervisor where there's

at least a chance to implement them with minimal fuss.
This commit is contained in:
pooka 2013-05-02 21:35:19 +00:00
parent 5d1d1ac212
commit f950fd3d52
4 changed files with 119 additions and 69 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: rumpuser.3,v 1.6 2013/05/02 19:14:59 pooka Exp $
.\" $NetBSD: rumpuser.3,v 1.7 2013/05/02 21:35:19 pooka Exp $
.\"
.\" Copyright (c) 2013 Antti Kantee. All rights reserved.
.\"
@ -561,10 +561,16 @@ will never be called for that particular mutex.
.Fn rumpuser_rw_init "struct rumpuser_rw **rwp"
.Pp
.Ft void
.Fn rumpuser_rw_enter "struct rumpuser_rw *rw" "int writelock"
.Fn rumpuser_rw_enter "struct rumpuser_rw *rw" "const enum rumprwlock lk"
.Pp
.Ft int
.Fn rumpuser_rw_tryenter "struct rumpuser_rw *rw" "int writelock"
.Fn rumpuser_rw_tryenter "struct rumpuser_rw *rw" "const enum rumprwlock lk"
.Pp
.Ft int
.Fn rumpuser_rw_tryupgrade "struct rumpuser_rw *rw"
.Pp
.Ft void
.Fn rumpuser_rw_downgrade "struct rumpuser_rw *rw"
.Pp
.Ft void
.Fn rumpuser_rw_exit "struct rumpuser_rw *rw"
@ -573,18 +579,20 @@ will never be called for that particular mutex.
.Fn rumpuser_rw_destroy "struct rumpuser_rw *rw"
.Pp
.Ft void
.Fn rumpuser_rw_held "struct rumpuser_rw *rw" "int *heldp"
.Pp
.Ft void
.Fn rumpuser_rw_rdheld "struct rumpuser_rw *rw" "int *heldp"
.Pp
.Ft void
.Fn rumpuser_rw_wrheld "struct rumpuser_rw *rw" "int *heldp"
.Pp
Read/write locks acquire an exclusive version of the lock if the
.Fa writelock
parameter is non-zero and a shared lock otherwise.
.Fo rumpuser_rw_held
.Fa "struct rumpuser_rw *rw" "const enum rumprwlock lk" "int *heldp"
.Fc
.Pp
Read/write locks provide either shared or exclusive locking.
The possible values for
.Fa lk
are
.Dv RUMPUSER_RW_READER
and
.Dv RUMPUSER_RW_WRITER .
Upgrading means trying to migrate from an already owned shared
lock to an exclusive lock and downgrading means migrating from
an already owned exclusive lock to a shared lock.
.Pp
.Ft void
.Fn rumpuser_cv_init "struct rumpuser_cv **cvp"

View File

@ -1,4 +1,4 @@
/* $NetBSD: rumpuser_pth.c,v 1.24 2013/05/02 20:33:54 pooka Exp $ */
/* $NetBSD: rumpuser_pth.c,v 1.25 2013/05/02 21:35:19 pooka Exp $ */
/*
* Copyright (c) 2007-2010 Antti Kantee. All Rights Reserved.
@ -28,7 +28,7 @@
#include "rumpuser_port.h"
#if !defined(lint)
__RCSID("$NetBSD: rumpuser_pth.c,v 1.24 2013/05/02 20:33:54 pooka Exp $");
__RCSID("$NetBSD: rumpuser_pth.c,v 1.25 2013/05/02 21:35:19 pooka Exp $");
#endif /* !lint */
#include <sys/queue.h>
@ -286,40 +286,72 @@ rumpuser_rw_init(struct rumpuser_rw **rw)
}
void
rumpuser_rw_enter(struct rumpuser_rw *rw, int iswrite)
rumpuser_rw_enter(struct rumpuser_rw *rw, const enum rumprwlock lk)
{
if (iswrite) {
switch (lk) {
case RUMPUSER_RW_WRITER:
if (pthread_rwlock_trywrlock(&rw->pthrw) != 0)
KLOCK_WRAP(NOFAIL_ERRNO(
pthread_rwlock_wrlock(&rw->pthrw)));
RURW_SETWRITE(rw);
} else {
break;
case RUMPUSER_RW_READER:
if (pthread_rwlock_tryrdlock(&rw->pthrw) != 0)
KLOCK_WRAP(NOFAIL_ERRNO(
pthread_rwlock_rdlock(&rw->pthrw)));
RURW_INCREAD(rw);
break;
}
}
int
rumpuser_rw_tryenter(struct rumpuser_rw *rw, int iswrite)
rumpuser_rw_tryenter(struct rumpuser_rw *rw, const enum rumprwlock lk)
{
int rv;
if (iswrite) {
switch (lk) {
case RUMPUSER_RW_WRITER:
rv = pthread_rwlock_trywrlock(&rw->pthrw);
if (rv == 0)
RURW_SETWRITE(rw);
} else {
break;
case RUMPUSER_RW_READER:
rv = pthread_rwlock_tryrdlock(&rw->pthrw);
if (rv == 0)
RURW_INCREAD(rw);
break;
default:
rv = EINVAL;
break;
}
ET(rv);
}
int
rumpuser_rw_tryupgrade(struct rumpuser_rw *rw)
{
/* not supported by pthreads */
ET(EBUSY);
}
void
rumpuser_rw_downgrade(struct rumpuser_rw *rw)
{
/*
* I guess this is not strictly speaking correct,
* but the option is to provide a complete implementation
* of rwlocks here, or at least wrap acquiry in 1) lock
* 2) check if someone is downgrading. if not, we're done
* 3) unlock 4) yield 5) goto 1.
*/
rumpuser_rw_exit(rw);
rumpuser_rw_enter(rw, RUMPUSER_RW_READER);
}
void
rumpuser_rw_exit(struct rumpuser_rw *rw)
{
@ -341,24 +373,17 @@ rumpuser_rw_destroy(struct rumpuser_rw *rw)
}
void
rumpuser_rw_held(struct rumpuser_rw *rw, int *rv)
rumpuser_rw_held(struct rumpuser_rw *rw, const enum rumprwlock lk, int *rv)
{
*rv = rw->readers != 0;
}
void
rumpuser_rw_rdheld(struct rumpuser_rw *rw, int *rv)
{
*rv = RURW_HASREAD(rw);
}
void
rumpuser_rw_wrheld(struct rumpuser_rw *rw, int *rv)
{
*rv = RURW_AMWRITER(rw);
switch (lk) {
case RUMPUSER_RW_WRITER:
*rv = RURW_AMWRITER(rw);
break;
case RUMPUSER_RW_READER:
*rv = RURW_HASREAD(rw);
break;
}
}
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: rumpuser.h,v 1.101 2013/05/02 19:15:01 pooka Exp $ */
/* $NetBSD: rumpuser.h,v 1.102 2013/05/02 21:35:19 pooka Exp $ */
/*
* Copyright (c) 2007-2013 Antti Kantee. All Rights Reserved.
@ -180,14 +180,15 @@ void rumpuser_mutex_destroy(struct rumpuser_mtx *);
void rumpuser_mutex_owner(struct rumpuser_mtx *, struct lwp **);
struct rumpuser_rw;
enum rumprwlock { RUMPUSER_RW_READER, RUMPUSER_RW_WRITER };
void rumpuser_rw_init(struct rumpuser_rw **);
void rumpuser_rw_enter(struct rumpuser_rw *, int);
int rumpuser_rw_tryenter(struct rumpuser_rw *, int);
void rumpuser_rw_enter(struct rumpuser_rw *, const enum rumprwlock);
int rumpuser_rw_tryenter(struct rumpuser_rw *, const enum rumprwlock);
int rumpuser_rw_tryupgrade(struct rumpuser_rw *);
void rumpuser_rw_downgrade(struct rumpuser_rw *);
void rumpuser_rw_exit(struct rumpuser_rw *);
void rumpuser_rw_destroy(struct rumpuser_rw *);
void rumpuser_rw_held(struct rumpuser_rw *, int *);
void rumpuser_rw_rdheld(struct rumpuser_rw *, int *);
void rumpuser_rw_wrheld(struct rumpuser_rw *, int *);
void rumpuser_rw_held(struct rumpuser_rw *, const enum rumprwlock, int *);
struct rumpuser_cv;
void rumpuser_cv_init(struct rumpuser_cv **);

View File

@ -1,4 +1,4 @@
/* $NetBSD: locks.c,v 1.62 2013/05/02 20:37:32 pooka Exp $ */
/* $NetBSD: locks.c,v 1.63 2013/05/02 21:35:19 pooka Exp $ */
/*
* Copyright (c) 2007-2011 Antti Kantee. All Rights Reserved.
@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: locks.c,v 1.62 2013/05/02 20:37:32 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: locks.c,v 1.63 2013/05/02 21:35:19 pooka Exp $");
#include <sys/param.h>
#include <sys/kmem.h>
@ -187,6 +187,20 @@ mutex_owner(kmutex_t *mtx)
/* reader/writer locks */
static enum rumprwlock
krw2rumprw(const krw_t op)
{
switch (op) {
case RW_READER:
return RUMPUSER_RW_READER;
case RW_WRITER:
return RUMPUSER_RW_WRITER;
default:
panic("unknown rwlock type");
}
}
void
rw_init(krwlock_t *rw)
{
@ -211,7 +225,7 @@ rw_enter(krwlock_t *rw, const krw_t op)
WANTLOCK(rw, op == RW_READER, false);
rumpuser_rw_enter(RUMPRW(rw), op == RW_WRITER);
rumpuser_rw_enter(RUMPRW(rw), krw2rumprw(op));
LOCKED(rw, op == RW_READER);
}
@ -220,7 +234,7 @@ rw_tryenter(krwlock_t *rw, const krw_t op)
{
int error;
error = rumpuser_rw_tryenter(RUMPRW(rw), op == RW_WRITER);
error = rumpuser_rw_tryenter(RUMPRW(rw), krw2rumprw(op));
if (error == 0) {
WANTLOCK(rw, op == RW_READER, true);
LOCKED(rw, op == RW_READER);
@ -242,33 +256,28 @@ rw_exit(krwlock_t *rw)
rumpuser_rw_exit(RUMPRW(rw));
}
/* always fails */
int
rw_tryupgrade(krwlock_t *rw)
{
int rv;
return 0;
rv = rumpuser_rw_tryupgrade(RUMPRW(rw));
if (rv == 0) {
UNLOCKED(rw, 1);
WANTLOCK(rw, 0, true);
LOCKED(rw, 0);
}
return rv == 0;
}
void
rw_downgrade(krwlock_t *rw)
{
/*
* XXX HACK: How we can downgrade re lock in rump properly.
*/
rw_exit(rw);
rw_enter(rw, RW_READER);
return;
}
int
rw_write_held(krwlock_t *rw)
{
int rv;
rumpuser_rw_wrheld(RUMPRW(rw), &rv);
return rv;
rumpuser_rw_downgrade(RUMPRW(rw));
UNLOCKED(rw, 0);
WANTLOCK(rw, 1, false);
LOCKED(rw, 1);
}
int
@ -276,17 +285,24 @@ rw_read_held(krwlock_t *rw)
{
int rv;
rumpuser_rw_rdheld(RUMPRW(rw), &rv);
rumpuser_rw_held(RUMPRW(rw), RUMPUSER_RW_READER, &rv);
return rv;
}
int
rw_write_held(krwlock_t *rw)
{
int rv;
rumpuser_rw_held(RUMPRW(rw), RUMPUSER_RW_WRITER, &rv);
return rv;
}
int
rw_lock_held(krwlock_t *rw)
{
int rv;
rumpuser_rw_held(RUMPRW(rw), &rv);
return rv;
return rw_read_held(rw) || rw_write_held(rw);
}
/* curriculum vitaes */