xref: /dragonfly/sys/kern/kern_mutex.c (revision 0dace59e)
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * Implement fast persistent locks based on atomic_cmpset_int() with
36  * semantics similar to lockmgr locks but faster and taking up much less
37  * space.  Taken from HAMMER's lock implementation.
38  *
39  * These are meant to complement our LWKT tokens.  Tokens are only held
40  * while the thread is running.  Mutexes can be held across blocking
41  * conditions.
42  *
43  * Most of the support is in sys/mutex[2].h.  We mostly provide backoff
44  * functions here.
45  */
46 
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/sysctl.h>
51 #include <sys/thread.h>
52 
53 #include <machine/cpufunc.h>
54 
55 #include <sys/thread2.h>
56 #include <sys/mutex2.h>
57 
58 static __int64_t mtx_contention_count;
59 static __int64_t mtx_collision_count;
60 static __int64_t mtx_wakeup_count;
61 
62 SYSCTL_QUAD(_kern, OID_AUTO, mtx_contention_count, CTLFLAG_RW,
63 	    &mtx_contention_count, 0, "");
64 SYSCTL_QUAD(_kern, OID_AUTO, mtx_collision_count, CTLFLAG_RW,
65 	    &mtx_collision_count, 0, "");
66 SYSCTL_QUAD(_kern, OID_AUTO, mtx_wakeup_count, CTLFLAG_RW,
67 	    &mtx_wakeup_count, 0, "");
68 
69 static void mtx_chain_link(mtx_t mtx);
70 static void mtx_delete_link(mtx_t mtx, mtx_link_t link);
71 
72 /*
73  * Exclusive-lock a mutex, block until acquired.  Recursion is allowed.
74  *
75  * Returns 0 on success, or the tsleep() return code on failure.
76  * An error can only be returned if PCATCH is specified in the flags.
77  */
78 static __inline int
79 __mtx_lock_ex(mtx_t mtx, mtx_link_t link, const char *ident, int flags, int to)
80 {
81 	u_int	lock;
82 	u_int	nlock;
83 	int	error;
84 
85 	for (;;) {
86 		lock = mtx->mtx_lock;
87 		if (lock == 0) {
88 			nlock = MTX_EXCLUSIVE | 1;
89 			if (atomic_cmpset_int(&mtx->mtx_lock, 0, nlock)) {
90 				mtx->mtx_owner = curthread;
91 				error = 0;
92 				break;
93 			}
94 		} else if ((lock & MTX_EXCLUSIVE) &&
95 			   mtx->mtx_owner == curthread) {
96 			KKASSERT((lock & MTX_MASK) != MTX_MASK);
97 			nlock = lock + 1;
98 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
99 				error = 0;
100 				break;
101 			}
102 		} else {
103 			/*
104 			 * Clearing MTX_EXLINK in lock causes us to loop until
105 			 * MTX_EXLINK is available.  However, to avoid
106 			 * unnecessary cpu cache traffic we poll instead.
107 			 *
108 			 * Setting MTX_EXLINK in nlock causes us to loop until
109 			 * we can acquire MTX_EXLINK.
110 			 *
111 			 * Also set MTX_EXWANTED coincident with EXLINK, if
112 			 * not already set.
113 			 */
114 			thread_t td;
115 
116 			if (lock & MTX_EXLINK) {
117 				cpu_pause();
118 				++mtx_collision_count;
119 				continue;
120 			}
121 			td = curthread;
122 			/*lock &= ~MTX_EXLINK;*/
123 			nlock = lock | MTX_EXWANTED | MTX_EXLINK;
124 			++td->td_critcount;
125 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
126 				/*
127 				 * Check for early abort
128 				 */
129 				if (link->state == MTX_LINK_ABORTED) {
130 					atomic_clear_int(&mtx->mtx_lock,
131 							 MTX_EXLINK);
132 					--td->td_critcount;
133 					error = ENOLCK;
134 					if (mtx->mtx_link == NULL) {
135 						atomic_clear_int(&mtx->mtx_lock,
136 								 MTX_EXWANTED);
137 					}
138 					break;
139 				}
140 
141 				/*
142 				 * Success.  Link in our structure then
143 				 * release EXLINK and sleep.
144 				 */
145 				link->owner = td;
146 				link->state = MTX_LINK_LINKED;
147 				if (mtx->mtx_link) {
148 					link->next = mtx->mtx_link;
149 					link->prev = link->next->prev;
150 					link->next->prev = link;
151 					link->prev->next = link;
152 				} else {
153 					link->next = link;
154 					link->prev = link;
155 					mtx->mtx_link = link;
156 				}
157 				tsleep_interlock(link, 0);
158 				atomic_clear_int(&mtx->mtx_lock, MTX_EXLINK);
159 				--td->td_critcount;
160 
161 				error = tsleep(link, flags | PINTERLOCKED,
162 					       ident, to);
163 				++mtx_contention_count;
164 
165 				/*
166 				 * Normal unlink, we should own the exclusive
167 				 * lock now.
168 				 */
169 				if (link->state == MTX_LINK_LINKED)
170 					mtx_delete_link(mtx, link);
171 				if (link->state == MTX_LINK_ACQUIRED) {
172 					KKASSERT(mtx->mtx_owner == link->owner);
173 					error = 0;
174 					break;
175 				}
176 
177 				/*
178 				 * Aborted lock (mtx_abort_ex called).
179 				 */
180 				if (link->state == MTX_LINK_ABORTED) {
181 					error = ENOLCK;
182 					break;
183 				}
184 
185 				/*
186 				 * tsleep error, else retry.
187 				 */
188 				if (error)
189 					break;
190 			} else {
191 				--td->td_critcount;
192 			}
193 		}
194 		++mtx_collision_count;
195 	}
196 	return (error);
197 }
198 
199 int
200 _mtx_lock_ex_link(mtx_t mtx, mtx_link_t link,
201 		  const char *ident, int flags, int to)
202 {
203 	return(__mtx_lock_ex(mtx, link, ident, flags, to));
204 }
205 
206 int
207 _mtx_lock_ex(mtx_t mtx, const char *ident, int flags, int to)
208 {
209 	struct mtx_link link;
210 
211 	mtx_link_init(&link);
212 	return(__mtx_lock_ex(mtx, &link, ident, flags, to));
213 }
214 
215 int
216 _mtx_lock_ex_quick(mtx_t mtx, const char *ident)
217 {
218 	struct mtx_link link;
219 
220 	mtx_link_init(&link);
221 	return(__mtx_lock_ex(mtx, &link, ident, 0, 0));
222 }
223 
224 /*
225  * Share-lock a mutex, block until acquired.  Recursion is allowed.
226  *
227  * Returns 0 on success, or the tsleep() return code on failure.
228  * An error can only be returned if PCATCH is specified in the flags.
229  *
230  * NOTE: Shared locks get a mass-wakeup so if the tsleep fails we
231  *	 do not have to chain the wakeup().
232  */
233 static __inline int
234 __mtx_lock_sh(mtx_t mtx, const char *ident, int flags, int to)
235 {
236 	u_int	lock;
237 	u_int	nlock;
238 	int	error;
239 
240 	for (;;) {
241 		lock = mtx->mtx_lock;
242 		if ((lock & MTX_EXCLUSIVE) == 0) {
243 			KKASSERT((lock & MTX_MASK) != MTX_MASK);
244 			nlock = lock + 1;
245 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
246 				error = 0;
247 				break;
248 			}
249 		} else {
250 			nlock = lock | MTX_SHWANTED;
251 			tsleep_interlock(mtx, 0);
252 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
253 				error = tsleep(mtx, flags | PINTERLOCKED,
254 					       ident, to);
255 				if (error)
256 					break;
257 				++mtx_contention_count;
258 				/* retry */
259 			} else {
260 				crit_enter();
261 				tsleep_remove(curthread);
262 				crit_exit();
263 			}
264 		}
265 		++mtx_collision_count;
266 	}
267 	return (error);
268 }
269 
270 int
271 _mtx_lock_sh(mtx_t mtx, const char *ident, int flags, int to)
272 {
273 	return (__mtx_lock_sh(mtx, ident, flags, to));
274 }
275 
276 int
277 _mtx_lock_sh_quick(mtx_t mtx, const char *ident)
278 {
279 	return (__mtx_lock_sh(mtx, ident, 0, 0));
280 }
281 
282 /*
283  * Get an exclusive spinlock the hard way.
284  */
285 void
286 _mtx_spinlock(mtx_t mtx)
287 {
288 	u_int	lock;
289 	u_int	nlock;
290 	int	bb = 1;
291 	int	bo;
292 
293 	for (;;) {
294 		lock = mtx->mtx_lock;
295 		if (lock == 0) {
296 			nlock = MTX_EXCLUSIVE | 1;
297 			if (atomic_cmpset_int(&mtx->mtx_lock, 0, nlock)) {
298 				mtx->mtx_owner = curthread;
299 				break;
300 			}
301 		} else if ((lock & MTX_EXCLUSIVE) &&
302 			   mtx->mtx_owner == curthread) {
303 			KKASSERT((lock & MTX_MASK) != MTX_MASK);
304 			nlock = lock + 1;
305 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock))
306 				break;
307 		} else {
308 			/* MWAIT here */
309 			if (bb < 1000)
310 				++bb;
311 			cpu_pause();
312 			for (bo = 0; bo < bb; ++bo)
313 				;
314 			++mtx_contention_count;
315 		}
316 		cpu_pause();
317 		++mtx_collision_count;
318 	}
319 }
320 
321 /*
322  * Attempt to acquire a spinlock, if we fail we must undo the
323  * gd->gd_spinlocks/gd->gd_curthead->td_critcount predisposition.
324  *
325  * Returns 0 on success, EAGAIN on failure.
326  */
327 int
328 _mtx_spinlock_try(mtx_t mtx)
329 {
330 	globaldata_t gd = mycpu;
331 	u_int	lock;
332 	u_int	nlock;
333 	int	res = 0;
334 
335 	for (;;) {
336 		lock = mtx->mtx_lock;
337 		if (lock == 0) {
338 			nlock = MTX_EXCLUSIVE | 1;
339 			if (atomic_cmpset_int(&mtx->mtx_lock, 0, nlock)) {
340 				mtx->mtx_owner = gd->gd_curthread;
341 				break;
342 			}
343 		} else if ((lock & MTX_EXCLUSIVE) &&
344 			   mtx->mtx_owner == gd->gd_curthread) {
345 			KKASSERT((lock & MTX_MASK) != MTX_MASK);
346 			nlock = lock + 1;
347 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock))
348 				break;
349 		} else {
350 			--gd->gd_spinlocks;
351 			cpu_ccfence();
352 			--gd->gd_curthread->td_critcount;
353 			res = EAGAIN;
354 			break;
355 		}
356 		cpu_pause();
357 		++mtx_collision_count;
358 	}
359 	return res;
360 }
361 
362 #if 0
363 
364 void
365 _mtx_spinlock_sh(mtx_t mtx)
366 {
367 	u_int	lock;
368 	u_int	nlock;
369 	int	bb = 1;
370 	int	bo;
371 
372 	for (;;) {
373 		lock = mtx->mtx_lock;
374 		if ((lock & MTX_EXCLUSIVE) == 0) {
375 			KKASSERT((lock & MTX_MASK) != MTX_MASK);
376 			nlock = lock + 1;
377 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock))
378 				break;
379 		} else {
380 			/* MWAIT here */
381 			if (bb < 1000)
382 				++bb;
383 			cpu_pause();
384 			for (bo = 0; bo < bb; ++bo)
385 				;
386 			++mtx_contention_count;
387 		}
388 		cpu_pause();
389 		++mtx_collision_count;
390 	}
391 }
392 
393 #endif
394 
395 int
396 _mtx_lock_ex_try(mtx_t mtx)
397 {
398 	u_int	lock;
399 	u_int	nlock;
400 	int	error = 0;
401 
402 	for (;;) {
403 		lock = mtx->mtx_lock;
404 		if (lock == 0) {
405 			nlock = MTX_EXCLUSIVE | 1;
406 			if (atomic_cmpset_int(&mtx->mtx_lock, 0, nlock)) {
407 				mtx->mtx_owner = curthread;
408 				break;
409 			}
410 		} else if ((lock & MTX_EXCLUSIVE) &&
411 			   mtx->mtx_owner == curthread) {
412 			KKASSERT((lock & MTX_MASK) != MTX_MASK);
413 			nlock = lock + 1;
414 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock))
415 				break;
416 		} else {
417 			error = EAGAIN;
418 			break;
419 		}
420 		cpu_pause();
421 		++mtx_collision_count;
422 	}
423 	return (error);
424 }
425 
426 int
427 _mtx_lock_sh_try(mtx_t mtx)
428 {
429 	u_int	lock;
430 	u_int	nlock;
431 	int	error = 0;
432 
433 	for (;;) {
434 		lock = mtx->mtx_lock;
435 		if ((lock & MTX_EXCLUSIVE) == 0) {
436 			KKASSERT((lock & MTX_MASK) != MTX_MASK);
437 			nlock = lock + 1;
438 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock))
439 				break;
440 		} else {
441 			error = EAGAIN;
442 			break;
443 		}
444 		cpu_pause();
445 		++mtx_collision_count;
446 	}
447 	return (error);
448 }
449 
450 /*
451  * If the lock is held exclusively it must be owned by the caller.  If the
452  * lock is already a shared lock this operation is a NOP.  A panic will
453  * occur if the lock is not held either shared or exclusive.
454  *
455  * The exclusive count is converted to a shared count.
456  */
457 void
458 _mtx_downgrade(mtx_t mtx)
459 {
460 	u_int	lock;
461 	u_int	nlock;
462 
463 	for (;;) {
464 		lock = mtx->mtx_lock;
465 		if ((lock & MTX_EXCLUSIVE) == 0) {
466 			KKASSERT((lock & MTX_MASK) > 0);
467 			break;
468 		}
469 		KKASSERT(mtx->mtx_owner == curthread);
470 		nlock = lock & ~(MTX_EXCLUSIVE | MTX_SHWANTED);
471 		if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
472 			if (lock & MTX_SHWANTED) {
473 				wakeup(mtx);
474 				++mtx_wakeup_count;
475 			}
476 			break;
477 		}
478 		cpu_pause();
479 		++mtx_collision_count;
480 	}
481 }
482 
483 /*
484  * Upgrade a shared lock to an exclusive lock.  The upgrade will fail if
485  * the shared lock has a count other then 1.  Optimize the most likely case
486  * but note that a single cmpset can fail due to WANTED races.
487  *
488  * If the lock is held exclusively it must be owned by the caller and
489  * this function will simply return without doing anything.   A panic will
490  * occur if the lock is held exclusively by someone other then the caller.
491  *
492  * Returns 0 on success, EDEADLK on failure.
493  */
494 int
495 _mtx_upgrade_try(mtx_t mtx)
496 {
497 	u_int	lock;
498 	u_int	nlock;
499 	int	error = 0;
500 
501 	for (;;) {
502 		lock = mtx->mtx_lock;
503 
504 		if ((lock & ~MTX_EXWANTED) == 1) {
505 			nlock = lock | MTX_EXCLUSIVE;
506 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
507 				mtx->mtx_owner = curthread;
508 				break;
509 			}
510 		} else if (lock & MTX_EXCLUSIVE) {
511 			KKASSERT(mtx->mtx_owner == curthread);
512 			break;
513 		} else {
514 			error = EDEADLK;
515 			break;
516 		}
517 		cpu_pause();
518 		++mtx_collision_count;
519 	}
520 	return (error);
521 }
522 
523 /*
524  * Unlock a lock.  The caller must hold the lock either shared or exclusive.
525  *
526  * Any release which makes the lock available when others want an exclusive
527  * lock causes us to chain the owner to the next exclusive lock instead of
528  * releasing the lock.
529  */
530 void
531 _mtx_unlock(mtx_t mtx)
532 {
533 	u_int	lock;
534 	u_int	nlock;
535 
536 	for (;;) {
537 		lock = mtx->mtx_lock;
538 		nlock = lock & ~(MTX_SHWANTED | MTX_EXLINK);
539 
540 		if (nlock == 1) {
541 			/*
542 			 * Last release, shared lock, no exclusive waiters.
543 			 */
544 			nlock = lock & MTX_EXLINK;
545 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock))
546 				break;
547 		} else if (nlock == (MTX_EXCLUSIVE | 1)) {
548 			/*
549 			 * Last release, exclusive lock, no exclusive waiters.
550 			 * Wake up any shared waiters.
551 			 */
552 			mtx->mtx_owner = NULL;
553 			nlock = lock & MTX_EXLINK;
554 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
555 				if (lock & MTX_SHWANTED) {
556 					wakeup(mtx);
557 					++mtx_wakeup_count;
558 				}
559 				break;
560 			}
561 		} else if (nlock == (MTX_EXWANTED | 1)) {
562 			/*
563 			 * Last release, shared lock, with exclusive
564 			 * waiters.
565 			 *
566 			 * Wait for EXLINK to clear, then acquire it.
567 			 * We could use the cmpset for this but polling
568 			 * is better on the cpu caches.
569 			 *
570 			 * Acquire an exclusive lock leaving the lockcount
571 			 * set to 1, and get EXLINK for access to mtx_link.
572 			 */
573 			thread_t td;
574 
575 			if (lock & MTX_EXLINK) {
576 				cpu_pause();
577 				++mtx_collision_count;
578 				continue;
579 			}
580 			td = curthread;
581 			/*lock &= ~MTX_EXLINK;*/
582 			nlock |= MTX_EXLINK | MTX_EXCLUSIVE;
583 			nlock |= (lock & MTX_SHWANTED);
584 			++td->td_critcount;
585 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
586 				mtx_chain_link(mtx);
587 				--td->td_critcount;
588 				break;
589 			}
590 			--td->td_critcount;
591 		} else if (nlock == (MTX_EXCLUSIVE | MTX_EXWANTED | 1)) {
592 			/*
593 			 * Last release, exclusive lock, with exclusive
594 			 * waiters.
595 			 *
596 			 * leave the exclusive lock intact and the lockcount
597 			 * set to 1, and get EXLINK for access to mtx_link.
598 			 */
599 			thread_t td;
600 
601 			if (lock & MTX_EXLINK) {
602 				cpu_pause();
603 				++mtx_collision_count;
604 				continue;
605 			}
606 			td = curthread;
607 			/*lock &= ~MTX_EXLINK;*/
608 			nlock |= MTX_EXLINK;
609 			nlock |= (lock & MTX_SHWANTED);
610 			++td->td_critcount;
611 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
612 				mtx_chain_link(mtx);
613 				--td->td_critcount;
614 				break;
615 			}
616 			--td->td_critcount;
617 		} else {
618 			/*
619 			 * Not the last release (shared or exclusive)
620 			 */
621 			nlock = lock - 1;
622 			KKASSERT((nlock & MTX_MASK) != MTX_MASK);
623 			if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock))
624 				break;
625 		}
626 		cpu_pause();
627 		++mtx_collision_count;
628 	}
629 }
630 
631 /*
632  * Chain mtx_chain_link.  Called with the lock held exclusively with a
633  * single ref count, and also with MTX_EXLINK held.
634  */
635 static void
636 mtx_chain_link(mtx_t mtx)
637 {
638 	mtx_link_t link;
639 	u_int	lock;
640 	u_int	nlock;
641 	u_int	clock;	/* bits we own and want to clear */
642 
643 	/*
644 	 * Chain the exclusive lock to the next link.  The caller cleared
645 	 * SHWANTED so if there is no link we have to wake up any shared
646 	 * waiters.
647 	 */
648 	clock = MTX_EXLINK;
649 	if ((link = mtx->mtx_link) != NULL) {
650 		KKASSERT(link->state == MTX_LINK_LINKED);
651 		if (link->next == link) {
652 			mtx->mtx_link = NULL;
653 			clock |= MTX_EXWANTED;
654 		} else {
655 			mtx->mtx_link = link->next;
656 			link->next->prev = link->prev;
657 			link->prev->next = link->next;
658 		}
659 		link->state = MTX_LINK_ACQUIRED;
660 		mtx->mtx_owner = link->owner;
661 	} else {
662 		/*
663 		 * Chain was empty, release the exclusive lock's last count
664 		 * as well the bits shown.
665 		 */
666 		clock |= MTX_EXCLUSIVE | MTX_EXWANTED | MTX_SHWANTED | 1;
667 	}
668 
669 	/*
670 	 * We have to uset cmpset here to deal with MTX_SHWANTED.  If
671 	 * we just clear the bits we can miss a wakeup or, worse,
672 	 * leave mtx_lock unlocked with MTX_SHWANTED still set.
673 	 */
674 	for (;;) {
675 		lock = mtx->mtx_lock;
676 		nlock = lock & ~clock;
677 
678 		if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock)) {
679 			if (link) {
680 				/*
681 				 * Wakeup new exclusive holder.  Leave
682 				 * SHWANTED intact.
683 				 */
684 				wakeup(link);
685 			} else if (lock & MTX_SHWANTED) {
686 				/*
687 				 * Signal any shared waiters (and we also
688 				 * clear SHWANTED).
689 				 */
690 				mtx->mtx_owner = NULL;
691 				wakeup(mtx);
692 				++mtx_wakeup_count;
693 			}
694 			break;
695 		}
696 		cpu_pause();
697 		++mtx_collision_count;
698 	}
699 }
700 
701 /*
702  * Delete a link structure after tsleep has failed.  This code is not
703  * in the critical path as most exclusive waits are chained.
704  */
705 static
706 void
707 mtx_delete_link(mtx_t mtx, mtx_link_t link)
708 {
709 	thread_t td = curthread;
710 	u_int	lock;
711 	u_int	nlock;
712 
713 	/*
714 	 * Acquire MTX_EXLINK.
715 	 *
716 	 * Do not use cmpxchg to wait for EXLINK to clear as this might
717 	 * result in too much cpu cache traffic.
718 	 */
719 	++td->td_critcount;
720 	for (;;) {
721 		lock = mtx->mtx_lock;
722 		if (lock & MTX_EXLINK) {
723 			cpu_pause();
724 			++mtx_collision_count;
725 			continue;
726 		}
727 		/* lock &= ~MTX_EXLINK; */
728 		nlock = lock | MTX_EXLINK;
729 		if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock))
730 			break;
731 		cpu_pause();
732 		++mtx_collision_count;
733 	}
734 
735 	/*
736 	 * Delete the link and release EXLINK.
737 	 */
738 	if (link->state == MTX_LINK_LINKED) {
739 		if (link->next == link) {
740 			mtx->mtx_link = NULL;
741 		} else {
742 			mtx->mtx_link = link->next;
743 			link->next->prev = link->prev;
744 			link->prev->next = link->next;
745 		}
746 		link->state = MTX_LINK_IDLE;
747 	}
748 	atomic_clear_int(&mtx->mtx_lock, MTX_EXLINK);
749 	--td->td_critcount;
750 }
751 
752 /*
753  * Abort a mutex locking operation, causing mtx_lock_ex_link() to
754  * return ENOLCK.  This may be called at any time after the
755  * mtx_link is initialized, including both before and after the call
756  * to mtx_lock_ex_link().
757  */
758 void
759 mtx_abort_ex_link(mtx_t mtx, mtx_link_t link)
760 {
761 	thread_t td = curthread;
762 	u_int	lock;
763 	u_int	nlock;
764 
765 	/*
766 	 * Acquire MTX_EXLINK
767 	 */
768 	++td->td_critcount;
769 	for (;;) {
770 		lock = mtx->mtx_lock;
771 		if (lock & MTX_EXLINK) {
772 			cpu_pause();
773 			++mtx_collision_count;
774 			continue;
775 		}
776 		/* lock &= ~MTX_EXLINK; */
777 		nlock = lock | MTX_EXLINK;
778 		if (atomic_cmpset_int(&mtx->mtx_lock, lock, nlock))
779 			break;
780 		cpu_pause();
781 		++mtx_collision_count;
782 	}
783 
784 	/*
785 	 * Do the abort
786 	 */
787 	switch(link->state) {
788 	case MTX_LINK_IDLE:
789 		/*
790 		 * Link not started yet
791 		 */
792 		link->state = MTX_LINK_ABORTED;
793 		break;
794 	case MTX_LINK_LINKED:
795 		/*
796 		 * de-link, mark aborted, and wakeup the thread.
797 		 */
798 		if (link->next == link) {
799 			mtx->mtx_link = NULL;
800 		} else {
801 			mtx->mtx_link = link->next;
802 			link->next->prev = link->prev;
803 			link->prev->next = link->next;
804 		}
805 		link->state = MTX_LINK_ABORTED;
806 		wakeup(link);
807 		break;
808 	case MTX_LINK_ACQUIRED:
809 		/*
810 		 * Too late, the lock was acquired.  Let it complete.
811 		 */
812 		break;
813 	default:
814 		/*
815 		 * link already aborted, do nothing.
816 		 */
817 		break;
818 	}
819 	atomic_clear_int(&mtx->mtx_lock, MTX_EXLINK);
820 	--td->td_critcount;
821 }
822