Annotation of sys/kern/kern_lock.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: kern_lock.c,v 1.30 2007/05/31 22:07:53 thib Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1995
! 5: * The Regents of the University of California. All rights reserved.
! 6: *
! 7: * This code contains ideas from software contributed to Berkeley by
! 8: * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating
! 9: * System project at Carnegie-Mellon University.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. Neither the name of the University nor the names of its contributors
! 20: * may be used to endorse or promote products derived from this software
! 21: * without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: *
! 35: * @(#)kern_lock.c 8.18 (Berkeley) 5/21/95
! 36: */
! 37:
! 38: #include <sys/param.h>
! 39: #include <sys/proc.h>
! 40: #include <sys/lock.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/sched.h>
! 43:
! 44: #include <machine/cpu.h>
! 45:
! 46: #ifndef spllock
! 47: #define spllock() splhigh()
! 48: #endif
! 49:
! 50: #ifdef MULTIPROCESSOR
! 51: #define CPU_NUMBER() cpu_number()
! 52: #else
! 53: #define CPU_NUMBER() 0
! 54: #endif
! 55:
! 56: void record_stacktrace(int *, int);
! 57: void playback_stacktrace(int *, int);
! 58:
! 59: /*
! 60: * Locking primitives implementation.
! 61: * Locks provide shared/exclusive synchronization.
! 62: */
! 63:
! 64: #ifdef DDB /* { */
! 65: #ifdef MULTIPROCESSOR
! 66: int simple_lock_debugger = 1; /* more serious on MP */
! 67: #else
! 68: int simple_lock_debugger = 0;
! 69: #endif
! 70: #define SLOCK_DEBUGGER() if (simple_lock_debugger) Debugger()
! 71: #define SLOCK_TRACE() \
! 72: db_stack_trace_print((db_expr_t)__builtin_frame_address(0), \
! 73: TRUE, 65535, "", lock_printf);
! 74: #else
! 75: #define SLOCK_DEBUGGER() /* nothing */
! 76: #define SLOCK_TRACE() /* nothing */
! 77: #endif /* } */
! 78:
! 79: /*
! 80: * Acquire a resource.
! 81: */
! 82: #define ACQUIRE(lkp, error, extflags, drain, wanted) \
! 83: do { \
! 84: for (error = 0; wanted; ) { \
! 85: if ((drain)) \
! 86: (lkp)->lk_flags |= LK_WAITDRAIN; \
! 87: else \
! 88: (lkp)->lk_waitcount++; \
! 89: /* XXX Cast away volatile. */ \
! 90: error = tsleep((drain) ? \
! 91: (void *)&(lkp)->lk_flags : (void *)(lkp), \
! 92: (lkp)->lk_prio, (lkp)->lk_wmesg, (lkp)->lk_timo); \
! 93: if ((drain) == 0) \
! 94: (lkp)->lk_waitcount--; \
! 95: if (error) \
! 96: break; \
! 97: if ((extflags) & LK_SLEEPFAIL) { \
! 98: error = ENOLCK; \
! 99: break; \
! 100: } \
! 101: } \
! 102: } while (0)
! 103:
! 104: #define SETHOLDER(lkp, pid, cpu_id) \
! 105: (lkp)->lk_lockholder = (pid)
! 106:
! 107: #define WEHOLDIT(lkp, pid, cpu_id) \
! 108: (lkp)->lk_lockholder == (pid)
! 109:
! 110: #define WAKEUP_WAITER(lkp) \
! 111: do { \
! 112: if ((lkp)->lk_waitcount) { \
! 113: /* XXX Cast away volatile. */ \
! 114: wakeup((void *)(lkp)); \
! 115: } \
! 116: } while (/*CONSTCOND*/0)
! 117:
! 118: #if defined(LOCKDEBUG) /* { */
! 119: #if defined(MULTIPROCESSOR) /* { */
! 120: struct simplelock spinlock_list_slock = SIMPLELOCK_INITIALIZER;
! 121:
! 122: #define SPINLOCK_LIST_LOCK() \
! 123: __cpu_simple_lock(&spinlock_list_slock.lock_data)
! 124:
! 125: #define SPINLOCK_LIST_UNLOCK() \
! 126: __cpu_simple_unlock(&spinlock_list_slock.lock_data)
! 127: #else
! 128: #define SPINLOCK_LIST_LOCK() /* nothing */
! 129:
! 130: #define SPINLOCK_LIST_UNLOCK() /* nothing */
! 131: #endif /* MULTIPROCESSOR */ /* } */
! 132:
! 133: TAILQ_HEAD(, lock) spinlock_list =
! 134: TAILQ_HEAD_INITIALIZER(spinlock_list);
! 135: #endif /* LOCKDEBUG */ /* } */
! 136:
! 137: #define HAVEIT(lkp) \
! 138: do { \
! 139: } while (/*CONSTCOND*/0)
! 140:
! 141: #define DONTHAVEIT(lkp) \
! 142: do { \
! 143: } while (/*CONSTCOND*/0)
! 144:
! 145: #if defined(LOCKDEBUG)
! 146: /*
! 147: * Lock debug printing routine; can be configured to print to console
! 148: * or log to syslog.
! 149: */
! 150: void
! 151: lock_printf(const char *fmt, ...)
! 152: {
! 153: char b[150];
! 154: va_list ap;
! 155:
! 156: va_start(ap, fmt);
! 157: if (lock_debug_syslog)
! 158: vlog(LOG_DEBUG, fmt, ap);
! 159: else {
! 160: vsnprintf(b, sizeof(b), fmt, ap);
! 161: printf_nolog("%s", b);
! 162: }
! 163: va_end(ap);
! 164: }
! 165: #endif /* LOCKDEBUG */
! 166:
! 167: /*
! 168: * Initialize a lock; required before use.
! 169: */
! 170: void
! 171: lockinit(struct lock *lkp, int prio, char *wmesg, int timo, int flags)
! 172: {
! 173:
! 174: bzero(lkp, sizeof(struct lock));
! 175: lkp->lk_flags = flags & LK_EXTFLG_MASK;
! 176: lkp->lk_lockholder = LK_NOPROC;
! 177: lkp->lk_prio = prio;
! 178: lkp->lk_timo = timo;
! 179: lkp->lk_wmesg = wmesg; /* just a name for spin locks */
! 180: #if defined(LOCKDEBUG)
! 181: lkp->lk_lock_file = NULL;
! 182: lkp->lk_unlock_file = NULL;
! 183: #endif
! 184: }
! 185:
! 186: /*
! 187: * Determine the status of a lock.
! 188: */
! 189: int
! 190: lockstatus(struct lock *lkp)
! 191: {
! 192: int lock_type = 0;
! 193:
! 194: if (lkp->lk_exclusivecount != 0)
! 195: lock_type = LK_EXCLUSIVE;
! 196: else if (lkp->lk_sharecount != 0)
! 197: lock_type = LK_SHARED;
! 198: return (lock_type);
! 199: }
! 200:
! 201: /*
! 202: * Set, change, or release a lock.
! 203: *
! 204: * Shared requests increment the shared count. Exclusive requests set the
! 205: * LK_WANT_EXCL flag (preventing further shared locks), and wait for already
! 206: * accepted shared locks and shared-to-exclusive upgrades to go away.
! 207: */
! 208: int
! 209: lockmgr(__volatile struct lock *lkp, u_int flags, struct simplelock *interlkp)
! 210: {
! 211: int error;
! 212: pid_t pid;
! 213: int extflags;
! 214: cpuid_t cpu_id;
! 215: struct proc *p = curproc;
! 216:
! 217: error = 0;
! 218: extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
! 219:
! 220: #ifdef DIAGNOSTIC
! 221: if (p == NULL)
! 222: panic("lockmgr: process context required");
! 223: #endif
! 224: /* Process context required. */
! 225: pid = p->p_pid;
! 226: cpu_id = CPU_NUMBER();
! 227:
! 228: /*
! 229: * Once a lock has drained, the LK_DRAINING flag is set and an
! 230: * exclusive lock is returned. The only valid operation thereafter
! 231: * is a single release of that exclusive lock. This final release
! 232: * clears the LK_DRAINING flag and sets the LK_DRAINED flag. Any
! 233: * further requests of any sort will result in a panic. The bits
! 234: * selected for these two flags are chosen so that they will be set
! 235: * in memory that is freed (freed memory is filled with 0xdeadbeef).
! 236: */
! 237: if (lkp->lk_flags & (LK_DRAINING|LK_DRAINED)) {
! 238: #ifdef DIAGNOSTIC
! 239: if (lkp->lk_flags & LK_DRAINED)
! 240: panic("lockmgr: using decommissioned lock");
! 241: if ((flags & LK_TYPE_MASK) != LK_RELEASE ||
! 242: WEHOLDIT(lkp, pid, cpu_id) == 0)
! 243: panic("lockmgr: non-release on draining lock: %d",
! 244: flags & LK_TYPE_MASK);
! 245: #endif /* DIAGNOSTIC */
! 246: lkp->lk_flags &= ~LK_DRAINING;
! 247: lkp->lk_flags |= LK_DRAINED;
! 248: }
! 249:
! 250: /*
! 251: * Check if the caller is asking us to be schizophrenic.
! 252: */
! 253: if ((lkp->lk_flags & (LK_CANRECURSE|LK_RECURSEFAIL)) ==
! 254: (LK_CANRECURSE|LK_RECURSEFAIL))
! 255: panic("lockmgr: make up your mind");
! 256:
! 257: switch (flags & LK_TYPE_MASK) {
! 258:
! 259: case LK_SHARED:
! 260: if (WEHOLDIT(lkp, pid, cpu_id) == 0) {
! 261: /*
! 262: * If just polling, check to see if we will block.
! 263: */
! 264: if ((extflags & LK_NOWAIT) && (lkp->lk_flags &
! 265: (LK_HAVE_EXCL | LK_WANT_EXCL))) {
! 266: error = EBUSY;
! 267: break;
! 268: }
! 269: /*
! 270: * Wait for exclusive locks and upgrades to clear.
! 271: */
! 272: ACQUIRE(lkp, error, extflags, 0, lkp->lk_flags &
! 273: (LK_HAVE_EXCL | LK_WANT_EXCL));
! 274: if (error)
! 275: break;
! 276: lkp->lk_sharecount++;
! 277: break;
! 278: }
! 279: /*
! 280: * We hold an exclusive lock, so downgrade it to shared.
! 281: * An alternative would be to fail with EDEADLK.
! 282: */
! 283: lkp->lk_sharecount++;
! 284:
! 285: if (WEHOLDIT(lkp, pid, cpu_id) == 0 ||
! 286: lkp->lk_exclusivecount == 0)
! 287: panic("lockmgr: not holding exclusive lock");
! 288: lkp->lk_sharecount += lkp->lk_exclusivecount;
! 289: lkp->lk_exclusivecount = 0;
! 290: lkp->lk_flags &= ~LK_HAVE_EXCL;
! 291: SETHOLDER(lkp, LK_NOPROC, LK_NOCPU);
! 292: #if defined(LOCKDEBUG)
! 293: lkp->lk_unlock_file = file;
! 294: lkp->lk_unlock_line = line;
! 295: #endif
! 296: DONTHAVEIT(lkp);
! 297: WAKEUP_WAITER(lkp);
! 298: break;
! 299:
! 300: case LK_EXCLUSIVE:
! 301: if (WEHOLDIT(lkp, pid, cpu_id)) {
! 302: /*
! 303: * Recursive lock.
! 304: */
! 305: if ((extflags & LK_CANRECURSE) == 0) {
! 306: if (extflags & LK_RECURSEFAIL) {
! 307: error = EDEADLK;
! 308: break;
! 309: } else
! 310: panic("lockmgr: locking against myself");
! 311: }
! 312: lkp->lk_exclusivecount++;
! 313: break;
! 314: }
! 315: /*
! 316: * If we are just polling, check to see if we will sleep.
! 317: */
! 318: if ((extflags & LK_NOWAIT) && ((lkp->lk_flags &
! 319: (LK_HAVE_EXCL | LK_WANT_EXCL)) ||
! 320: lkp->lk_sharecount != 0)) {
! 321: error = EBUSY;
! 322: break;
! 323: }
! 324: /*
! 325: * Try to acquire the want_exclusive flag.
! 326: */
! 327: ACQUIRE(lkp, error, extflags, 0, lkp->lk_flags &
! 328: (LK_HAVE_EXCL | LK_WANT_EXCL));
! 329: if (error)
! 330: break;
! 331: lkp->lk_flags |= LK_WANT_EXCL;
! 332: /*
! 333: * Wait for shared locks and upgrades to finish.
! 334: */
! 335: ACQUIRE(lkp, error, extflags, 0, lkp->lk_sharecount != 0);
! 336: lkp->lk_flags &= ~LK_WANT_EXCL;
! 337: if (error)
! 338: break;
! 339: lkp->lk_flags |= LK_HAVE_EXCL;
! 340: SETHOLDER(lkp, pid, cpu_id);
! 341: #if defined(LOCKDEBUG)
! 342: lkp->lk_lock_file = file;
! 343: lkp->lk_lock_line = line;
! 344: #endif
! 345: HAVEIT(lkp);
! 346: if (lkp->lk_exclusivecount != 0)
! 347: panic("lockmgr: non-zero exclusive count");
! 348: lkp->lk_exclusivecount = 1;
! 349: break;
! 350:
! 351: case LK_RELEASE:
! 352: if (lkp->lk_exclusivecount != 0) {
! 353: if (WEHOLDIT(lkp, pid, cpu_id) == 0) {
! 354: panic("lockmgr: pid %d, not exclusive lock "
! 355: "holder %d unlocking",
! 356: pid, lkp->lk_lockholder);
! 357: }
! 358: lkp->lk_exclusivecount--;
! 359: if (lkp->lk_exclusivecount == 0) {
! 360: lkp->lk_flags &= ~LK_HAVE_EXCL;
! 361: SETHOLDER(lkp, LK_NOPROC, LK_NOCPU);
! 362: #if defined(LOCKDEBUG)
! 363: lkp->lk_unlock_file = file;
! 364: lkp->lk_unlock_line = line;
! 365: #endif
! 366: DONTHAVEIT(lkp);
! 367: }
! 368: } else if (lkp->lk_sharecount != 0) {
! 369: lkp->lk_sharecount--;
! 370: }
! 371: #ifdef DIAGNOSTIC
! 372: else
! 373: panic("lockmgr: release of unlocked lock!");
! 374: #endif
! 375: WAKEUP_WAITER(lkp);
! 376: break;
! 377:
! 378: case LK_DRAIN:
! 379: /*
! 380: * Check that we do not already hold the lock, as it can
! 381: * never drain if we do. Unfortunately, we have no way to
! 382: * check for holding a shared lock, but at least we can
! 383: * check for an exclusive one.
! 384: */
! 385: if (WEHOLDIT(lkp, pid, cpu_id))
! 386: panic("lockmgr: draining against myself");
! 387: /*
! 388: * If we are just polling, check to see if we will sleep.
! 389: */
! 390: if ((extflags & LK_NOWAIT) && ((lkp->lk_flags &
! 391: (LK_HAVE_EXCL | LK_WANT_EXCL)) ||
! 392: lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0)) {
! 393: error = EBUSY;
! 394: break;
! 395: }
! 396: ACQUIRE(lkp, error, extflags, 1,
! 397: ((lkp->lk_flags &
! 398: (LK_HAVE_EXCL | LK_WANT_EXCL)) ||
! 399: lkp->lk_sharecount != 0 ||
! 400: lkp->lk_waitcount != 0));
! 401: if (error)
! 402: break;
! 403: lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL;
! 404: SETHOLDER(lkp, pid, cpu_id);
! 405: #if defined(LOCKDEBUG)
! 406: lkp->lk_lock_file = file;
! 407: lkp->lk_lock_line = line;
! 408: #endif
! 409: HAVEIT(lkp);
! 410: lkp->lk_exclusivecount = 1;
! 411: break;
! 412:
! 413: default:
! 414: panic("lockmgr: unknown locktype request %d",
! 415: flags & LK_TYPE_MASK);
! 416: /* NOTREACHED */
! 417: }
! 418: if ((lkp->lk_flags & LK_WAITDRAIN) != 0 &&
! 419: ((lkp->lk_flags &
! 420: (LK_HAVE_EXCL | LK_WANT_EXCL)) == 0 &&
! 421: lkp->lk_sharecount == 0 && lkp->lk_waitcount == 0)) {
! 422: lkp->lk_flags &= ~LK_WAITDRAIN;
! 423: wakeup((void *)&lkp->lk_flags);
! 424: }
! 425: return (error);
! 426: }
! 427:
! 428: #ifdef DIAGNOSTIC
! 429: /*
! 430: * Print out information about state of a lock. Used by VOP_PRINT
! 431: * routines to display ststus about contained locks.
! 432: */
! 433: void
! 434: lockmgr_printinfo(__volatile struct lock *lkp)
! 435: {
! 436:
! 437: if (lkp->lk_sharecount)
! 438: printf(" lock type %s: SHARED (count %d)", lkp->lk_wmesg,
! 439: lkp->lk_sharecount);
! 440: else if (lkp->lk_flags & LK_HAVE_EXCL) {
! 441: printf(" lock type %s: EXCL (count %d) by ",
! 442: lkp->lk_wmesg, lkp->lk_exclusivecount);
! 443: printf("pid %d", lkp->lk_lockholder);
! 444: } else
! 445: printf(" not locked");
! 446: if (lkp->lk_waitcount > 0)
! 447: printf(" with %d pending", lkp->lk_waitcount);
! 448: }
! 449: #endif /* DIAGNOSTIC */
! 450:
! 451: #if defined(LOCKDEBUG)
! 452: TAILQ_HEAD(, simplelock) simplelock_list =
! 453: TAILQ_HEAD_INITIALIZER(simplelock_list);
! 454:
! 455: #if defined(MULTIPROCESSOR) /* { */
! 456: struct simplelock simplelock_list_slock = SIMPLELOCK_INITIALIZER;
! 457:
! 458: #define SLOCK_LIST_LOCK() \
! 459: __cpu_simple_lock(&simplelock_list_slock.lock_data)
! 460:
! 461: #define SLOCK_LIST_UNLOCK() \
! 462: __cpu_simple_unlock(&simplelock_list_slock.lock_data)
! 463:
! 464: #define SLOCK_COUNT(x) \
! 465: curcpu()->ci_simple_locks += (x)
! 466: #else
! 467: u_long simple_locks;
! 468:
! 469: #define SLOCK_LIST_LOCK() /* nothing */
! 470:
! 471: #define SLOCK_LIST_UNLOCK() /* nothing */
! 472:
! 473: #define SLOCK_COUNT(x) simple_locks += (x)
! 474: #endif /* MULTIPROCESSOR */ /* } */
! 475:
! 476: #ifdef MULTIPROCESSOR
! 477: #define SLOCK_MP() lock_printf("on cpu %ld\n", \
! 478: (u_long) cpu_number())
! 479: #else
! 480: #define SLOCK_MP() /* nothing */
! 481: #endif
! 482:
! 483: #define SLOCK_WHERE(str, alp, id, l) \
! 484: do { \
! 485: lock_printf("\n"); \
! 486: lock_printf(str); \
! 487: lock_printf("lock: %p, currently at: %s:%d\n", (alp), (id), (l)); \
! 488: SLOCK_MP(); \
! 489: if ((alp)->lock_file != NULL) \
! 490: lock_printf("last locked: %s:%d\n", (alp)->lock_file, \
! 491: (alp)->lock_line); \
! 492: if ((alp)->unlock_file != NULL) \
! 493: lock_printf("last unlocked: %s:%d\n", (alp)->unlock_file, \
! 494: (alp)->unlock_line); \
! 495: SLOCK_TRACE() \
! 496: SLOCK_DEBUGGER(); \
! 497: } while (/*CONSTCOND*/0)
! 498:
! 499: /*
! 500: * Simple lock functions so that the debugger can see from whence
! 501: * they are being called.
! 502: */
! 503: void
! 504: simple_lock_init(struct simplelock *lkp)
! 505: {
! 506:
! 507: #if defined(MULTIPROCESSOR) /* { */
! 508: __cpu_simple_lock_init(&alp->lock_data);
! 509: #else
! 510: alp->lock_data = __SIMPLELOCK_UNLOCKED;
! 511: #endif /* } */
! 512: alp->lock_file = NULL;
! 513: alp->lock_line = 0;
! 514: alp->unlock_file = NULL;
! 515: alp->unlock_line = 0;
! 516: alp->lock_holder = LK_NOCPU;
! 517: }
! 518:
! 519: void
! 520: _simple_lock(__volatile struct simplelock *lkp, const char *id, int l)
! 521: {
! 522: cpuid_t cpu_id = CPU_NUMBER();
! 523: int s;
! 524:
! 525: s = spllock();
! 526:
! 527: /*
! 528: * MULTIPROCESSOR case: This is `safe' since if it's not us, we
! 529: * don't take any action, and just fall into the normal spin case.
! 530: */
! 531: if (alp->lock_data == __SIMPLELOCK_LOCKED) {
! 532: #if defined(MULTIPROCESSOR) /* { */
! 533: if (alp->lock_holder == cpu_id) {
! 534: SLOCK_WHERE("simple_lock: locking against myself\n",
! 535: alp, id, l);
! 536: goto out;
! 537: }
! 538: #else
! 539: SLOCK_WHERE("simple_lock: lock held\n", alp, id, l);
! 540: goto out;
! 541: #endif /* MULTIPROCESSOR */ /* } */
! 542: }
! 543:
! 544: #if defined(MULTIPROCESSOR) /* { */
! 545: /* Acquire the lock before modifying any fields. */
! 546: splx(s);
! 547: __cpu_simple_lock(&alp->lock_data);
! 548: s = spllock();
! 549: #else
! 550: alp->lock_data = __SIMPLELOCK_LOCKED;
! 551: #endif /* } */
! 552:
! 553: if (alp->lock_holder != LK_NOCPU) {
! 554: SLOCK_WHERE("simple_lock: uninitialized lock\n",
! 555: alp, id, l);
! 556: }
! 557: alp->lock_file = id;
! 558: alp->lock_line = l;
! 559: alp->lock_holder = cpu_id;
! 560:
! 561: SLOCK_LIST_LOCK();
! 562: /* XXX Cast away volatile */
! 563: TAILQ_INSERT_TAIL(&simplelock_list, (struct simplelock *)alp, list);
! 564: SLOCK_LIST_UNLOCK();
! 565:
! 566: SLOCK_COUNT(1);
! 567:
! 568: out:
! 569: splx(s);
! 570: }
! 571:
! 572: int
! 573: _simple_lock_held(__volatile struct simplelock *alp)
! 574: {
! 575: cpuid_t cpu_id = CPU_NUMBER();
! 576: int s, locked = 0;
! 577:
! 578: s = spllock();
! 579:
! 580: #if defined(MULTIPROCESSOR)
! 581: if (__cpu_simple_lock_try(&alp->lock_data) == 0)
! 582: locked = (alp->lock_holder == cpu_id);
! 583: else
! 584: __cpu_simple_unlock(&alp->lock_data);
! 585: #else
! 586: if (alp->lock_data == __SIMPLELOCK_LOCKED) {
! 587: locked = 1;
! 588: KASSERT(alp->lock_holder == cpu_id);
! 589: }
! 590: #endif
! 591:
! 592: splx(s);
! 593:
! 594: return (locked);
! 595: }
! 596:
! 597: int
! 598: _simple_lock_try(__volatile struct simplelock *lkp, const char *id, int l)
! 599: {
! 600: cpuid_t cpu_id = CPU_NUMBER();
! 601: int s, rv = 0;
! 602:
! 603: s = spllock();
! 604:
! 605: /*
! 606: * MULTIPROCESSOR case: This is `safe' since if it's not us, we
! 607: * don't take any action.
! 608: */
! 609: #if defined(MULTIPROCESSOR) /* { */
! 610: if ((rv = __cpu_simple_lock_try(&alp->lock_data)) == 0) {
! 611: if (alp->lock_holder == cpu_id)
! 612: SLOCK_WHERE("simple_lock_try: locking against myself\n",
! 613: alp, id, l);
! 614: goto out;
! 615: }
! 616: #else
! 617: if (alp->lock_data == __SIMPLELOCK_LOCKED) {
! 618: SLOCK_WHERE("simple_lock_try: lock held\n", alp, id, l);
! 619: goto out;
! 620: }
! 621: alp->lock_data = __SIMPLELOCK_LOCKED;
! 622: #endif /* MULTIPROCESSOR */ /* } */
! 623:
! 624: /*
! 625: * At this point, we have acquired the lock.
! 626: */
! 627:
! 628: rv = 1;
! 629:
! 630: alp->lock_file = id;
! 631: alp->lock_line = l;
! 632: alp->lock_holder = cpu_id;
! 633:
! 634: SLOCK_LIST_LOCK();
! 635: /* XXX Cast away volatile. */
! 636: TAILQ_INSERT_TAIL(&simplelock_list, (struct simplelock *)alp, list);
! 637: SLOCK_LIST_UNLOCK();
! 638:
! 639: SLOCK_COUNT(1);
! 640:
! 641: out:
! 642: splx(s);
! 643: return (rv);
! 644: }
! 645:
! 646: void
! 647: _simple_unlock(__volatile struct simplelock *lkp, const char *id, int l)
! 648: {
! 649: int s;
! 650:
! 651: s = spllock();
! 652:
! 653: /*
! 654: * MULTIPROCESSOR case: This is `safe' because we think we hold
! 655: * the lock, and if we don't, we don't take any action.
! 656: */
! 657: if (alp->lock_data == __SIMPLELOCK_UNLOCKED) {
! 658: SLOCK_WHERE("simple_unlock: lock not held\n",
! 659: alp, id, l);
! 660: goto out;
! 661: }
! 662:
! 663: SLOCK_LIST_LOCK();
! 664: TAILQ_REMOVE(&simplelock_list, alp, list);
! 665: SLOCK_LIST_UNLOCK();
! 666:
! 667: SLOCK_COUNT(-1);
! 668:
! 669: alp->list.tqe_next = NULL; /* sanity */
! 670: alp->list.tqe_prev = NULL; /* sanity */
! 671:
! 672: alp->unlock_file = id;
! 673: alp->unlock_line = l;
! 674:
! 675: #if defined(MULTIPROCESSOR) /* { */
! 676: alp->lock_holder = LK_NOCPU;
! 677: /* Now that we've modified all fields, release the lock. */
! 678: __cpu_simple_unlock(&alp->lock_data);
! 679: #else
! 680: alp->lock_data = __SIMPLELOCK_UNLOCKED;
! 681: KASSERT(alp->lock_holder == CPU_NUMBER());
! 682: alp->lock_holder = LK_NOCPU;
! 683: #endif /* } */
! 684:
! 685: out:
! 686: splx(s);
! 687: }
! 688:
! 689: void
! 690: simple_lock_dump(void)
! 691: {
! 692: struct simplelock *alp;
! 693: int s;
! 694:
! 695: s = spllock();
! 696: SLOCK_LIST_LOCK();
! 697: lock_printf("all simple locks:\n");
! 698: TAILQ_FOREACH(alp, &simplelock_list, list) {
! 699: lock_printf("%p CPU %lu %s:%d\n", alp, alp->lock_holder,
! 700: alp->lock_file, alp->lock_line);
! 701: }
! 702: SLOCK_LIST_UNLOCK();
! 703: splx(s);
! 704: }
! 705:
! 706: void
! 707: simple_lock_freecheck(void *start, void *end)
! 708: {
! 709: struct simplelock *alp;
! 710: int s;
! 711:
! 712: s = spllock();
! 713: SLOCK_LIST_LOCK();
! 714: TAILQ_FOREACH(alp, &simplelock_list, list) {
! 715: if ((void *)alp >= start && (void *)alp < end) {
! 716: lock_printf("freeing simple_lock %p CPU %lu %s:%d\n",
! 717: alp, alp->lock_holder, alp->lock_file,
! 718: alp->lock_line);
! 719: SLOCK_DEBUGGER();
! 720: }
! 721: }
! 722: SLOCK_LIST_UNLOCK();
! 723: splx(s);
! 724: }
! 725:
! 726: /*
! 727: * We must be holding exactly one lock: the sched_lock.
! 728: */
! 729:
! 730: #ifdef notyet
! 731: void
! 732: simple_lock_switchcheck(void)
! 733: {
! 734:
! 735: simple_lock_only_held(&sched_lock, "switching");
! 736: }
! 737: #endif
! 738:
! 739: void
! 740: simple_lock_only_held(volatile struct simplelock *lp, const char *where)
! 741: {
! 742: struct simplelock *alp;
! 743: cpuid_t cpu_id = CPU_NUMBER();
! 744: int s;
! 745:
! 746: if (lp) {
! 747: LOCK_ASSERT(simple_lock_held(lp));
! 748: }
! 749: s = spllock();
! 750: SLOCK_LIST_LOCK();
! 751: TAILQ_FOREACH(alp, &simplelock_list, list) {
! 752: if (alp == lp)
! 753: continue;
! 754: if (alp->lock_holder == cpu_id)
! 755: break;
! 756: }
! 757: SLOCK_LIST_UNLOCK();
! 758: splx(s);
! 759:
! 760: if (alp != NULL) {
! 761: lock_printf("\n%s with held simple_lock %p "
! 762: "CPU %lu %s:%d\n",
! 763: where, alp, alp->lock_holder, alp->lock_file,
! 764: alp->lock_line);
! 765: SLOCK_TRACE();
! 766: SLOCK_DEBUGGER();
! 767: }
! 768: }
! 769: #endif /* LOCKDEBUG */
! 770:
! 771: #if defined(MULTIPROCESSOR)
! 772: /*
! 773: * Functions for manipulating the kernel_lock. We put them here
! 774: * so that they show up in profiles.
! 775: */
! 776:
! 777: struct __mp_lock kernel_lock;
! 778:
! 779: void
! 780: _kernel_lock_init(void)
! 781: {
! 782: __mp_lock_init(&kernel_lock);
! 783: }
! 784:
! 785: /*
! 786: * Acquire/release the kernel lock. Intended for use in the scheduler
! 787: * and the lower half of the kernel.
! 788: */
! 789:
! 790: void
! 791: _kernel_lock(void)
! 792: {
! 793: SCHED_ASSERT_UNLOCKED();
! 794: __mp_lock(&kernel_lock);
! 795: }
! 796:
! 797: void
! 798: _kernel_unlock(void)
! 799: {
! 800: __mp_unlock(&kernel_lock);
! 801: }
! 802:
! 803: /*
! 804: * Acquire/release the kernel_lock on behalf of a process. Intended for
! 805: * use in the top half of the kernel.
! 806: */
! 807: void
! 808: _kernel_proc_lock(struct proc *p)
! 809: {
! 810: SCHED_ASSERT_UNLOCKED();
! 811: __mp_lock(&kernel_lock);
! 812: atomic_setbits_int(&p->p_flag, P_BIGLOCK);
! 813: }
! 814:
! 815: void
! 816: _kernel_proc_unlock(struct proc *p)
! 817: {
! 818: atomic_clearbits_int(&p->p_flag, P_BIGLOCK);
! 819: __mp_unlock(&kernel_lock);
! 820: }
! 821:
! 822: #ifdef MP_LOCKDEBUG
! 823: /* CPU-dependent timing, needs this to be settable from ddb. */
! 824: int __mp_lock_spinout = 200000000;
! 825: #endif
! 826:
! 827: #endif /* MULTIPROCESSOR */
CVSweb