FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_lock.c
1 /*
2 * Copyright (c) 1995
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (C) 1997
5 * John S. Dyson. All rights reserved.
6 * Copyright (C) 2013
7 * Matthew Dillon, All rights reserved.
8 *
9 * This code contains ideas from software contributed to Berkeley by
10 * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating
11 * System project at Carnegie-Mellon University.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #include "opt_lint.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/proc.h>
44 #include <sys/lock.h>
45 #include <sys/sysctl.h>
46 #include <sys/spinlock.h>
47 #include <sys/thread2.h>
48 #include <sys/spinlock2.h>
49
50 static void undo_upreq(struct lock *lkp);
51
52 /*
53 * Locking primitives implementation.
54 * Locks provide shared/exclusive sychronization.
55 */
56
57 #ifdef DEBUG_LOCKS
58 #define COUNT(td, x) (td)->td_locks += (x)
59 #else
60 #define COUNT(td, x)
61 #endif
62
63 #define LOCK_WAIT_TIME 100
64 #define LOCK_SAMPLE_WAIT 7
65
66 /*
67 * Set, change, or release a lock.
68 *
69 */
70 int
71 #ifndef DEBUG_LOCKS
72 lockmgr(struct lock *lkp, u_int flags)
73 #else
74 debuglockmgr(struct lock *lkp, u_int flags,
75 const char *name, const char *file, int line)
76 #endif
77 {
78 thread_t td;
79 thread_t otd;
80 int error;
81 int extflags;
82 int count;
83 int pflags;
84 int wflags;
85 int timo;
86 #ifdef DEBUG_LOCKS
87 int i;
88 #endif
89
90 error = 0;
91
92 if (mycpu->gd_intr_nesting_level &&
93 (flags & LK_NOWAIT) == 0 &&
94 (flags & LK_TYPE_MASK) != LK_RELEASE &&
95 panic_cpu_gd != mycpu
96 ) {
97
98 #ifndef DEBUG_LOCKS
99 panic("lockmgr %s from %p: called from interrupt, ipi, "
100 "or hard code section",
101 lkp->lk_wmesg, ((int **)&lkp)[-1]);
102 #else
103 panic("lockmgr %s from %s:%d: called from interrupt, ipi, "
104 "or hard code section",
105 lkp->lk_wmesg, file, line);
106 #endif
107 }
108
109 #ifdef DEBUG_LOCKS
110 if (mycpu->gd_spinlocks && ((flags & LK_NOWAIT) == 0)) {
111 panic("lockmgr %s from %s:%d: called with %d spinlocks held",
112 lkp->lk_wmesg, file, line, mycpu->gd_spinlocks);
113 }
114 #endif
115
116 extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
117 td = curthread;
118
119 again:
120 count = lkp->lk_count;
121 cpu_ccfence();
122
123 switch (flags & LK_TYPE_MASK) {
124 case LK_SHARED:
125 /*
126 * Shared lock critical path case
127 */
128 if ((count & (LKC_EXREQ|LKC_UPREQ|LKC_EXCL)) == 0) {
129 if (atomic_cmpset_int(&lkp->lk_count,
130 count, count + 1)) {
131 COUNT(td, 1);
132 break;
133 }
134 goto again;
135 }
136
137 /*
138 * If the caller already holds the lock exclusively then
139 * we silently obtain another count on the exclusive lock.
140 *
141 * WARNING! The old FreeBSD behavior was to downgrade,
142 * but this creates a problem when recursions
143 * return to the caller and the caller expects
144 * its original exclusive lock to remain exclusively
145 * locked.
146 */
147 if (lkp->lk_lockholder == td) {
148 KKASSERT(count & LKC_EXCL);
149 if ((extflags & LK_CANRECURSE) == 0) {
150 if (extflags & LK_NOWAIT) {
151 error = EBUSY;
152 break;
153 }
154 panic("lockmgr: locking against myself");
155 }
156 atomic_add_int(&lkp->lk_count, 1);
157 COUNT(td, 1);
158 break;
159 }
160
161 /*
162 * Slow path
163 */
164 pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
165 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
166 wflags = (td->td_flags & TDF_DEADLKTREAT) ?
167 LKC_EXCL : (LKC_EXCL|LKC_EXREQ|LKC_UPREQ);
168
169 /*
170 * Block while the lock is held exclusively or, conditionally,
171 * if other threads are tring to obtain an exclusive lock or
172 * upgrade to one.
173 */
174 if (count & wflags) {
175 if (extflags & LK_NOWAIT) {
176 error = EBUSY;
177 break;
178 }
179 tsleep_interlock(lkp, pflags);
180 if (!atomic_cmpset_int(&lkp->lk_count, count,
181 count | LKC_SHREQ)) {
182 goto again;
183 }
184
185 mycpu->gd_cnt.v_lock_name[0] = 'S';
186 strncpy(mycpu->gd_cnt.v_lock_name + 1,
187 lkp->lk_wmesg,
188 sizeof(mycpu->gd_cnt.v_lock_name) - 2);
189 ++mycpu->gd_cnt.v_lock_colls;
190
191 error = tsleep(lkp, pflags | PINTERLOCKED,
192 lkp->lk_wmesg, timo);
193 if (error)
194 break;
195 if (extflags & LK_SLEEPFAIL) {
196 error = ENOLCK;
197 break;
198 }
199 goto again;
200 }
201
202 /*
203 * Otherwise we can bump the count
204 */
205 if (atomic_cmpset_int(&lkp->lk_count, count, count + 1)) {
206 COUNT(td, 1);
207 break;
208 }
209 goto again;
210
211 case LK_EXCLUSIVE:
212 /*
213 * Exclusive lock critical path.
214 */
215 if (count == 0) {
216 if (atomic_cmpset_int(&lkp->lk_count, count,
217 LKC_EXCL | (count + 1))) {
218 lkp->lk_lockholder = td;
219 COUNT(td, 1);
220 break;
221 }
222 goto again;
223 }
224
225 /*
226 * Recursive lock if we already hold it exclusively.
227 */
228 if (lkp->lk_lockholder == td) {
229 KKASSERT(count & LKC_EXCL);
230 if ((extflags & LK_CANRECURSE) == 0) {
231 if (extflags & LK_NOWAIT) {
232 error = EBUSY;
233 break;
234 }
235 panic("lockmgr: locking against myself");
236 }
237 atomic_add_int(&lkp->lk_count, 1);
238 COUNT(td, 1);
239 break;
240 }
241
242 /*
243 * We will block, handle LK_NOWAIT
244 */
245 if (extflags & LK_NOWAIT) {
246 error = EBUSY;
247 break;
248 }
249
250 /*
251 * Wait until we can obtain the exclusive lock. EXREQ is
252 * automatically cleared when all current holders release
253 * so if we abort the operation we can safely leave it set.
254 * There might be other exclusive requesters.
255 */
256 pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
257 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
258
259 tsleep_interlock(lkp, pflags);
260 if (!atomic_cmpset_int(&lkp->lk_count, count,
261 count | LKC_EXREQ)) {
262 goto again;
263 }
264
265 mycpu->gd_cnt.v_lock_name[0] = 'X';
266 strncpy(mycpu->gd_cnt.v_lock_name + 1,
267 lkp->lk_wmesg,
268 sizeof(mycpu->gd_cnt.v_lock_name) - 2);
269 ++mycpu->gd_cnt.v_lock_colls;
270
271 error = tsleep(lkp, pflags | PINTERLOCKED,
272 lkp->lk_wmesg, timo);
273 if (error)
274 break;
275 if (extflags & LK_SLEEPFAIL) {
276 error = ENOLCK;
277 break;
278 }
279 goto again;
280
281 case LK_DOWNGRADE:
282 /*
283 * Downgrade an exclusive lock into a shared lock. All
284 * counts on a recursive exclusive lock become shared.
285 *
286 * This function always succeeds.
287 */
288 if (lkp->lk_lockholder != td ||
289 (count & (LKC_EXCL|LKC_MASK)) != (LKC_EXCL|1)) {
290 panic("lockmgr: not holding exclusive lock");
291 }
292
293 #ifdef DEBUG_LOCKS
294 for (i = 0; i < LOCKMGR_DEBUG_ARRAY_SIZE; i++) {
295 if (td->td_lockmgr_stack[i] == lkp &&
296 td->td_lockmgr_stack_id[i] > 0
297 ) {
298 td->td_lockmgr_stack_id[i]--;
299 break;
300 }
301 }
302 #endif
303 /*
304 * NOTE! Must NULL-out lockholder before releasing LKC_EXCL.
305 */
306 otd = lkp->lk_lockholder;
307 lkp->lk_lockholder = NULL;
308 if (atomic_cmpset_int(&lkp->lk_count, count,
309 count & ~(LKC_EXCL|LKC_SHREQ))) {
310 if (count & LKC_SHREQ)
311 wakeup(lkp);
312 break;
313 }
314 lkp->lk_lockholder = otd;
315 goto again;
316
317 case LK_EXCLUPGRADE:
318 /*
319 * Upgrade from a single shared lock to an exclusive lock.
320 *
321 * If another process is ahead of us to get an upgrade,
322 * then we want to fail rather than have an intervening
323 * exclusive access. The shared lock is released on
324 * failure.
325 */
326 if (count & LKC_UPREQ) {
327 flags = LK_RELEASE;
328 error = EBUSY;
329 goto again;
330 }
331 /* fall through into normal upgrade */
332
333 case LK_UPGRADE:
334 /*
335 * Upgrade a shared lock to an exclusive one. This can cause
336 * the lock to be temporarily released and stolen by other
337 * threads. LK_SLEEPFAIL or LK_NOWAIT may be used to detect
338 * this case, or use LK_EXCLUPGRADE.
339 *
340 * If the lock is already exclusively owned by us, this
341 * operation is a NOP.
342 *
343 * If we return an error (even NOWAIT), the current lock will
344 * be released.
345 *
346 * Start with the critical path.
347 */
348 if ((count & (LKC_UPREQ|LKC_EXCL|LKC_MASK)) == 1) {
349 if (atomic_cmpset_int(&lkp->lk_count, count,
350 count | LKC_EXCL)) {
351 lkp->lk_lockholder = td;
352 break;
353 }
354 goto again;
355 }
356
357 /*
358 * If we already hold the lock exclusively this operation
359 * succeeds and is a NOP.
360 */
361 if (count & LKC_EXCL) {
362 if (lkp->lk_lockholder == td)
363 break;
364 panic("lockmgr: upgrade unowned lock");
365 }
366 if ((count & LKC_MASK) == 0)
367 panic("lockmgr: upgrade unowned lock");
368
369 /*
370 * We cannot upgrade without blocking at this point.
371 */
372 if (extflags & LK_NOWAIT) {
373 flags = LK_RELEASE;
374 error = EBUSY;
375 goto again;
376 }
377
378 /*
379 * Release the shared lock and request the upgrade.
380 */
381 pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
382 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
383 tsleep_interlock(lkp, pflags);
384 wflags = (count & LKC_UPREQ) ? LKC_EXREQ : LKC_UPREQ;
385
386 /*
387 * If someone else owns UPREQ and this transition would
388 * allow it to be granted, we have to grant it. Otherwise
389 * we release the shared lock.
390 */
391 if ((count & (LKC_UPREQ|LKC_MASK)) == (LKC_UPREQ | 1)) {
392 wflags |= LKC_EXCL | LKC_UPGRANT;
393 wflags |= count;
394 wflags &= ~LKC_UPREQ;
395 } else {
396 wflags |= (count - 1);
397 }
398
399 if (atomic_cmpset_int(&lkp->lk_count, count, wflags)) {
400 COUNT(td, -1);
401
402 /*
403 * Must wakeup the thread granted the upgrade.
404 */
405 if ((count & (LKC_UPREQ|LKC_MASK)) == (LKC_UPREQ | 1))
406 wakeup(lkp);
407
408 mycpu->gd_cnt.v_lock_name[0] = 'U';
409 strncpy(mycpu->gd_cnt.v_lock_name + 1,
410 lkp->lk_wmesg,
411 sizeof(mycpu->gd_cnt.v_lock_name) - 2);
412 ++mycpu->gd_cnt.v_lock_colls;
413
414 error = tsleep(lkp, pflags | PINTERLOCKED,
415 lkp->lk_wmesg, timo);
416 if (error)
417 break;
418 if (extflags & LK_SLEEPFAIL) {
419 error = ENOLCK;
420 break;
421 }
422
423 /*
424 * Refactor to either LK_EXCLUSIVE or LK_WAITUPGRADE,
425 * depending on whether we were able to acquire the
426 * LKC_UPREQ bit.
427 */
428 if (count & LKC_UPREQ)
429 flags = LK_EXCLUSIVE; /* someone else */
430 else
431 flags = LK_WAITUPGRADE; /* we own the bit */
432 }
433 goto again;
434
435 case LK_WAITUPGRADE:
436 /*
437 * We own the LKC_UPREQ bit, wait until we are granted the
438 * exclusive lock (LKC_UPGRANT is set).
439 *
440 * IF THE OPERATION FAILS (tsleep error tsleep+LK_SLEEPFAIL),
441 * we have to undo the upgrade request and clean up any lock
442 * that might have been granted via a race.
443 */
444 if (count & LKC_UPGRANT) {
445 if (atomic_cmpset_int(&lkp->lk_count, count,
446 count & ~LKC_UPGRANT)) {
447 lkp->lk_lockholder = td;
448 KKASSERT(count & LKC_EXCL);
449 break;
450 }
451 /* retry */
452 } else {
453 pflags = (extflags & LK_PCATCH) ? PCATCH : 0;
454 timo = (extflags & LK_TIMELOCK) ? lkp->lk_timo : 0;
455 tsleep_interlock(lkp, pflags);
456 if (atomic_cmpset_int(&lkp->lk_count, count, count)) {
457
458 mycpu->gd_cnt.v_lock_name[0] = 'U';
459 strncpy(mycpu->gd_cnt.v_lock_name + 1,
460 lkp->lk_wmesg,
461 sizeof(mycpu->gd_cnt.v_lock_name) - 2);
462 ++mycpu->gd_cnt.v_lock_colls;
463
464 error = tsleep(lkp, pflags | PINTERLOCKED,
465 lkp->lk_wmesg, timo);
466 if (error) {
467 undo_upreq(lkp);
468 break;
469 }
470 if (extflags & LK_SLEEPFAIL) {
471 error = ENOLCK;
472 undo_upreq(lkp);
473 break;
474 }
475 }
476 /* retry */
477 }
478 goto again;
479
480 case LK_RELEASE:
481 /*
482 * Release the currently held lock. If releasing the current
483 * lock as part of an error return, error will ALREADY be
484 * non-zero.
485 *
486 * When releasing the last lock we automatically transition
487 * LKC_UPREQ to LKC_EXCL|1.
488 *
489 * WARNING! We cannot detect when there are multiple exclusive
490 * requests pending. We clear EXREQ unconditionally
491 * on the 1->0 transition so it is possible for
492 * shared requests to race the next exclusive
493 * request.
494 *
495 * Always succeeds.
496 */
497 if ((count & LKC_MASK) == 0)
498 panic("lockmgr: LK_RELEASE: no lock held");
499
500 if (count & LKC_EXCL) {
501 if (lkp->lk_lockholder != LK_KERNTHREAD &&
502 lkp->lk_lockholder != td) {
503 panic("lockmgr: pid %d, not exlusive "
504 "lock holder thr %p/%p unlocking",
505 (td->td_proc ? td->td_proc->p_pid : -1),
506 td, lkp->lk_lockholder);
507 }
508 if ((count & (LKC_UPREQ|LKC_MASK)) == 1) {
509 /*
510 * Last exclusive count is being released
511 */
512 otd = lkp->lk_lockholder;
513 lkp->lk_lockholder = NULL;
514 if (!atomic_cmpset_int(&lkp->lk_count, count,
515 (count - 1) &
516 ~(LKC_EXCL|LKC_EXREQ|LKC_SHREQ))) {
517 lkp->lk_lockholder = otd;
518 goto again;
519 }
520 if (count & (LKC_EXREQ|LKC_SHREQ))
521 wakeup(lkp);
522 /* success */
523 } else if ((count & (LKC_UPREQ|LKC_MASK)) ==
524 (LKC_UPREQ | 1)) {
525 /*
526 * Last exclusive count is being released but
527 * an upgrade request is present, automatically
528 * grant an exclusive state to the owner of
529 * the upgrade request.
530 */
531 otd = lkp->lk_lockholder;
532 lkp->lk_lockholder = NULL;
533 if (!atomic_cmpset_int(&lkp->lk_count, count,
534 (count & ~LKC_UPREQ) |
535 LKC_UPGRANT)) {
536 lkp->lk_lockholder = otd;
537 }
538 wakeup(lkp);
539 /* success */
540 } else {
541 otd = lkp->lk_lockholder;
542 if (!atomic_cmpset_int(&lkp->lk_count, count,
543 count - 1)) {
544 goto again;
545 }
546 /* success */
547 }
548 /* success */
549 if (otd != LK_KERNTHREAD)
550 COUNT(td, -1);
551 } else {
552 if ((count & (LKC_UPREQ|LKC_MASK)) == 1) {
553 /*
554 * Last shared count is being released.
555 */
556 if (!atomic_cmpset_int(&lkp->lk_count, count,
557 (count - 1) &
558 ~(LKC_EXREQ|LKC_SHREQ))) {
559 goto again;
560 }
561 if (count & (LKC_EXREQ|LKC_SHREQ))
562 wakeup(lkp);
563 /* success */
564 } else if ((count & (LKC_UPREQ|LKC_MASK)) ==
565 (LKC_UPREQ | 1)) {
566 /*
567 * Last shared count is being released but
568 * an upgrade request is present, automatically
569 * grant an exclusive state to the owner of
570 * the upgrade request.
571 */
572 if (!atomic_cmpset_int(&lkp->lk_count, count,
573 (count & ~LKC_UPREQ) |
574 LKC_EXCL | LKC_UPGRANT)) {
575 goto again;
576 }
577 wakeup(lkp);
578 } else {
579 if (!atomic_cmpset_int(&lkp->lk_count, count,
580 count - 1)) {
581 goto again;
582 }
583 }
584 /* success */
585 COUNT(td, -1);
586 }
587 break;
588
589 default:
590 panic("lockmgr: unknown locktype request %d",
591 flags & LK_TYPE_MASK);
592 /* NOTREACHED */
593 }
594 return (error);
595 }
596
597 /*
598 * Undo an upgrade request
599 */
600 static
601 void
602 undo_upreq(struct lock *lkp)
603 {
604 int count;
605
606 for (;;) {
607 count = lkp->lk_count;
608 cpu_ccfence();
609 if (count & LKC_UPGRANT) {
610 /*
611 * UPREQ was shifted to UPGRANT. We own UPGRANT now,
612 * another thread might own UPREQ. Clear UPGRANT
613 * and release the granted lock.
614 */
615 if (atomic_cmpset_int(&lkp->lk_count, count,
616 count & ~LKC_UPGRANT)) {
617 lockmgr(lkp, LK_RELEASE);
618 break;
619 }
620 } else if (count & LKC_EXCL) {
621 /*
622 * Clear the UPREQ we still own. Nobody to wakeup
623 * here because there is an existing exclusive
624 * holder.
625 */
626 KKASSERT(count & LKC_UPREQ);
627 KKASSERT((count & LKC_MASK) > 0);
628 if (atomic_cmpset_int(&lkp->lk_count, count,
629 count & ~LKC_UPREQ)) {
630 wakeup(lkp);
631 break;
632 }
633 } else if (count & LKC_EXREQ) {
634 /*
635 * Clear the UPREQ we still own. We cannot wakeup any
636 * shared waiters because there is an exclusive
637 * request pending.
638 */
639 KKASSERT(count & LKC_UPREQ);
640 KKASSERT((count & LKC_MASK) > 0);
641 if (atomic_cmpset_int(&lkp->lk_count, count,
642 count & ~LKC_UPREQ)) {
643 break;
644 }
645 } else {
646 /*
647 * Clear the UPREQ we still own. Wakeup any shared
648 * waiters.
649 */
650 KKASSERT(count & LKC_UPREQ);
651 KKASSERT((count & LKC_MASK) > 0);
652 if (atomic_cmpset_int(&lkp->lk_count, count,
653 count &
654 ~(LKC_UPREQ | LKC_SHREQ))) {
655 if (count & LKC_SHREQ)
656 wakeup(lkp);
657 break;
658 }
659 }
660 /* retry */
661 }
662 }
663
664 void
665 lockmgr_kernproc(struct lock *lp)
666 {
667 struct thread *td __debugvar = curthread;
668
669 if (lp->lk_lockholder != LK_KERNTHREAD) {
670 KASSERT(lp->lk_lockholder == td,
671 ("lockmgr_kernproc: lock not owned by curthread %p", td));
672 lp->lk_lockholder = LK_KERNTHREAD;
673 COUNT(td, -1);
674 }
675 }
676
677 /*
678 * Initialize a lock; required before use.
679 */
680 void
681 lockinit(struct lock *lkp, const char *wmesg, int timo, int flags)
682 {
683 lkp->lk_flags = (flags & LK_EXTFLG_MASK);
684 lkp->lk_count = 0;
685 lkp->lk_wmesg = wmesg;
686 lkp->lk_timo = timo;
687 lkp->lk_lockholder = LK_NOTHREAD;
688 }
689
690 /*
691 * Reinitialize a lock that is being reused for a different purpose, but
692 * which may have pending (blocked) threads sitting on it. The caller
693 * must already hold the interlock.
694 */
695 void
696 lockreinit(struct lock *lkp, const char *wmesg, int timo, int flags)
697 {
698 lkp->lk_wmesg = wmesg;
699 lkp->lk_timo = timo;
700 }
701
702 /*
703 * De-initialize a lock. The structure must no longer be used by anyone.
704 */
705 void
706 lockuninit(struct lock *lkp)
707 {
708 KKASSERT((lkp->lk_count & (LKC_EXREQ|LKC_SHREQ|LKC_UPREQ)) == 0);
709 }
710
711 /*
712 * Determine the status of a lock.
713 */
714 int
715 lockstatus(struct lock *lkp, struct thread *td)
716 {
717 int lock_type = 0;
718 int count;
719
720 count = lkp->lk_count;
721 cpu_ccfence();
722
723 if (count & LKC_EXCL) {
724 if (td == NULL || lkp->lk_lockholder == td)
725 lock_type = LK_EXCLUSIVE;
726 else
727 lock_type = LK_EXCLOTHER;
728 } else if (count & LKC_MASK) {
729 lock_type = LK_SHARED;
730 }
731 return (lock_type);
732 }
733
734 /*
735 * Return non-zero if the caller owns the lock shared or exclusive.
736 * We can only guess re: shared locks.
737 */
738 int
739 lockowned(struct lock *lkp)
740 {
741 thread_t td = curthread;
742 int count;
743
744 count = lkp->lk_count;
745 cpu_ccfence();
746
747 if (count & LKC_EXCL)
748 return(lkp->lk_lockholder == td);
749 else
750 return((count & LKC_MASK) != 0);
751 }
752
753 /*
754 * Determine the number of holders of a lock.
755 *
756 * The non-blocking version can usually be used for assertions.
757 */
758 int
759 lockcount(struct lock *lkp)
760 {
761 return(lkp->lk_count & LKC_MASK);
762 }
763
764 int
765 lockcountnb(struct lock *lkp)
766 {
767 return(lkp->lk_count & LKC_MASK);
768 }
769
770 /*
771 * Print out information about state of a lock. Used by VOP_PRINT
772 * routines to display status about contained locks.
773 */
774 void
775 lockmgr_printinfo(struct lock *lkp)
776 {
777 struct thread *td = lkp->lk_lockholder;
778 struct proc *p;
779 int count;
780
781 count = lkp->lk_count;
782 cpu_ccfence();
783
784 if (td && td != LK_KERNTHREAD && td != LK_NOTHREAD)
785 p = td->td_proc;
786 else
787 p = NULL;
788
789 if (count & LKC_EXCL) {
790 kprintf(" lock type %s: EXCLUS (count %08x) by td %p pid %d",
791 lkp->lk_wmesg, count, td,
792 p ? p->p_pid : -99);
793 } else if (count & LKC_MASK) {
794 kprintf(" lock type %s: SHARED (count %08x)",
795 lkp->lk_wmesg, count);
796 } else {
797 kprintf(" lock type %s: NOTHELD", lkp->lk_wmesg);
798 }
799 if (count & (LKC_EXREQ|LKC_SHREQ))
800 kprintf(" with waiters\n");
801 else
802 kprintf("\n");
803 }
804
805 void
806 lock_sysinit(struct lock_args *arg)
807 {
808 lockinit(arg->la_lock, arg->la_desc, 0, arg->la_flags);
809 }
Cache object: c37026def061e4324865e9b9b739a1f9
|