From f950fd3d526096fd97b11670778807906a712891 Mon Sep 17 00:00:00 2001 From: pooka Date: Thu, 2 May 2013 21:35:19 +0000 Subject: [PATCH] Push rwlock upgrade and downgrade into the hypervisor where there's at least a chance to implement them with minimal fuss. --- lib/librumpuser/rumpuser.3 | 36 +++++++++------ lib/librumpuser/rumpuser_pth.c | 73 +++++++++++++++++++++---------- sys/rump/include/rump/rumpuser.h | 13 +++--- sys/rump/librump/rumpkern/locks.c | 66 +++++++++++++++++----------- 4 files changed, 119 insertions(+), 69 deletions(-) diff --git a/lib/librumpuser/rumpuser.3 b/lib/librumpuser/rumpuser.3 index 3cdd0b066aca..bd3185438f8d 100644 --- a/lib/librumpuser/rumpuser.3 +++ b/lib/librumpuser/rumpuser.3 @@ -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" diff --git a/lib/librumpuser/rumpuser_pth.c b/lib/librumpuser/rumpuser_pth.c index bdd043183bc5..372105053bf5 100644 --- a/lib/librumpuser/rumpuser_pth.c +++ b/lib/librumpuser/rumpuser_pth.c @@ -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 @@ -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 diff --git a/sys/rump/include/rump/rumpuser.h b/sys/rump/include/rump/rumpuser.h index 7b77c6482c6a..93e372898100 100644 --- a/sys/rump/include/rump/rumpuser.h +++ b/sys/rump/include/rump/rumpuser.h @@ -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 **); diff --git a/sys/rump/librump/rumpkern/locks.c b/sys/rump/librump/rumpkern/locks.c index be98878d1131..f4e7b0dd4697 100644 --- a/sys/rump/librump/rumpkern/locks.c +++ b/sys/rump/librump/rumpkern/locks.c @@ -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 -__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 #include @@ -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 */