Home | History | Annotate | Line # | Download | only in rumpkern
locks.c revision 1.80.4.1
      1  1.80.4.1    martin /*	$NetBSD: locks.c,v 1.80.4.1 2020/04/08 14:09:01 martin Exp $	*/
      2       1.1     pooka 
      3       1.1     pooka /*
      4      1.54     pooka  * Copyright (c) 2007-2011 Antti Kantee.  All Rights Reserved.
      5       1.1     pooka  *
      6       1.1     pooka  * Redistribution and use in source and binary forms, with or without
      7       1.1     pooka  * modification, are permitted provided that the following conditions
      8       1.1     pooka  * are met:
      9       1.1     pooka  * 1. Redistributions of source code must retain the above copyright
     10       1.1     pooka  *    notice, this list of conditions and the following disclaimer.
     11       1.1     pooka  * 2. Redistributions in binary form must reproduce the above copyright
     12       1.1     pooka  *    notice, this list of conditions and the following disclaimer in the
     13       1.1     pooka  *    documentation and/or other materials provided with the distribution.
     14       1.1     pooka  *
     15       1.1     pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16       1.1     pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17       1.1     pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18       1.1     pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19       1.1     pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20       1.1     pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21       1.1     pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22       1.1     pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23       1.1     pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24       1.1     pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25       1.1     pooka  * SUCH DAMAGE.
     26       1.1     pooka  */
     27       1.1     pooka 
     28      1.23     pooka #include <sys/cdefs.h>
     29  1.80.4.1    martin __KERNEL_RCSID(0, "$NetBSD: locks.c,v 1.80.4.1 2020/04/08 14:09:01 martin Exp $");
     30      1.23     pooka 
     31       1.1     pooka #include <sys/param.h>
     32      1.26     pooka #include <sys/kmem.h>
     33       1.1     pooka #include <sys/mutex.h>
     34       1.1     pooka #include <sys/rwlock.h>
     35       1.1     pooka 
     36      1.72     pooka #include <rump-sys/kern.h>
     37      1.72     pooka 
     38      1.18     pooka #include <rump/rumpuser.h>
     39      1.18     pooka 
     40      1.69     pooka #ifdef LOCKDEBUG
     41      1.69     pooka const int rump_lockdebug = 1;
     42      1.69     pooka #else
     43      1.69     pooka const int rump_lockdebug = 0;
     44      1.69     pooka #endif
     45      1.69     pooka 
     46      1.22     pooka /*
     47      1.45     pooka  * Simple lockdebug.  If it's compiled in, it's always active.
     48      1.45     pooka  * Currently available only for mtx/rwlock.
     49      1.45     pooka  */
     50      1.45     pooka #ifdef LOCKDEBUG
     51      1.45     pooka #include <sys/lockdebug.h>
     52      1.45     pooka 
     53      1.78     ozaki static lockops_t mutex_spin_lockops = {
     54      1.78     ozaki 	.lo_name = "mutex",
     55      1.78     ozaki 	.lo_type = LOCKOPS_SPIN,
     56      1.78     ozaki 	.lo_dump = NULL,
     57      1.78     ozaki };
     58      1.78     ozaki static lockops_t mutex_adaptive_lockops = {
     59      1.76     ozaki 	.lo_name = "mutex",
     60      1.76     ozaki 	.lo_type = LOCKOPS_SLEEP,
     61      1.76     ozaki 	.lo_dump = NULL,
     62      1.45     pooka };
     63      1.45     pooka static lockops_t rw_lockops = {
     64      1.76     ozaki 	.lo_name = "rwlock",
     65      1.76     ozaki 	.lo_type = LOCKOPS_SLEEP,
     66      1.76     ozaki 	.lo_dump = NULL,
     67      1.45     pooka };
     68      1.45     pooka 
     69      1.80     ozaki #define ALLOCK(lock, ops, return_address)		\
     70      1.77     ozaki 	lockdebug_alloc(__func__, __LINE__, lock, ops,	\
     71      1.80     ozaki 	    return_address)
     72      1.77     ozaki #define FREELOCK(lock)					\
     73      1.77     ozaki 	lockdebug_free(__func__, __LINE__, lock)
     74      1.73     ozaki #define WANTLOCK(lock, shar)				\
     75      1.77     ozaki 	lockdebug_wantlock(__func__, __LINE__, lock,	\
     76      1.77     ozaki 	    (uintptr_t)__builtin_return_address(0), shar)
     77      1.73     ozaki #define LOCKED(lock, shar)				\
     78      1.77     ozaki 	lockdebug_locked(__func__, __LINE__, lock, NULL,\
     79      1.77     ozaki 	    (uintptr_t)__builtin_return_address(0), shar)
     80      1.77     ozaki #define UNLOCKED(lock, shar)				\
     81      1.77     ozaki 	lockdebug_unlocked(__func__, __LINE__, lock,	\
     82      1.77     ozaki 	    (uintptr_t)__builtin_return_address(0), shar)
     83      1.77     ozaki #define BARRIER(lock, slp)				\
     84      1.77     ozaki 	lockdebug_barrier(__func__, __LINE__, lock, slp)
     85      1.45     pooka #else
     86      1.80     ozaki #define ALLOCK(a, b, c)	do {} while (0)
     87      1.77     ozaki #define FREELOCK(a)	do {} while (0)
     88      1.77     ozaki #define WANTLOCK(a, b)	do {} while (0)
     89      1.77     ozaki #define LOCKED(a, b)	do {} while (0)
     90      1.77     ozaki #define UNLOCKED(a, b)	do {} while (0)
     91      1.77     ozaki #define BARRIER(a, b)	do {} while (0)
     92      1.45     pooka #endif
     93      1.45     pooka 
     94      1.45     pooka /*
     95      1.22     pooka  * We map locks to pthread routines.  The difference between kernel
     96      1.22     pooka  * and rumpuser routines is that while the kernel uses static
     97      1.22     pooka  * storage, rumpuser allocates the object from the heap.  This
     98      1.22     pooka  * indirection is necessary because we don't know the size of
     99      1.38       snj  * pthread objects here.  It is also beneficial, since we can
    100      1.22     pooka  * be easily compatible with the kernel ABI because all kernel
    101      1.22     pooka  * objects regardless of machine architecture are always at least
    102      1.22     pooka  * the size of a pointer.  The downside, of course, is a performance
    103      1.22     pooka  * penalty.
    104      1.22     pooka  */
    105      1.22     pooka 
    106      1.75       kre #define RUMPMTX(mtx) (*(struct rumpuser_mtx *const*)(mtx))
    107      1.22     pooka 
    108      1.80     ozaki void _mutex_init(kmutex_t *, kmutex_type_t, int, uintptr_t);
    109       1.1     pooka void
    110      1.80     ozaki _mutex_init(kmutex_t *mtx, kmutex_type_t type, int ipl, uintptr_t return_address)
    111       1.1     pooka {
    112      1.57     pooka 	int ruflags = RUMPUSER_MTX_KMUTEX;
    113      1.56     pooka 	int isspin;
    114      1.56     pooka 
    115      1.57     pooka 	CTASSERT(sizeof(kmutex_t) >= sizeof(void *));
    116      1.57     pooka 
    117      1.56     pooka 	/*
    118      1.56     pooka 	 * Try to figure out if the caller wanted a spin mutex or
    119      1.56     pooka 	 * not with this easy set of conditionals.  The difference
    120      1.56     pooka 	 * between a spin mutex and an adaptive mutex for a rump
    121      1.56     pooka 	 * kernel is that the hypervisor does not relinquish the
    122      1.56     pooka 	 * rump kernel CPU context for a spin mutex.  The
    123      1.56     pooka 	 * hypervisor itself may block even when "spinning".
    124      1.56     pooka 	 */
    125      1.56     pooka 	if (type == MUTEX_SPIN) {
    126      1.56     pooka 		isspin = 1;
    127      1.56     pooka 	} else if (ipl == IPL_NONE || ipl == IPL_SOFTCLOCK ||
    128      1.56     pooka 	    ipl == IPL_SOFTBIO || ipl == IPL_SOFTNET ||
    129      1.56     pooka 	    ipl == IPL_SOFTSERIAL) {
    130      1.56     pooka 		isspin = 0;
    131      1.56     pooka 	} else {
    132      1.56     pooka 		isspin = 1;
    133      1.56     pooka 	}
    134       1.1     pooka 
    135      1.57     pooka 	if (isspin)
    136      1.57     pooka 		ruflags |= RUMPUSER_MTX_SPIN;
    137      1.57     pooka 	rumpuser_mutex_init((struct rumpuser_mtx **)mtx, ruflags);
    138      1.78     ozaki 	if (isspin)
    139      1.80     ozaki 		ALLOCK(mtx, &mutex_spin_lockops, return_address);
    140      1.78     ozaki 	else
    141      1.80     ozaki 		ALLOCK(mtx, &mutex_adaptive_lockops, return_address);
    142      1.80     ozaki }
    143      1.80     ozaki 
    144      1.80     ozaki void
    145      1.80     ozaki mutex_init(kmutex_t *mtx, kmutex_type_t type, int ipl)
    146      1.80     ozaki {
    147      1.80     ozaki 
    148      1.80     ozaki 	_mutex_init(mtx, type, ipl, (uintptr_t)__builtin_return_address(0));
    149       1.1     pooka }
    150       1.1     pooka 
    151       1.1     pooka void
    152       1.1     pooka mutex_destroy(kmutex_t *mtx)
    153       1.1     pooka {
    154       1.1     pooka 
    155      1.45     pooka 	FREELOCK(mtx);
    156      1.22     pooka 	rumpuser_mutex_destroy(RUMPMTX(mtx));
    157       1.1     pooka }
    158       1.1     pooka 
    159       1.1     pooka void
    160       1.1     pooka mutex_enter(kmutex_t *mtx)
    161       1.1     pooka {
    162       1.1     pooka 
    163      1.65     njoly 	WANTLOCK(mtx, 0);
    164      1.78     ozaki 	if (!rumpuser_mutex_spin_p(RUMPMTX(mtx)))
    165      1.78     ozaki 		BARRIER(mtx, 1);
    166      1.22     pooka 	rumpuser_mutex_enter(RUMPMTX(mtx));
    167      1.45     pooka 	LOCKED(mtx, false);
    168       1.1     pooka }
    169      1.56     pooka 
    170      1.56     pooka void
    171      1.56     pooka mutex_spin_enter(kmutex_t *mtx)
    172      1.56     pooka {
    173      1.56     pooka 
    174      1.78     ozaki 	KASSERT(rumpuser_mutex_spin_p(RUMPMTX(mtx)));
    175      1.65     njoly 	WANTLOCK(mtx, 0);
    176      1.61     pooka 	rumpuser_mutex_enter_nowrap(RUMPMTX(mtx));
    177      1.56     pooka 	LOCKED(mtx, false);
    178      1.56     pooka }
    179       1.6     pooka 
    180       1.1     pooka int
    181       1.1     pooka mutex_tryenter(kmutex_t *mtx)
    182       1.1     pooka {
    183      1.60     pooka 	int error;
    184       1.1     pooka 
    185      1.60     pooka 	error = rumpuser_mutex_tryenter(RUMPMTX(mtx));
    186      1.60     pooka 	if (error == 0) {
    187      1.65     njoly 		WANTLOCK(mtx, 0);
    188      1.45     pooka 		LOCKED(mtx, false);
    189      1.45     pooka 	}
    190      1.60     pooka 	return error == 0;
    191       1.1     pooka }
    192       1.1     pooka 
    193       1.1     pooka void
    194       1.1     pooka mutex_exit(kmutex_t *mtx)
    195       1.1     pooka {
    196       1.1     pooka 
    197      1.79     ozaki #ifndef LOCKDEBUG
    198      1.79     ozaki 	KASSERT(mutex_owned(mtx));
    199      1.79     ozaki #endif
    200      1.45     pooka 	UNLOCKED(mtx, false);
    201      1.22     pooka 	rumpuser_mutex_exit(RUMPMTX(mtx));
    202       1.1     pooka }
    203      1.45     pooka __strong_alias(mutex_spin_exit,mutex_exit);
    204       1.6     pooka 
    205       1.1     pooka int
    206      1.75       kre mutex_ownable(const kmutex_t *mtx)
    207      1.74  pgoyette {
    208      1.74  pgoyette 
    209      1.74  pgoyette #ifdef LOCKDEBUG
    210      1.74  pgoyette 	WANTLOCK(mtx, -1);
    211      1.74  pgoyette #endif
    212      1.74  pgoyette 	return 1;
    213      1.74  pgoyette }
    214      1.74  pgoyette 
    215      1.74  pgoyette int
    216      1.75       kre mutex_owned(const kmutex_t *mtx)
    217       1.1     pooka {
    218       1.1     pooka 
    219      1.44     pooka 	return mutex_owner(mtx) == curlwp;
    220      1.44     pooka }
    221      1.44     pooka 
    222      1.75       kre lwp_t *
    223      1.75       kre mutex_owner(const kmutex_t *mtx)
    224      1.44     pooka {
    225      1.60     pooka 	struct lwp *l;
    226      1.44     pooka 
    227      1.60     pooka 	rumpuser_mutex_owner(RUMPMTX(mtx), &l);
    228      1.60     pooka 	return l;
    229       1.1     pooka }
    230       1.1     pooka 
    231      1.22     pooka #define RUMPRW(rw) (*(struct rumpuser_rw **)(rw))
    232      1.22     pooka 
    233       1.1     pooka /* reader/writer locks */
    234       1.1     pooka 
    235      1.63     pooka static enum rumprwlock
    236      1.63     pooka krw2rumprw(const krw_t op)
    237      1.63     pooka {
    238      1.63     pooka 
    239      1.63     pooka 	switch (op) {
    240      1.63     pooka 	case RW_READER:
    241      1.63     pooka 		return RUMPUSER_RW_READER;
    242      1.63     pooka 	case RW_WRITER:
    243      1.63     pooka 		return RUMPUSER_RW_WRITER;
    244      1.63     pooka 	default:
    245      1.63     pooka 		panic("unknown rwlock type");
    246      1.63     pooka 	}
    247      1.63     pooka }
    248      1.63     pooka 
    249      1.80     ozaki void _rw_init(krwlock_t *, uintptr_t);
    250       1.1     pooka void
    251      1.80     ozaki _rw_init(krwlock_t *rw, uintptr_t return_address)
    252       1.1     pooka {
    253       1.1     pooka 
    254      1.22     pooka 	CTASSERT(sizeof(krwlock_t) >= sizeof(void *));
    255      1.22     pooka 
    256      1.22     pooka 	rumpuser_rw_init((struct rumpuser_rw **)rw);
    257      1.80     ozaki 	ALLOCK(rw, &rw_lockops, return_address);
    258      1.80     ozaki }
    259      1.80     ozaki 
    260      1.80     ozaki void
    261      1.80     ozaki rw_init(krwlock_t *rw)
    262      1.80     ozaki {
    263      1.80     ozaki 
    264      1.80     ozaki 	_rw_init(rw, (uintptr_t)__builtin_return_address(0));
    265       1.1     pooka }
    266       1.1     pooka 
    267       1.1     pooka void
    268       1.1     pooka rw_destroy(krwlock_t *rw)
    269       1.1     pooka {
    270       1.1     pooka 
    271      1.45     pooka 	FREELOCK(rw);
    272      1.22     pooka 	rumpuser_rw_destroy(RUMPRW(rw));
    273       1.1     pooka }
    274       1.1     pooka 
    275       1.1     pooka void
    276       1.1     pooka rw_enter(krwlock_t *rw, const krw_t op)
    277       1.1     pooka {
    278       1.1     pooka 
    279      1.65     njoly 	WANTLOCK(rw, op == RW_READER);
    280      1.71     ozaki 	BARRIER(rw, 1);
    281      1.64     pooka 	rumpuser_rw_enter(krw2rumprw(op), RUMPRW(rw));
    282      1.45     pooka 	LOCKED(rw, op == RW_READER);
    283       1.1     pooka }
    284       1.1     pooka 
    285       1.1     pooka int
    286       1.1     pooka rw_tryenter(krwlock_t *rw, const krw_t op)
    287       1.1     pooka {
    288      1.60     pooka 	int error;
    289       1.1     pooka 
    290      1.64     pooka 	error = rumpuser_rw_tryenter(krw2rumprw(op), RUMPRW(rw));
    291      1.60     pooka 	if (error == 0) {
    292      1.65     njoly 		WANTLOCK(rw, op == RW_READER);
    293      1.45     pooka 		LOCKED(rw, op == RW_READER);
    294      1.45     pooka 	}
    295      1.60     pooka 	return error == 0;
    296       1.1     pooka }
    297       1.1     pooka 
    298       1.1     pooka void
    299       1.1     pooka rw_exit(krwlock_t *rw)
    300       1.1     pooka {
    301       1.1     pooka 
    302      1.45     pooka #ifdef LOCKDEBUG
    303      1.45     pooka 	bool shared = !rw_write_held(rw);
    304      1.45     pooka 
    305      1.45     pooka 	if (shared)
    306      1.45     pooka 		KASSERT(rw_read_held(rw));
    307      1.45     pooka 	UNLOCKED(rw, shared);
    308      1.45     pooka #endif
    309      1.22     pooka 	rumpuser_rw_exit(RUMPRW(rw));
    310       1.1     pooka }
    311       1.1     pooka 
    312       1.1     pooka int
    313       1.1     pooka rw_tryupgrade(krwlock_t *rw)
    314       1.1     pooka {
    315      1.63     pooka 	int rv;
    316       1.1     pooka 
    317      1.63     pooka 	rv = rumpuser_rw_tryupgrade(RUMPRW(rw));
    318      1.63     pooka 	if (rv == 0) {
    319      1.63     pooka 		UNLOCKED(rw, 1);
    320      1.65     njoly 		WANTLOCK(rw, 0);
    321      1.63     pooka 		LOCKED(rw, 0);
    322      1.63     pooka 	}
    323      1.63     pooka 	return rv == 0;
    324       1.1     pooka }
    325       1.1     pooka 
    326      1.48      haad void
    327      1.48      haad rw_downgrade(krwlock_t *rw)
    328      1.48      haad {
    329      1.48      haad 
    330      1.63     pooka 	rumpuser_rw_downgrade(RUMPRW(rw));
    331      1.63     pooka 	UNLOCKED(rw, 0);
    332      1.65     njoly 	WANTLOCK(rw, 1);
    333      1.63     pooka 	LOCKED(rw, 1);
    334      1.48      haad }
    335      1.48      haad 
    336       1.6     pooka int
    337      1.63     pooka rw_read_held(krwlock_t *rw)
    338       1.6     pooka {
    339      1.60     pooka 	int rv;
    340       1.6     pooka 
    341      1.64     pooka 	rumpuser_rw_held(RUMPUSER_RW_READER, RUMPRW(rw), &rv);
    342      1.60     pooka 	return rv;
    343      1.10        ad }
    344      1.10        ad 
    345      1.10        ad int
    346      1.63     pooka rw_write_held(krwlock_t *rw)
    347      1.10        ad {
    348      1.60     pooka 	int rv;
    349      1.10        ad 
    350      1.64     pooka 	rumpuser_rw_held(RUMPUSER_RW_WRITER, RUMPRW(rw), &rv);
    351      1.60     pooka 	return rv;
    352      1.10        ad }
    353      1.10        ad 
    354      1.10        ad int
    355      1.10        ad rw_lock_held(krwlock_t *rw)
    356      1.10        ad {
    357      1.10        ad 
    358      1.63     pooka 	return rw_read_held(rw) || rw_write_held(rw);
    359       1.6     pooka }
    360       1.6     pooka 
    361  1.80.4.1    martin krw_t
    362  1.80.4.1    martin rw_lock_op(krwlock_t *rw)
    363  1.80.4.1    martin {
    364  1.80.4.1    martin 
    365  1.80.4.1    martin 	return rw_write_held(rw) ? RW_WRITER : RW_READER;
    366  1.80.4.1    martin }
    367  1.80.4.1    martin 
    368       1.1     pooka /* curriculum vitaes */
    369       1.1     pooka 
    370      1.24     pooka #define RUMPCV(cv) (*(struct rumpuser_cv **)(cv))
    371       1.1     pooka 
    372       1.1     pooka void
    373       1.1     pooka cv_init(kcondvar_t *cv, const char *msg)
    374       1.1     pooka {
    375       1.1     pooka 
    376      1.25     pooka 	CTASSERT(sizeof(kcondvar_t) >= sizeof(void *));
    377      1.25     pooka 
    378      1.24     pooka 	rumpuser_cv_init((struct rumpuser_cv **)cv);
    379       1.1     pooka }
    380       1.1     pooka 
    381       1.1     pooka void
    382       1.1     pooka cv_destroy(kcondvar_t *cv)
    383       1.1     pooka {
    384       1.1     pooka 
    385       1.1     pooka 	rumpuser_cv_destroy(RUMPCV(cv));
    386       1.1     pooka }
    387       1.1     pooka 
    388      1.47     pooka static int
    389      1.47     pooka docvwait(kcondvar_t *cv, kmutex_t *mtx, struct timespec *ts)
    390      1.47     pooka {
    391      1.47     pooka 	struct lwp *l = curlwp;
    392      1.47     pooka 	int rv;
    393      1.47     pooka 
    394      1.51     pooka 	if (__predict_false(l->l_flag & LW_RUMP_QEXIT)) {
    395      1.47     pooka 		/*
    396      1.50     pooka 		 * yield() here, someone might want the cpu
    397      1.50     pooka 		 * to set a condition.  otherwise we'll just
    398      1.50     pooka 		 * loop forever.
    399      1.47     pooka 		 */
    400      1.50     pooka 		yield();
    401      1.47     pooka 		return EINTR;
    402      1.47     pooka 	}
    403      1.47     pooka 
    404      1.47     pooka 	UNLOCKED(mtx, false);
    405      1.47     pooka 
    406      1.47     pooka 	l->l_private = cv;
    407      1.47     pooka 	rv = 0;
    408      1.47     pooka 	if (ts) {
    409      1.47     pooka 		if (rumpuser_cv_timedwait(RUMPCV(cv), RUMPMTX(mtx),
    410      1.47     pooka 		    ts->tv_sec, ts->tv_nsec))
    411      1.47     pooka 			rv = EWOULDBLOCK;
    412      1.47     pooka 	} else {
    413      1.47     pooka 		rumpuser_cv_wait(RUMPCV(cv), RUMPMTX(mtx));
    414      1.47     pooka 	}
    415      1.47     pooka 
    416      1.52     pooka 	LOCKED(mtx, false);
    417      1.52     pooka 
    418      1.47     pooka 	/*
    419      1.51     pooka 	 * Check for QEXIT.  if so, we need to wait here until we
    420      1.47     pooka 	 * are allowed to exit.
    421      1.47     pooka 	 */
    422      1.51     pooka 	if (__predict_false(l->l_flag & LW_RUMP_QEXIT)) {
    423      1.47     pooka 		struct proc *p = l->l_proc;
    424      1.47     pooka 
    425      1.47     pooka 		mutex_exit(mtx); /* drop and retake later */
    426      1.47     pooka 
    427      1.47     pooka 		mutex_enter(p->p_lock);
    428      1.51     pooka 		while ((p->p_sflag & PS_RUMP_LWPEXIT) == 0) {
    429      1.47     pooka 			/* avoid recursion */
    430      1.47     pooka 			rumpuser_cv_wait(RUMPCV(&p->p_waitcv),
    431      1.47     pooka 			    RUMPMTX(p->p_lock));
    432      1.47     pooka 		}
    433      1.51     pooka 		KASSERT(p->p_sflag & PS_RUMP_LWPEXIT);
    434      1.47     pooka 		mutex_exit(p->p_lock);
    435      1.47     pooka 
    436      1.47     pooka 		/* ok, we can exit and remove "reference" to l->private */
    437      1.47     pooka 
    438      1.47     pooka 		mutex_enter(mtx);
    439      1.47     pooka 		rv = EINTR;
    440      1.47     pooka 	}
    441      1.47     pooka 	l->l_private = NULL;
    442      1.47     pooka 
    443      1.47     pooka 	return rv;
    444      1.47     pooka }
    445      1.47     pooka 
    446       1.1     pooka void
    447       1.1     pooka cv_wait(kcondvar_t *cv, kmutex_t *mtx)
    448       1.1     pooka {
    449       1.1     pooka 
    450      1.42     pooka 	if (__predict_false(rump_threads == 0))
    451      1.28     pooka 		panic("cv_wait without threads");
    452      1.47     pooka 	(void) docvwait(cv, mtx, NULL);
    453       1.1     pooka }
    454       1.1     pooka 
    455       1.3     pooka int
    456       1.5     pooka cv_wait_sig(kcondvar_t *cv, kmutex_t *mtx)
    457       1.5     pooka {
    458       1.5     pooka 
    459      1.42     pooka 	if (__predict_false(rump_threads == 0))
    460      1.42     pooka 		panic("cv_wait without threads");
    461      1.47     pooka 	return docvwait(cv, mtx, NULL);
    462       1.5     pooka }
    463       1.5     pooka 
    464       1.5     pooka int
    465       1.3     pooka cv_timedwait(kcondvar_t *cv, kmutex_t *mtx, int ticks)
    466       1.3     pooka {
    467      1.58     pooka 	struct timespec ts;
    468       1.3     pooka 	extern int hz;
    469      1.45     pooka 	int rv;
    470      1.27     pooka 
    471       1.9     pooka 	if (ticks == 0) {
    472      1.47     pooka 		rv = cv_wait_sig(cv, mtx);
    473       1.9     pooka 	} else {
    474      1.58     pooka 		ts.tv_sec = ticks / hz;
    475      1.58     pooka 		ts.tv_nsec = (ticks % hz) * (1000000000/hz);
    476      1.47     pooka 		rv = docvwait(cv, mtx, &ts);
    477       1.9     pooka 	}
    478       1.5     pooka 
    479      1.45     pooka 	return rv;
    480       1.5     pooka }
    481      1.45     pooka __strong_alias(cv_timedwait_sig,cv_timedwait);
    482       1.5     pooka 
    483       1.1     pooka void
    484       1.1     pooka cv_signal(kcondvar_t *cv)
    485       1.1     pooka {
    486       1.1     pooka 
    487       1.1     pooka 	rumpuser_cv_signal(RUMPCV(cv));
    488       1.1     pooka }
    489       1.2     pooka 
    490       1.4     pooka void
    491       1.4     pooka cv_broadcast(kcondvar_t *cv)
    492       1.4     pooka {
    493       1.4     pooka 
    494       1.4     pooka 	rumpuser_cv_broadcast(RUMPCV(cv));
    495       1.4     pooka }
    496       1.4     pooka 
    497      1.17     pooka bool
    498      1.17     pooka cv_has_waiters(kcondvar_t *cv)
    499      1.17     pooka {
    500      1.60     pooka 	int rv;
    501      1.17     pooka 
    502      1.60     pooka 	rumpuser_cv_has_waiters(RUMPCV(cv), &rv);
    503      1.60     pooka 	return rv != 0;
    504      1.17     pooka }
    505      1.17     pooka 
    506      1.35     pooka /* this is not much of an attempt, but ... */
    507      1.35     pooka bool
    508      1.35     pooka cv_is_valid(kcondvar_t *cv)
    509      1.35     pooka {
    510      1.35     pooka 
    511      1.35     pooka 	return RUMPCV(cv) != NULL;
    512      1.35     pooka }
    513