1 /* $NetBSD: ltsleep.c,v 1.25 2009/12/20 13:56:36 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2007 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 /* 32 * Emulate the prehistoric tsleep-style kernel interfaces. We assume 33 * only code under the biglock will be using this type of synchronization 34 * and use the biglock as the cv interlock. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: ltsleep.c,v 1.25 2009/12/20 13:56:36 pooka Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/kernel.h> 42 #include <sys/proc.h> 43 #include <sys/queue.h> 44 #include <sys/simplelock.h> 45 46 #include <rump/rumpuser.h> 47 48 #include "rump_private.h" 49 50 struct ltsleeper { 51 wchan_t id; 52 struct rumpuser_cv *cv; 53 LIST_ENTRY(ltsleeper) entries; 54 }; 55 56 static LIST_HEAD(, ltsleeper) sleepers = LIST_HEAD_INITIALIZER(sleepers); 57 58 static int 59 sleeper(struct ltsleeper *ltsp, int timo) 60 { 61 struct timespec ts, ticks; 62 int rv, nlocks; 63 64 LIST_INSERT_HEAD(&sleepers, ltsp, entries); 65 kernel_unlock_allbutone(&nlocks); 66 67 /* protected by biglock */ 68 if (timo) { 69 /* 70 * Calculate wakeup-time. 71 * XXX: should assert nanotime() does not block, 72 * i.e. yield the cpu and/or biglock. 73 */ 74 ticks.tv_sec = timo / hz; 75 ticks.tv_nsec = (timo % hz) * (1000000000/hz); 76 nanotime(&ts); 77 timespecadd(&ts, &ticks, &ts); 78 79 if (rumpuser_cv_timedwait(ltsp->cv, rump_giantlock, 80 ts.tv_sec, ts.tv_nsec) == 0) 81 rv = 0; 82 else 83 rv = EWOULDBLOCK; 84 } else { 85 rumpuser_cv_wait(ltsp->cv, rump_giantlock); 86 rv = 0; 87 } 88 89 LIST_REMOVE(ltsp, entries); 90 rumpuser_cv_destroy(ltsp->cv); 91 kernel_ununlock_allbutone(nlocks); 92 93 return rv; 94 } 95 96 int 97 ltsleep(wchan_t ident, pri_t prio, const char *wmesg, int timo, 98 volatile struct simplelock *slock) 99 { 100 struct ltsleeper lts; 101 int rv; 102 103 lts.id = ident; 104 rumpuser_cv_init(<s.cv); 105 106 if (slock) 107 simple_unlock(slock); 108 109 rv = sleeper(<s, timo); 110 111 if (slock && (prio & PNORELOCK) == 0) 112 simple_lock(slock); 113 114 return rv; 115 } 116 117 int 118 mtsleep(wchan_t ident, pri_t prio, const char *wmesg, int timo, 119 kmutex_t *lock) 120 { 121 struct ltsleeper lts; 122 int rv; 123 124 lts.id = ident; 125 rumpuser_cv_init(<s.cv); 126 127 mutex_exit(lock); 128 129 rv = sleeper(<s, timo); 130 131 if ((prio & PNORELOCK) == 0) 132 mutex_enter(lock); 133 134 return rv; 135 } 136 137 static void 138 do_wakeup(wchan_t ident, void (*wakeupfn)(struct rumpuser_cv *)) 139 { 140 struct ltsleeper *ltsp; 141 142 KASSERT(kernel_biglocked()); 143 LIST_FOREACH(ltsp, &sleepers, entries) { 144 if (ltsp->id == ident) { 145 wakeupfn(ltsp->cv); 146 } 147 } 148 } 149 150 void 151 wakeup(wchan_t ident) 152 { 153 154 do_wakeup(ident, rumpuser_cv_broadcast); 155 } 156 157 void 158 wakeup_one(wchan_t ident) 159 { 160 161 do_wakeup(ident, rumpuser_cv_signal); 162 } 163