#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ltsleep.c,v 1.36 2020/03/14 20:23:51 ad Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/queue.h>
#include <rump-sys/kern.h>
#include <rump/rumpuser.h>
struct ltsleeper {
wchan_t id;
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 kmutex_t qlock;
static int
sleeper(wchan_t ident, int timo, bool kinterlock)
{
struct ltsleeper lts;
struct timespec ts;
int rv;
lts.id = ident;
if (kinterlock) {
lts.iskwait = true;
cv_init(<s.kcv, "mtsleep");
} else {
lts.iskwait = false;
rumpuser_cv_init(<s.ucv);
}
LIST_INSERT_HEAD(&sleepers, <s, entries);
if (timo) {
if (kinterlock) {
rv = cv_timedwait(<s.kcv, &qlock, timo);
} else {
ts.tv_sec = timo / hz;
ts.tv_nsec = (timo % hz) * (1000000000/hz);
mutex_spin_exit(&qlock);
rv = rumpuser_cv_timedwait(lts.ucv, rump_giantlock,
ts.tv_sec, ts.tv_nsec);
mutex_spin_enter(&qlock);
}
if (rv != 0)
rv = EWOULDBLOCK;
} else {
if (kinterlock) {
cv_wait(<s.kcv, &qlock);
} else {
mutex_spin_exit(&qlock);
rumpuser_cv_wait(lts.ucv, rump_giantlock);
mutex_spin_enter(&qlock);
}
rv = 0;
}
LIST_REMOVE(<s, entries);
mutex_spin_exit(&qlock);
if (kinterlock)
cv_destroy(<s.kcv);
else
rumpuser_cv_destroy(lts.ucv);
return rv;
}
int
tsleep(wchan_t ident, pri_t prio, const char *wmesg, int timo)
{
int rv, nlocks;
rump_kernel_bigwrap(&nlocks);
mutex_spin_enter(&qlock);
rv = sleeper(ident, timo, false);
rump_kernel_bigunwrap(nlocks);
return rv;
}
int
mtsleep(wchan_t ident, pri_t prio, const char *wmesg, int timo, kmutex_t *lock)
{
int rv;
mutex_spin_enter(&qlock);
mutex_exit(lock);
rv = sleeper(ident, timo, true);
if ((prio & PNORELOCK) == 0)
mutex_enter(lock);
return rv;
}
void
wakeup(wchan_t ident)
{
struct ltsleeper *ltsp;
mutex_spin_enter(&qlock);
LIST_FOREACH(ltsp, &sleepers, entries) {
if (ltsp->id == ident) {
if (ltsp->iskwait) {
cv_broadcast(<sp->kcv);
} else {
rumpuser_cv_broadcast(ltsp->ucv);
}
}
}
mutex_exit(&qlock);
}
void
rump_tsleep_init()
{
mutex_init(&qlock, MUTEX_SPIN, IPL_NONE);
}