1 /* $NetBSD: lock.h,v 1.46 2002/05/21 01:38:26 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * This code is derived from software contributed to The NetBSD Foundation 12 * by Ross Harvey. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the NetBSD 25 * Foundation, Inc. and its contributors. 26 * 4. Neither the name of The NetBSD Foundation nor the names of its 27 * contributors may be used to endorse or promote products derived 28 * from this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 * POSSIBILITY OF SUCH DAMAGE. 41 */ 42 43 /* 44 * Copyright (c) 1995 45 * The Regents of the University of California. All rights reserved. 46 * 47 * This code contains ideas from software contributed to Berkeley by 48 * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating 49 * System project at Carnegie-Mellon University. 50 * 51 * Redistribution and use in source and binary forms, with or without 52 * modification, are permitted provided that the following conditions 53 * are met: 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. All advertising materials mentioning features or use of this software 60 * must display the following acknowledgement: 61 * This product includes software developed by the University of 62 * California, Berkeley and its contributors. 63 * 4. Neither the name of the University nor the names of its contributors 64 * may be used to endorse or promote products derived from this software 65 * without specific prior written permission. 66 * 67 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 68 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 69 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 70 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 71 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 72 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 73 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 74 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 75 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 76 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 77 * SUCH DAMAGE. 78 * 79 * @(#)lock.h 8.12 (Berkeley) 5/19/95 80 */ 81 82 #ifndef _SYS_LOCK_H_ 83 #define _SYS_LOCK_H_ 84 85 #if defined(_KERNEL_OPT) 86 #include "opt_lockdebug.h" 87 #include "opt_multiprocessor.h" 88 #endif 89 90 #include <sys/queue.h> 91 #include <machine/lock.h> 92 93 /* 94 * The simple lock. Provides a simple spinning mutex. Note the 95 * member which is used in atomic operations must be aligned in 96 * order for it to work on the widest range of processor types. 97 */ 98 struct simplelock { 99 __cpu_simple_lock_t lock_data; 100 #ifdef LOCKDEBUG 101 const char *lock_file; 102 const char *unlock_file; 103 short lock_line; 104 short unlock_line; 105 TAILQ_ENTRY(simplelock) list; 106 cpuid_t lock_holder; /* CPU ID */ 107 #endif 108 }; 109 110 #ifdef LOCKDEBUG 111 #define SIMPLELOCK_INITIALIZER { __SIMPLELOCK_UNLOCKED, NULL, NULL, 0, \ 112 0, { NULL, NULL }, LK_NOCPU } 113 #else 114 #define SIMPLELOCK_INITIALIZER { __SIMPLELOCK_UNLOCKED } 115 #endif 116 117 /* 118 * The general lock structure. Provides for multiple shared locks, 119 * upgrading from shared to exclusive, and sleeping/spinning until the 120 * lock can be gained. 121 */ 122 struct lock { 123 struct simplelock lk_interlock; /* lock on remaining fields */ 124 u_int lk_flags; /* see below */ 125 int lk_sharecount; /* # of accepted shared locks */ 126 short lk_exclusivecount; /* # of recursive exclusive locks */ 127 short lk_recurselevel; /* lvl above which recursion ok */ 128 int lk_waitcount; /* # of sleepers/spinners */ 129 130 /* 131 * This is the sleep message for sleep locks, and a simple name 132 * for spin locks. 133 */ 134 const char *lk_wmesg; 135 136 union { 137 struct { 138 /* pid of exclusive lock holder */ 139 pid_t lk_sleep_lockholder; 140 141 /* priority at which to sleep */ 142 int lk_sleep_prio; 143 144 /* maximum sleep time (for tsleep) */ 145 int lk_sleep_timo; 146 } lk_un_sleep; 147 struct { 148 /* CPU ID of exclusive lock holder */ 149 cpuid_t lk_spin_cpu; 150 #if defined(LOCKDEBUG) 151 TAILQ_ENTRY(lock) lk_spin_list; 152 #endif 153 } lk_un_spin; 154 } lk_un; 155 156 #define lk_lockholder lk_un.lk_un_sleep.lk_sleep_lockholder 157 #define lk_prio lk_un.lk_un_sleep.lk_sleep_prio 158 #define lk_timo lk_un.lk_un_sleep.lk_sleep_timo 159 160 #define lk_cpu lk_un.lk_un_spin.lk_spin_cpu 161 #if defined(LOCKDEBUG) 162 #define lk_list lk_un.lk_un_spin.lk_spin_list 163 #endif 164 165 #if defined(LOCKDEBUG) 166 const char *lk_lock_file; 167 const char *lk_unlock_file; 168 int lk_lock_line; 169 int lk_unlock_line; 170 #endif 171 }; 172 173 /* 174 * Lock request types: 175 * LK_SHARED - get one of many possible shared locks. If a process 176 * holding an exclusive lock requests a shared lock, the exclusive 177 * lock(s) will be downgraded to shared locks. 178 * LK_EXCLUSIVE - stop further shared locks, when they are cleared, 179 * grant a pending upgrade if it exists, then grant an exclusive 180 * lock. Only one exclusive lock may exist at a time, except that 181 * a process holding an exclusive lock may get additional exclusive 182 * locks if it explicitly sets the LK_CANRECURSE flag in the lock 183 * request, or if the LK_CANRECUSE flag was set when the lock was 184 * initialized. 185 * LK_UPGRADE - the process must hold a shared lock that it wants to 186 * have upgraded to an exclusive lock. Other processes may get 187 * exclusive access to the resource between the time that the upgrade 188 * is requested and the time that it is granted. 189 * LK_EXCLUPGRADE - the process must hold a shared lock that it wants to 190 * have upgraded to an exclusive lock. If the request succeeds, no 191 * other processes will have gotten exclusive access to the resource 192 * between the time that the upgrade is requested and the time that 193 * it is granted. However, if another process has already requested 194 * an upgrade, the request will fail (see error returns below). 195 * LK_DOWNGRADE - the process must hold an exclusive lock that it wants 196 * to have downgraded to a shared lock. If the process holds multiple 197 * (recursive) exclusive locks, they will all be downgraded to shared 198 * locks. 199 * LK_RELEASE - release one instance of a lock. 200 * LK_DRAIN - wait for all activity on the lock to end, then mark it 201 * decommissioned. This feature is used before freeing a lock that 202 * is part of a piece of memory that is about to be freed. 203 * 204 * These are flags that are passed to the lockmgr routine. 205 */ 206 #define LK_TYPE_MASK 0x0000000f /* type of lock sought */ 207 #define LK_SHARED 0x00000001 /* shared lock */ 208 #define LK_EXCLUSIVE 0x00000002 /* exclusive lock */ 209 #define LK_UPGRADE 0x00000003 /* shared-to-exclusive upgrade */ 210 #define LK_EXCLUPGRADE 0x00000004 /* first shared-to-exclusive upgrade */ 211 #define LK_DOWNGRADE 0x00000005 /* exclusive-to-shared downgrade */ 212 #define LK_RELEASE 0x00000006 /* release any type of lock */ 213 #define LK_DRAIN 0x00000007 /* wait for all lock activity to end */ 214 /* 215 * External lock flags. 216 * 217 * The first three flags may be set in lock_init to set their mode permanently, 218 * or passed in as arguments to the lock manager. The LK_REENABLE flag may be 219 * set only at the release of a lock obtained by drain. 220 */ 221 #define LK_EXTFLG_MASK 0x00700070 /* mask of external flags */ 222 #define LK_NOWAIT 0x00000010 /* do not sleep to await lock */ 223 #define LK_SLEEPFAIL 0x00000020 /* sleep, then return failure */ 224 #define LK_CANRECURSE 0x00000040 /* this may be recursive lock attempt */ 225 #define LK_REENABLE 0x00000080 /* lock is be reenabled after drain */ 226 #define LK_SETRECURSE 0x00100000 /* other locks while we have it OK */ 227 #define LK_RECURSEFAIL 0x00200000 /* attempt at recursive lock fails */ 228 #define LK_SPIN 0x00400000 /* lock spins instead of sleeps */ 229 /* 230 * Internal lock flags. 231 * 232 * These flags are used internally to the lock manager. 233 */ 234 #define LK_WANT_UPGRADE 0x00000100 /* waiting for share-to-excl upgrade */ 235 #define LK_WANT_EXCL 0x00000200 /* exclusive lock sought */ 236 #define LK_HAVE_EXCL 0x00000400 /* exclusive lock obtained */ 237 #define LK_WAITDRAIN 0x00000800 /* process waiting for lock to drain */ 238 #define LK_DRAINING 0x00004000 /* lock is being drained */ 239 #define LK_DRAINED 0x00008000 /* lock has been decommissioned */ 240 /* 241 * Control flags 242 * 243 * Non-persistent external flags. 244 */ 245 #define LK_INTERLOCK 0x00010000 /* unlock passed simple lock after 246 getting lk_interlock */ 247 #define LK_RETRY 0x00020000 /* vn_lock: retry until locked */ 248 249 /* 250 * Lock return status. 251 * 252 * Successfully obtained locks return 0. Locks will always succeed 253 * unless one of the following is true: 254 * LK_FORCEUPGRADE is requested and some other process has already 255 * requested a lock upgrade (returns EBUSY). 256 * LK_WAIT is set and a sleep would be required (returns EBUSY). 257 * LK_SLEEPFAIL is set and a sleep was done (returns ENOLCK). 258 * PCATCH is set in lock priority and a signal arrives (returns 259 * either EINTR or ERESTART if system calls is to be restarted). 260 * Non-null lock timeout and timeout expires (returns EWOULDBLOCK). 261 * A failed lock attempt always returns a non-zero error value. No lock 262 * is held after an error return (in particular, a failed LK_UPGRADE 263 * or LK_FORCEUPGRADE will have released its shared access lock). 264 */ 265 266 /* 267 * Indicator that no process/cpu holds exclusive lock 268 */ 269 #define LK_KERNPROC ((pid_t) -2) 270 #define LK_NOPROC ((pid_t) -1) 271 #define LK_NOCPU ((cpuid_t) -1) 272 273 #ifdef _KERNEL 274 275 struct proc; 276 277 void lockinit(struct lock *, int prio, const char *wmesg, int timo, 278 int flags); 279 #if defined(LOCKDEBUG) 280 int _lockmgr(__volatile struct lock *, u_int flags, struct simplelock *, 281 const char *file, int line); 282 #define lockmgr(l, f, i) _lockmgr((l), (f), (i), __FILE__, __LINE__) 283 #else 284 int lockmgr(__volatile struct lock *, u_int flags, struct simplelock *); 285 #endif /* LOCKDEBUG */ 286 int lockstatus(struct lock *); 287 void lockmgr_printinfo(__volatile struct lock *); 288 289 #if defined(LOCKDEBUG) || defined(DIAGNOSTIC) 290 void spinlock_switchcheck(void); 291 #endif 292 293 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 294 #define spinlockinit(lkp, name, flags) \ 295 lockinit((lkp), 0, (name), 0, (flags) | LK_SPIN) 296 #define spinlockmgr(lkp, flags, intrlk) \ 297 lockmgr((lkp), (flags) | LK_SPIN, (intrlk)) 298 #else 299 #define spinlockinit(lkp, name, flags) (void)(lkp) 300 #define spinlockmgr(lkp, flags, intrlk) (0) 301 #endif 302 303 #if defined(LOCKDEBUG) 304 int _spinlock_release_all(__volatile struct lock *, const char *, int); 305 void _spinlock_acquire_count(__volatile struct lock *, int, const char *, 306 int); 307 308 #define spinlock_release_all(l) _spinlock_release_all((l), __FILE__, __LINE__) 309 #define spinlock_acquire_count(l, c) _spinlock_acquire_count((l), (c), \ 310 __FILE__, __LINE__) 311 #else 312 int spinlock_release_all(__volatile struct lock *); 313 void spinlock_acquire_count(__volatile struct lock *, int); 314 #endif 315 316 #if defined(LOCKDEBUG) 317 void _simple_lock(__volatile struct simplelock *, const char *, int); 318 int _simple_lock_try(__volatile struct simplelock *, const char *, int); 319 void _simple_unlock(__volatile struct simplelock *, const char *, int); 320 int _simple_lock_held(__volatile struct simplelock *); 321 void simple_lock_only_held(__volatile struct simplelock *, const char *); 322 323 #define simple_lock(alp) _simple_lock((alp), __FILE__, __LINE__) 324 #define simple_lock_try(alp) _simple_lock_try((alp), __FILE__, __LINE__) 325 #define simple_unlock(alp) _simple_unlock((alp), __FILE__, __LINE__) 326 #define simple_lock_held(alp) _simple_lock_held((alp)) 327 328 #define LOCK_ASSERT(x) KASSERT(x) 329 330 void simple_lock_init(struct simplelock *); 331 void simple_lock_dump(void); 332 void simple_lock_freecheck(void *, void *); 333 void simple_lock_switchcheck(void); 334 #elif defined(MULTIPROCESSOR) 335 #define simple_lock_init(alp) __cpu_simple_lock_init(&(alp)->lock_data) 336 #define simple_lock(alp) __cpu_simple_lock(&(alp)->lock_data) 337 #define simple_lock_try(alp) __cpu_simple_lock_try(&(alp)->lock_data) 338 #define simple_unlock(alp) __cpu_simple_unlock(&(alp)->lock_data) 339 #define LOCK_ASSERT(x) /* nothing */ 340 #define simple_lock_only_held(x,y) /* nothing */ 341 #else 342 #define simple_lock_init(alp) (alp)->lock_data = __SIMPLELOCK_UNLOCKED 343 #define simple_lock_try(alp) (1) 344 #ifndef lint 345 #define simple_lock(alp) (void)(alp) 346 #define simple_unlock(alp) (void)(alp) 347 #else /* lint */ 348 #define simple_lock(alp) /* nothing */ 349 #define simple_unlock(alp) /* nothing */ 350 #define simple_lock_only_held(x,y) /* nothing */ 351 #endif /* lint */ 352 #define LOCK_ASSERT(x) /* nothing */ 353 #endif 354 355 #if defined(MULTIPROCESSOR) 356 extern struct lock kernel_lock; 357 #endif 358 359 #endif /* _KERNEL */ 360 361 #endif /* _SYS_LOCK_H_ */ 362