Support mtsleep() without a biglocked sleeper (uvm uses this in
UVM_UNLOCK_AND_WAIT())
This commit is contained in:
parent
977a0ef122
commit
a590bfb92a
@ -1,10 +1,7 @@
|
||||
/* $NetBSD: ltsleep.c,v 1.26 2010/05/18 15:16:10 pooka Exp $ */
|
||||
/* $NetBSD: ltsleep.c,v 1.27 2010/05/31 23:18:33 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Development of this software was supported by the
|
||||
* Finnish Cultural Foundation.
|
||||
* Copyright (c) 2009, 2010 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -29,13 +26,15 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Emulate the prehistoric tsleep-style kernel interfaces. We assume
|
||||
* only code under the biglock will be using this type of synchronization
|
||||
* and use the biglock as the cv interlock.
|
||||
* Implementation of the ltsleep/mtsleep kernel sleep interface. There
|
||||
* are two sides to our implementation. For historic spinlocks we
|
||||
* assume the kernel is giantlocked and use kernel giantlock as the
|
||||
* wait interlock. For mtsleep, we use the interlock supplied by
|
||||
* the caller. This duality leads to some if/else messiness in the code ...
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ltsleep.c,v 1.26 2010/05/18 15:16:10 pooka Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ltsleep.c,v 1.27 2010/05/31 23:18:33 pooka Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -49,46 +48,76 @@ __KERNEL_RCSID(0, "$NetBSD: ltsleep.c,v 1.26 2010/05/18 15:16:10 pooka Exp $");
|
||||
|
||||
struct ltsleeper {
|
||||
wchan_t id;
|
||||
struct rumpuser_cv *cv;
|
||||
union {
|
||||
struct rumpuser_cv *user;
|
||||
kcondvar_t kern;
|
||||
} u;
|
||||
bool iskwait;
|
||||
LIST_ENTRY(ltsleeper) entries;
|
||||
};
|
||||
#define ucv u.user
|
||||
#define kcv u.kern
|
||||
|
||||
static LIST_HEAD(, ltsleeper) sleepers = LIST_HEAD_INITIALIZER(sleepers);
|
||||
static struct rumpuser_mtx *qlock;
|
||||
|
||||
static int
|
||||
sleeper(struct ltsleeper *ltsp, int timo)
|
||||
sleeper(wchan_t ident, int timo, kmutex_t *kinterlock)
|
||||
{
|
||||
struct ltsleeper lts;
|
||||
struct timespec ts, ticks;
|
||||
int rv, nlocks;
|
||||
int rv;
|
||||
|
||||
LIST_INSERT_HEAD(&sleepers, ltsp, entries);
|
||||
rump_kernel_unlock_allbutone(&nlocks);
|
||||
lts.id = ident;
|
||||
if (kinterlock) {
|
||||
lts.iskwait = true;
|
||||
cv_init(<s.kcv, "mtsleep");
|
||||
} else {
|
||||
lts.iskwait = false;
|
||||
rumpuser_cv_init(<s.ucv);
|
||||
}
|
||||
|
||||
rumpuser_mutex_enter_nowrap(qlock);
|
||||
LIST_INSERT_HEAD(&sleepers, <s, entries);
|
||||
rumpuser_mutex_exit(qlock);
|
||||
|
||||
/* protected by biglock */
|
||||
if (timo) {
|
||||
/*
|
||||
* Calculate wakeup-time.
|
||||
* XXX: should assert nanotime() does not block,
|
||||
* i.e. yield the cpu and/or biglock.
|
||||
*/
|
||||
ticks.tv_sec = timo / hz;
|
||||
ticks.tv_nsec = (timo % hz) * (1000000000/hz);
|
||||
nanotime(&ts);
|
||||
timespecadd(&ts, &ticks, &ts);
|
||||
if (kinterlock) {
|
||||
rv = cv_timedwait(<s.kcv, kinterlock, timo);
|
||||
} else {
|
||||
/*
|
||||
* Calculate wakeup-time.
|
||||
* XXX: should assert nanotime() does not block,
|
||||
* i.e. yield the cpu and/or biglock.
|
||||
*/
|
||||
ticks.tv_sec = timo / hz;
|
||||
ticks.tv_nsec = (timo % hz) * (1000000000/hz);
|
||||
nanotime(&ts);
|
||||
timespecadd(&ts, &ticks, &ts);
|
||||
|
||||
if (rumpuser_cv_timedwait(ltsp->cv, rump_giantlock,
|
||||
ts.tv_sec, ts.tv_nsec) == 0)
|
||||
rv = 0;
|
||||
else
|
||||
rv = rumpuser_cv_timedwait(lts.ucv, rump_giantlock,
|
||||
ts.tv_sec, ts.tv_nsec);
|
||||
}
|
||||
|
||||
if (rv != 0)
|
||||
rv = EWOULDBLOCK;
|
||||
} else {
|
||||
rumpuser_cv_wait(ltsp->cv, rump_giantlock);
|
||||
if (kinterlock) {
|
||||
cv_wait(<s.kcv, kinterlock);
|
||||
} else {
|
||||
rumpuser_cv_wait(lts.ucv, rump_giantlock);
|
||||
}
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
LIST_REMOVE(ltsp, entries);
|
||||
rumpuser_cv_destroy(ltsp->cv);
|
||||
rump_kernel_ununlock_allbutone(nlocks);
|
||||
rumpuser_mutex_enter_nowrap(qlock);
|
||||
LIST_REMOVE(<s, entries);
|
||||
rumpuser_mutex_exit(qlock);
|
||||
|
||||
if (kinterlock)
|
||||
cv_destroy(<s.kcv);
|
||||
else
|
||||
rumpuser_cv_destroy(lts.ucv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -97,16 +126,20 @@ int
|
||||
ltsleep(wchan_t ident, pri_t prio, const char *wmesg, int timo,
|
||||
volatile struct simplelock *slock)
|
||||
{
|
||||
struct ltsleeper lts;
|
||||
int rv;
|
||||
|
||||
lts.id = ident;
|
||||
rumpuser_cv_init(<s.cv);
|
||||
int rv, nlocks;
|
||||
|
||||
/*
|
||||
* Since we cannot use slock as the rumpuser interlock,
|
||||
* require that everyone using this prehistoric interface
|
||||
* is biglocked.
|
||||
*/
|
||||
KASSERT(rump_kernel_isbiglocked());
|
||||
if (slock)
|
||||
simple_unlock(slock);
|
||||
|
||||
rv = sleeper(<s, timo);
|
||||
rump_kernel_unlock_allbutone(&nlocks);
|
||||
rv = sleeper(ident, timo, NULL);
|
||||
rump_kernel_ununlock_allbutone(nlocks);
|
||||
|
||||
if (slock && (prio & PNORELOCK) == 0)
|
||||
simple_lock(slock);
|
||||
@ -118,45 +151,58 @@ int
|
||||
mtsleep(wchan_t ident, pri_t prio, const char *wmesg, int timo,
|
||||
kmutex_t *lock)
|
||||
{
|
||||
struct ltsleeper lts;
|
||||
int rv;
|
||||
|
||||
lts.id = ident;
|
||||
rumpuser_cv_init(<s.cv);
|
||||
|
||||
mutex_exit(lock);
|
||||
|
||||
rv = sleeper(<s, timo);
|
||||
|
||||
if ((prio & PNORELOCK) == 0)
|
||||
mutex_enter(lock);
|
||||
rv = sleeper(ident, timo, lock);
|
||||
if (prio & PNORELOCK)
|
||||
mutex_exit(lock);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void
|
||||
do_wakeup(wchan_t ident, void (*wakeupfn)(struct rumpuser_cv *))
|
||||
do_wakeup(wchan_t ident, bool wakeup_all)
|
||||
{
|
||||
struct ltsleeper *ltsp;
|
||||
|
||||
KASSERT(rump_kernel_isbiglocked());
|
||||
rumpuser_mutex_enter_nowrap(qlock);
|
||||
LIST_FOREACH(ltsp, &sleepers, entries) {
|
||||
if (ltsp->id == ident) {
|
||||
wakeupfn(ltsp->cv);
|
||||
if (wakeup_all) {
|
||||
if (ltsp->iskwait) {
|
||||
cv_broadcast(<sp->kcv);
|
||||
} else {
|
||||
rumpuser_cv_broadcast(ltsp->ucv);
|
||||
}
|
||||
} else {
|
||||
if (ltsp->iskwait) {
|
||||
cv_signal(<sp->kcv);
|
||||
} else {
|
||||
rumpuser_cv_signal(ltsp->ucv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rumpuser_mutex_exit(qlock);
|
||||
}
|
||||
|
||||
void
|
||||
wakeup(wchan_t ident)
|
||||
{
|
||||
|
||||
do_wakeup(ident, rumpuser_cv_broadcast);
|
||||
do_wakeup(ident, true);
|
||||
}
|
||||
|
||||
void
|
||||
wakeup_one(wchan_t ident)
|
||||
{
|
||||
|
||||
do_wakeup(ident, rumpuser_cv_signal);
|
||||
do_wakeup(ident, false);
|
||||
}
|
||||
|
||||
void
|
||||
rump_tsleep_init()
|
||||
{
|
||||
|
||||
rumpuser_mutex_init(&qlock);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rump.c,v 1.172 2010/05/28 16:44:14 pooka Exp $ */
|
||||
/* $NetBSD: rump.c,v 1.173 2010/05/31 23:18:33 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
@ -28,7 +28,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.172 2010/05/28 16:44:14 pooka Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: rump.c,v 1.173 2010/05/31 23:18:33 pooka Exp $");
|
||||
|
||||
#include <sys/systm.h>
|
||||
#define ELFSIZE ARCH_ELFSIZE
|
||||
@ -265,6 +265,7 @@ rump__init(int rump_version)
|
||||
rumpuser_thrinit(rump_user_schedule, rump_user_unschedule,
|
||||
rump_threads);
|
||||
rump_intr_init();
|
||||
rump_tsleep_init();
|
||||
|
||||
/* init minimal lwp/cpu context */
|
||||
l = &lwp0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: rump_private.h,v 1.46 2010/05/18 15:16:10 pooka Exp $ */
|
||||
/* $NetBSD: rump_private.h,v 1.47 2010/05/31 23:18:33 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
@ -127,6 +127,8 @@ bool rump_kernel_isbiglocked(void);
|
||||
void rump_kernel_unlock_allbutone(int *);
|
||||
void rump_kernel_ununlock_allbutone(int);
|
||||
|
||||
void rump_tsleep_init(void);
|
||||
|
||||
void rump_intr_init(void);
|
||||
void rump_softint_run(struct cpu_info *);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user