Home | History | Annotate | Line # | Download | only in rumpkern
locks.c revision 1.45
      1 /*	$NetBSD: locks.c,v 1.45 2011/01/06 11:22:55 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2007, 2008 Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Finnish Cultural Foundation.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: locks.c,v 1.45 2011/01/06 11:22:55 pooka Exp $");
     33 
     34 #include <sys/param.h>
     35 #include <sys/kmem.h>
     36 #include <sys/mutex.h>
     37 #include <sys/rwlock.h>
     38 
     39 #include <rump/rumpuser.h>
     40 
     41 #include "rump_private.h"
     42 
     43 /*
     44  * Simple lockdebug.  If it's compiled in, it's always active.
     45  * Currently available only for mtx/rwlock.
     46  */
     47 #ifdef LOCKDEBUG
     48 #include <sys/lockdebug.h>
     49 
     50 static lockops_t mutex_lockops = {
     51 	"mutex",
     52 	LOCKOPS_SLEEP,
     53 	NULL
     54 };
     55 static lockops_t rw_lockops = {
     56 	"mutex",
     57 	LOCKOPS_SLEEP,
     58 	NULL
     59 };
     60 
     61 #define ALLOCK(lock, ops)		\
     62     lockdebug_alloc(lock, ops, (uintptr_t)__builtin_return_address(0))
     63 #define FREELOCK(lock)			\
     64     lockdebug_free(lock)
     65 #define WANTLOCK(lock, shar, try)	\
     66     lockdebug_wantlock(lock, (uintptr_t)__builtin_return_address(0), shar, try)
     67 #define LOCKED(lock, shar)		\
     68     lockdebug_locked(lock, NULL, (uintptr_t)__builtin_return_address(0), shar)
     69 #define UNLOCKED(lock, shar)		\
     70     lockdebug_unlocked(lock, (uintptr_t)__builtin_return_address(0), shar)
     71 #else
     72 #define ALLOCK(a, b)
     73 #define FREELOCK(a)
     74 #define WANTLOCK(a, b, c)
     75 #define LOCKED(a, b)
     76 #define UNLOCKED(a, b)
     77 #endif
     78 
     79 /*
     80  * We map locks to pthread routines.  The difference between kernel
     81  * and rumpuser routines is that while the kernel uses static
     82  * storage, rumpuser allocates the object from the heap.  This
     83  * indirection is necessary because we don't know the size of
     84  * pthread objects here.  It is also beneficial, since we can
     85  * be easily compatible with the kernel ABI because all kernel
     86  * objects regardless of machine architecture are always at least
     87  * the size of a pointer.  The downside, of course, is a performance
     88  * penalty.
     89  */
     90 
     91 #define RUMPMTX(mtx) (*(struct rumpuser_mtx **)(mtx))
     92 
     93 void
     94 mutex_init(kmutex_t *mtx, kmutex_type_t type, int ipl)
     95 {
     96 
     97 	CTASSERT(sizeof(kmutex_t) >= sizeof(void *));
     98 
     99 	rumpuser_mutex_init_kmutex((struct rumpuser_mtx **)mtx);
    100 	ALLOCK(mtx, &mutex_lockops);
    101 }
    102 
    103 void
    104 mutex_destroy(kmutex_t *mtx)
    105 {
    106 
    107 	FREELOCK(mtx);
    108 	rumpuser_mutex_destroy(RUMPMTX(mtx));
    109 }
    110 
    111 void
    112 mutex_enter(kmutex_t *mtx)
    113 {
    114 
    115 	WANTLOCK(mtx, false, false);
    116 	rumpuser_mutex_enter(RUMPMTX(mtx));
    117 	LOCKED(mtx, false);
    118 }
    119 __strong_alias(mutex_spin_enter,mutex_enter);
    120 
    121 int
    122 mutex_tryenter(kmutex_t *mtx)
    123 {
    124 	int rv;
    125 
    126 	rv = rumpuser_mutex_tryenter(RUMPMTX(mtx));
    127 	if (rv) {
    128 		WANTLOCK(mtx, false, true);
    129 		LOCKED(mtx, false);
    130 	}
    131 	return rv;
    132 }
    133 
    134 void
    135 mutex_exit(kmutex_t *mtx)
    136 {
    137 
    138 	UNLOCKED(mtx, false);
    139 	rumpuser_mutex_exit(RUMPMTX(mtx));
    140 }
    141 __strong_alias(mutex_spin_exit,mutex_exit);
    142 
    143 int
    144 mutex_owned(kmutex_t *mtx)
    145 {
    146 
    147 	return mutex_owner(mtx) == curlwp;
    148 }
    149 
    150 struct lwp *
    151 mutex_owner(kmutex_t *mtx)
    152 {
    153 
    154 	return rumpuser_mutex_owner(RUMPMTX(mtx));
    155 }
    156 
    157 #define RUMPRW(rw) (*(struct rumpuser_rw **)(rw))
    158 
    159 /* reader/writer locks */
    160 
    161 void
    162 rw_init(krwlock_t *rw)
    163 {
    164 
    165 	CTASSERT(sizeof(krwlock_t) >= sizeof(void *));
    166 
    167 	rumpuser_rw_init((struct rumpuser_rw **)rw);
    168 	ALLOCK(rw, &rw_lockops);
    169 }
    170 
    171 void
    172 rw_destroy(krwlock_t *rw)
    173 {
    174 
    175 	FREELOCK(rw);
    176 	rumpuser_rw_destroy(RUMPRW(rw));
    177 }
    178 
    179 void
    180 rw_enter(krwlock_t *rw, const krw_t op)
    181 {
    182 
    183 
    184 	WANTLOCK(rw, op == RW_READER, false);
    185 	rumpuser_rw_enter(RUMPRW(rw), op == RW_WRITER);
    186 	LOCKED(rw, op == RW_READER);
    187 }
    188 
    189 int
    190 rw_tryenter(krwlock_t *rw, const krw_t op)
    191 {
    192 	int rv;
    193 
    194 	rv = rumpuser_rw_tryenter(RUMPRW(rw), op == RW_WRITER);
    195 	if (rv) {
    196 		WANTLOCK(rw, op == RW_READER, true);
    197 		LOCKED(rw, op == RW_READER);
    198 	}
    199 	return rv;
    200 }
    201 
    202 void
    203 rw_exit(krwlock_t *rw)
    204 {
    205 
    206 #ifdef LOCKDEBUG
    207 	bool shared = !rw_write_held(rw);
    208 
    209 	if (shared)
    210 		KASSERT(rw_read_held(rw));
    211 	UNLOCKED(rw, shared);
    212 #endif
    213 	rumpuser_rw_exit(RUMPRW(rw));
    214 }
    215 
    216 /* always fails */
    217 int
    218 rw_tryupgrade(krwlock_t *rw)
    219 {
    220 
    221 	return 0;
    222 }
    223 
    224 int
    225 rw_write_held(krwlock_t *rw)
    226 {
    227 
    228 	return rumpuser_rw_wrheld(RUMPRW(rw));
    229 }
    230 
    231 int
    232 rw_read_held(krwlock_t *rw)
    233 {
    234 
    235 	return rumpuser_rw_rdheld(RUMPRW(rw));
    236 }
    237 
    238 int
    239 rw_lock_held(krwlock_t *rw)
    240 {
    241 
    242 	return rumpuser_rw_held(RUMPRW(rw));
    243 }
    244 
    245 /* curriculum vitaes */
    246 
    247 #define RUMPCV(cv) (*(struct rumpuser_cv **)(cv))
    248 
    249 void
    250 cv_init(kcondvar_t *cv, const char *msg)
    251 {
    252 
    253 	CTASSERT(sizeof(kcondvar_t) >= sizeof(void *));
    254 
    255 	rumpuser_cv_init((struct rumpuser_cv **)cv);
    256 }
    257 
    258 void
    259 cv_destroy(kcondvar_t *cv)
    260 {
    261 
    262 	rumpuser_cv_destroy(RUMPCV(cv));
    263 }
    264 
    265 void
    266 cv_wait(kcondvar_t *cv, kmutex_t *mtx)
    267 {
    268 
    269 	if (__predict_false(rump_threads == 0))
    270 		panic("cv_wait without threads");
    271 	UNLOCKED(mtx, false);
    272 	rumpuser_cv_wait(RUMPCV(cv), RUMPMTX(mtx));
    273 	LOCKED(mtx, false);
    274 }
    275 
    276 int
    277 cv_wait_sig(kcondvar_t *cv, kmutex_t *mtx)
    278 {
    279 
    280 	if (__predict_false(rump_threads == 0))
    281 		panic("cv_wait without threads");
    282 	UNLOCKED(mtx, false);
    283 	rumpuser_cv_wait(RUMPCV(cv), RUMPMTX(mtx));
    284 	LOCKED(mtx, false);
    285 	return 0;
    286 }
    287 
    288 int
    289 cv_timedwait(kcondvar_t *cv, kmutex_t *mtx, int ticks)
    290 {
    291 	struct timespec ts, tick;
    292 	extern int hz;
    293 	int rv;
    294 
    295 	if (ticks == 0) {
    296 		cv_wait(cv, mtx);
    297 		rv = 0;
    298 	} else {
    299 		/*
    300 		 * XXX: this fetches rump kernel time, but
    301 		 * rumpuser_cv_timedwait uses host time.
    302 		 */
    303 		nanotime(&ts);
    304 		tick.tv_sec = ticks / hz;
    305 		tick.tv_nsec = (ticks % hz) * (1000000000/hz);
    306 		timespecadd(&ts, &tick, &ts);
    307 
    308 		UNLOCKED(mtx, false);
    309 		if (rumpuser_cv_timedwait(RUMPCV(cv), RUMPMTX(mtx),
    310 		    ts.tv_sec, ts.tv_nsec))
    311 			rv = EWOULDBLOCK;
    312 		else
    313 			rv = 0;
    314 		LOCKED(mtx, false);
    315 	}
    316 
    317 	return rv;
    318 }
    319 __strong_alias(cv_timedwait_sig,cv_timedwait);
    320 
    321 void
    322 cv_signal(kcondvar_t *cv)
    323 {
    324 
    325 	rumpuser_cv_signal(RUMPCV(cv));
    326 }
    327 
    328 void
    329 cv_broadcast(kcondvar_t *cv)
    330 {
    331 
    332 	rumpuser_cv_broadcast(RUMPCV(cv));
    333 }
    334 
    335 bool
    336 cv_has_waiters(kcondvar_t *cv)
    337 {
    338 
    339 	return rumpuser_cv_has_waiters(RUMPCV(cv));
    340 }
    341 
    342 /* this is not much of an attempt, but ... */
    343 bool
    344 cv_is_valid(kcondvar_t *cv)
    345 {
    346 
    347 	return RUMPCV(cv) != NULL;
    348 }
    349