1 /* 2 * Copyright (c) 2003,2004,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 /* 36 * lwkt_token - Implement soft token locks. 37 * 38 * Tokens are locks which serialize a thread only while the thread is 39 * running. If the thread blocks all tokens are released, then reacquired 40 * when the thread resumes. 41 * 42 * This implementation requires no critical sections or spin locks, but 43 * does use atomic_cmpset_ptr(). 44 * 45 * Tokens may be recursively acquired by the same thread. However the 46 * caller must be sure to release such tokens in reverse order. 47 */ 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/kernel.h> 51 #include <sys/proc.h> 52 #include <sys/rtprio.h> 53 #include <sys/queue.h> 54 #include <sys/sysctl.h> 55 #include <sys/ktr.h> 56 #include <sys/kthread.h> 57 #include <machine/cpu.h> 58 #include <sys/lock.h> 59 #include <sys/caps.h> 60 #include <sys/spinlock.h> 61 62 #include <sys/thread2.h> 63 #include <sys/spinlock2.h> 64 #include <sys/mplock2.h> 65 66 #include <vm/vm.h> 67 #include <vm/vm_param.h> 68 #include <vm/vm_kern.h> 69 #include <vm/vm_object.h> 70 #include <vm/vm_page.h> 71 #include <vm/vm_map.h> 72 #include <vm/vm_pager.h> 73 #include <vm/vm_extern.h> 74 #include <vm/vm_zone.h> 75 76 #include <machine/stdarg.h> 77 #include <machine/smp.h> 78 79 extern int lwkt_sched_debug; 80 81 #ifndef LWKT_NUM_POOL_TOKENS 82 #define LWKT_NUM_POOL_TOKENS 4001 /* prime number */ 83 #endif 84 85 static lwkt_token pool_tokens[LWKT_NUM_POOL_TOKENS]; 86 87 #define TOKEN_STRING "REF=%p TOK=%p TD=%p" 88 #define CONTENDED_STRING "REF=%p TOK=%p TD=%p (contention started)" 89 #define UNCONTENDED_STRING "REF=%p TOK=%p TD=%p (contention stopped)" 90 #if !defined(KTR_TOKENS) 91 #define KTR_TOKENS KTR_ALL 92 #endif 93 94 KTR_INFO_MASTER(tokens); 95 KTR_INFO(KTR_TOKENS, tokens, fail, 0, TOKEN_STRING, sizeof(void *) * 3); 96 KTR_INFO(KTR_TOKENS, tokens, succ, 1, TOKEN_STRING, sizeof(void *) * 3); 97 #if 0 98 KTR_INFO(KTR_TOKENS, tokens, release, 2, TOKEN_STRING, sizeof(void *) * 3); 99 KTR_INFO(KTR_TOKENS, tokens, remote, 3, TOKEN_STRING, sizeof(void *) * 3); 100 KTR_INFO(KTR_TOKENS, tokens, reqremote, 4, TOKEN_STRING, sizeof(void *) * 3); 101 KTR_INFO(KTR_TOKENS, tokens, reqfail, 5, TOKEN_STRING, sizeof(void *) * 3); 102 KTR_INFO(KTR_TOKENS, tokens, drain, 6, TOKEN_STRING, sizeof(void *) * 3); 103 KTR_INFO(KTR_TOKENS, tokens, contention_start, 7, CONTENDED_STRING, sizeof(void *) * 3); 104 KTR_INFO(KTR_TOKENS, tokens, contention_stop, 7, UNCONTENDED_STRING, sizeof(void *) * 3); 105 #endif 106 107 #define logtoken(name, ref) \ 108 KTR_LOG(tokens_ ## name, ref, ref->tr_tok, curthread) 109 110 /* 111 * Global tokens. These replace the MP lock for major subsystem locking. 112 * These tokens are initially used to lockup both global and individual 113 * operations. 114 * 115 * Once individual structures get their own locks these tokens are used 116 * only to protect global lists & other variables and to interlock 117 * allocations and teardowns and such. 118 * 119 * The UP initializer causes token acquisition to also acquire the MP lock 120 * for maximum compatibility. The feature may be enabled and disabled at 121 * any time, the MP state is copied to the tokref when the token is acquired 122 * and will not race against sysctl changes. 123 */ 124 struct lwkt_token mp_token = LWKT_TOKEN_INITIALIZER(mp_token); 125 struct lwkt_token pmap_token = LWKT_TOKEN_INITIALIZER(pmap_token); 126 struct lwkt_token dev_token = LWKT_TOKEN_INITIALIZER(dev_token); 127 struct lwkt_token vm_token = LWKT_TOKEN_INITIALIZER(vm_token); 128 struct lwkt_token vmspace_token = LWKT_TOKEN_INITIALIZER(vmspace_token); 129 struct lwkt_token kvm_token = LWKT_TOKEN_INITIALIZER(kvm_token); 130 struct lwkt_token proc_token = LWKT_TOKEN_INITIALIZER(proc_token); 131 struct lwkt_token tty_token = LWKT_TOKEN_INITIALIZER(tty_token); 132 struct lwkt_token vnode_token = LWKT_TOKEN_INITIALIZER(vnode_token); 133 struct lwkt_token vmobj_token = LWKT_TOKEN_INITIALIZER(vmobj_token); 134 135 static int lwkt_token_spin = 5; 136 SYSCTL_INT(_lwkt, OID_AUTO, token_spin, CTLFLAG_RW, 137 &lwkt_token_spin, 0, "Decontention spin loops"); 138 static int lwkt_token_delay = 0; 139 SYSCTL_INT(_lwkt, OID_AUTO, token_delay, CTLFLAG_RW, 140 &lwkt_token_delay, 0, "Decontention spin delay in ns"); 141 142 /* 143 * The collision count is bumped every time the LWKT scheduler fails 144 * to acquire needed tokens in addition to a normal lwkt_gettoken() 145 * stall. 146 */ 147 SYSCTL_LONG(_lwkt, OID_AUTO, mp_collisions, CTLFLAG_RW, 148 &mp_token.t_collisions, 0, "Collision counter of mp_token"); 149 SYSCTL_LONG(_lwkt, OID_AUTO, pmap_collisions, CTLFLAG_RW, 150 &pmap_token.t_collisions, 0, "Collision counter of pmap_token"); 151 SYSCTL_LONG(_lwkt, OID_AUTO, dev_collisions, CTLFLAG_RW, 152 &dev_token.t_collisions, 0, "Collision counter of dev_token"); 153 SYSCTL_LONG(_lwkt, OID_AUTO, vm_collisions, CTLFLAG_RW, 154 &vm_token.t_collisions, 0, "Collision counter of vm_token"); 155 SYSCTL_LONG(_lwkt, OID_AUTO, vmspace_collisions, CTLFLAG_RW, 156 &vmspace_token.t_collisions, 0, "Collision counter of vmspace_token"); 157 SYSCTL_LONG(_lwkt, OID_AUTO, kvm_collisions, CTLFLAG_RW, 158 &kvm_token.t_collisions, 0, "Collision counter of kvm_token"); 159 SYSCTL_LONG(_lwkt, OID_AUTO, proc_collisions, CTLFLAG_RW, 160 &proc_token.t_collisions, 0, "Collision counter of proc_token"); 161 SYSCTL_LONG(_lwkt, OID_AUTO, tty_collisions, CTLFLAG_RW, 162 &tty_token.t_collisions, 0, "Collision counter of tty_token"); 163 SYSCTL_LONG(_lwkt, OID_AUTO, vnode_collisions, CTLFLAG_RW, 164 &vnode_token.t_collisions, 0, "Collision counter of vnode_token"); 165 166 static int _lwkt_getalltokens_sorted(thread_t td); 167 168 #ifdef SMP 169 /* 170 * Acquire the initial mplock 171 * 172 * (low level boot only) 173 */ 174 void 175 cpu_get_initial_mplock(void) 176 { 177 KKASSERT(mp_token.t_ref == NULL); 178 if (lwkt_trytoken(&mp_token) == FALSE) 179 panic("cpu_get_initial_mplock"); 180 } 181 #endif 182 183 /* 184 * Return a pool token given an address. Use a prime number to reduce 185 * overlaps. 186 */ 187 static __inline 188 lwkt_token_t 189 _lwkt_token_pool_lookup(void *ptr) 190 { 191 u_int i; 192 193 i = (u_int)(uintptr_t)ptr % LWKT_NUM_POOL_TOKENS; 194 return(&pool_tokens[i]); 195 } 196 197 /* 198 * Initialize a tokref_t prior to making it visible in the thread's 199 * token array. 200 */ 201 static __inline 202 void 203 _lwkt_tokref_init(lwkt_tokref_t ref, lwkt_token_t tok, thread_t td, long excl) 204 { 205 ref->tr_tok = tok; 206 ref->tr_count = excl; 207 ref->tr_owner = td; 208 } 209 210 /* 211 * Attempt to acquire a shared or exclusive token. Returns TRUE on success, 212 * FALSE on failure. 213 * 214 * If TOK_EXCLUSIVE is set in mode we are attempting to get an exclusive 215 * token, otherwise are attempting to get a shared token. 216 * 217 * If TOK_EXCLREQ is set in mode this is a blocking operation, otherwise 218 * it is a non-blocking operation (for both exclusive or shared acquisions). 219 */ 220 static __inline 221 int 222 _lwkt_trytokref(lwkt_tokref_t ref, thread_t td, long mode) 223 { 224 lwkt_token_t tok; 225 lwkt_tokref_t oref; 226 long count; 227 228 tok = ref->tr_tok; 229 KASSERT(((mode & TOK_EXCLREQ) == 0 || /* non blocking */ 230 td->td_gd->gd_intr_nesting_level == 0 || 231 panic_cpu_gd == mycpu), 232 ("Attempt to acquire token %p not already " 233 "held in hard code section", tok)); 234 235 if (mode & TOK_EXCLUSIVE) { 236 /* 237 * Attempt to get an exclusive token 238 */ 239 for (;;) { 240 count = tok->t_count; 241 oref = tok->t_ref; /* can be NULL */ 242 cpu_ccfence(); 243 if ((count & ~TOK_EXCLREQ) == 0) { 244 /* 245 * It is possible to get the exclusive bit. 246 * We must clear TOK_EXCLREQ on successful 247 * acquisition. 248 */ 249 if (atomic_cmpset_long(&tok->t_count, count, 250 (count & ~TOK_EXCLREQ) | 251 TOK_EXCLUSIVE)) { 252 KKASSERT(tok->t_ref == NULL); 253 tok->t_ref = ref; 254 return TRUE; 255 } 256 /* retry */ 257 } else if ((count & TOK_EXCLUSIVE) && 258 oref >= &td->td_toks_base && 259 oref < td->td_toks_stop) { 260 /* 261 * Our thread already holds the exclusive 262 * bit, we treat this tokref as a shared 263 * token (sorta) to make the token release 264 * code easier. 265 * 266 * NOTE: oref cannot race above if it 267 * happens to be ours, so we're good. 268 * But we must still have a stable 269 * variable for both parts of the 270 * comparison. 271 * 272 * NOTE: Since we already have an exclusive 273 * lock and don't need to check EXCLREQ 274 * we can just use an atomic_add here 275 */ 276 atomic_add_long(&tok->t_count, TOK_INCR); 277 ref->tr_count &= ~TOK_EXCLUSIVE; 278 return TRUE; 279 } else if ((mode & TOK_EXCLREQ) && 280 (count & TOK_EXCLREQ) == 0) { 281 /* 282 * Unable to get the exclusive bit but being 283 * asked to set the exclusive-request bit. 284 * Since we are going to retry anyway just 285 * set the bit unconditionally. 286 */ 287 atomic_set_long(&tok->t_count, TOK_EXCLREQ); 288 return FALSE; 289 } else { 290 /* 291 * Unable to get the exclusive bit and not 292 * being asked to set the exclusive-request 293 * (aka lwkt_trytoken()), or EXCLREQ was 294 * already set. 295 */ 296 cpu_pause(); 297 return FALSE; 298 } 299 /* retry */ 300 } 301 } else { 302 /* 303 * Attempt to get a shared token. Note that TOK_EXCLREQ 304 * for shared tokens simply means the caller intends to 305 * block. We never actually set the bit in tok->t_count. 306 */ 307 for (;;) { 308 count = tok->t_count; 309 oref = tok->t_ref; /* can be NULL */ 310 cpu_ccfence(); 311 if ((count & (TOK_EXCLUSIVE/*|TOK_EXCLREQ*/)) == 0) { 312 /* XXX EXCLREQ should work */ 313 /* 314 * It is possible to get the token shared. 315 */ 316 if (atomic_cmpset_long(&tok->t_count, count, 317 count + TOK_INCR)) { 318 return TRUE; 319 } 320 /* retry */ 321 } else if ((count & TOK_EXCLUSIVE) && 322 oref >= &td->td_toks_base && 323 oref < td->td_toks_stop) { 324 /* 325 * We own the exclusive bit on the token so 326 * we can in fact also get it shared. 327 */ 328 atomic_add_long(&tok->t_count, TOK_INCR); 329 return TRUE; 330 } else { 331 /* 332 * We failed to get the token shared 333 */ 334 return FALSE; 335 } 336 /* retry */ 337 } 338 } 339 } 340 341 static __inline 342 int 343 _lwkt_trytokref_spin(lwkt_tokref_t ref, thread_t td, long mode) 344 { 345 int spin; 346 347 if (_lwkt_trytokref(ref, td, mode)) 348 return TRUE; 349 for (spin = lwkt_token_spin; spin > 0; --spin) { 350 if (lwkt_token_delay) 351 tsc_delay(lwkt_token_delay); 352 else 353 cpu_pause(); 354 if (_lwkt_trytokref(ref, td, mode)) 355 return TRUE; 356 } 357 return FALSE; 358 } 359 360 /* 361 * Release a token that we hold. 362 */ 363 static __inline 364 void 365 _lwkt_reltokref(lwkt_tokref_t ref, thread_t td) 366 { 367 lwkt_token_t tok; 368 long count; 369 370 tok = ref->tr_tok; 371 for (;;) { 372 count = tok->t_count; 373 cpu_ccfence(); 374 if (tok->t_ref == ref) { 375 /* 376 * We are an exclusive holder. We must clear tr_ref 377 * before we clear the TOK_EXCLUSIVE bit. If we are 378 * unable to clear the bit we must restore 379 * tok->t_ref. 380 */ 381 KKASSERT(count & TOK_EXCLUSIVE); 382 tok->t_ref = NULL; 383 if (atomic_cmpset_long(&tok->t_count, count, 384 count & ~TOK_EXCLUSIVE)) { 385 return; 386 } 387 tok->t_ref = ref; 388 /* retry */ 389 } else { 390 /* 391 * We are a shared holder 392 */ 393 KKASSERT(count & TOK_COUNTMASK); 394 if (atomic_cmpset_long(&tok->t_count, count, 395 count - TOK_INCR)) { 396 return; 397 } 398 /* retry */ 399 } 400 /* retry */ 401 } 402 } 403 404 /* 405 * Obtain all the tokens required by the specified thread on the current 406 * cpu, return 0 on failure and non-zero on success. If a failure occurs 407 * any partially acquired tokens will be released prior to return. 408 * 409 * lwkt_getalltokens is called by the LWKT scheduler to re-acquire all 410 * tokens that the thread had to release when it switched away. 411 * 412 * If spinning is non-zero this function acquires the tokens in a particular 413 * order to deal with potential deadlocks. We simply use address order for 414 * the case. 415 * 416 * Called from a critical section. 417 */ 418 int 419 lwkt_getalltokens(thread_t td, int spinning) 420 { 421 lwkt_tokref_t scan; 422 lwkt_token_t tok; 423 424 if (spinning) 425 return(_lwkt_getalltokens_sorted(td)); 426 427 /* 428 * Acquire tokens in forward order, assign or validate tok->t_ref. 429 */ 430 for (scan = &td->td_toks_base; scan < td->td_toks_stop; ++scan) { 431 tok = scan->tr_tok; 432 for (;;) { 433 /* 434 * Only try really hard on the last token 435 */ 436 if (scan == td->td_toks_stop - 1) { 437 if (_lwkt_trytokref_spin(scan, td, scan->tr_count)) 438 break; 439 } else { 440 if (_lwkt_trytokref(scan, td, scan->tr_count)) 441 break; 442 } 443 444 /* 445 * Otherwise we failed to acquire all the tokens. 446 * Release whatever we did get. 447 */ 448 if (lwkt_sched_debug > 0) { 449 --lwkt_sched_debug; 450 kprintf("toka %p %s %s\n", 451 tok, tok->t_desc, td->td_comm); 452 } 453 td->td_wmesg = tok->t_desc; 454 ++tok->t_collisions; 455 while (--scan >= &td->td_toks_base) 456 _lwkt_reltokref(scan, td); 457 return(FALSE); 458 } 459 } 460 return (TRUE); 461 } 462 463 /* 464 * Release all tokens owned by the specified thread on the current cpu. 465 * 466 * This code is really simple. Even in cases where we own all the tokens 467 * note that t_ref may not match the scan for recursively held tokens which 468 * are held deeper in the stack, or for the case where a lwkt_getalltokens() 469 * failed. 470 * 471 * Tokens are released in reverse order to reduce chasing race failures. 472 * 473 * Called from a critical section. 474 */ 475 void 476 lwkt_relalltokens(thread_t td) 477 { 478 lwkt_tokref_t scan; 479 480 /* 481 * Weird order is to try to avoid a panic loop 482 */ 483 if (td->td_toks_have) { 484 scan = td->td_toks_have; 485 td->td_toks_have = NULL; 486 } else { 487 scan = td->td_toks_stop; 488 } 489 while (--scan >= &td->td_toks_base) 490 _lwkt_reltokref(scan, td); 491 } 492 493 /* 494 * This is the decontention version of lwkt_getalltokens(). The tokens are 495 * acquired in address-sorted order to deal with any deadlocks. Ultimately 496 * token failures will spin into the scheduler and get here. 497 * 498 * Called from critical section 499 */ 500 static 501 int 502 _lwkt_getalltokens_sorted(thread_t td) 503 { 504 lwkt_tokref_t sort_array[LWKT_MAXTOKENS]; 505 lwkt_tokref_t scan; 506 lwkt_token_t tok; 507 int i; 508 int j; 509 int n; 510 511 /* 512 * Sort the token array. Yah yah, I know this isn't fun. 513 * 514 * NOTE: Recursively acquired tokens are ordered the same as in the 515 * td_toks_array so we can always get the earliest one first. 516 */ 517 i = 0; 518 scan = &td->td_toks_base; 519 while (scan < td->td_toks_stop) { 520 for (j = 0; j < i; ++j) { 521 if (scan->tr_tok < sort_array[j]->tr_tok) 522 break; 523 } 524 if (j != i) { 525 bcopy(sort_array + j, sort_array + j + 1, 526 (i - j) * sizeof(lwkt_tokref_t)); 527 } 528 sort_array[j] = scan; 529 ++scan; 530 ++i; 531 } 532 n = i; 533 534 /* 535 * Acquire tokens in forward order, assign or validate tok->t_ref. 536 */ 537 for (i = 0; i < n; ++i) { 538 scan = sort_array[i]; 539 tok = scan->tr_tok; 540 for (;;) { 541 /* 542 * Only try really hard on the last token 543 */ 544 if (scan == td->td_toks_stop - 1) { 545 if (_lwkt_trytokref_spin(scan, td, scan->tr_count)) 546 break; 547 } else { 548 if (_lwkt_trytokref(scan, td, scan->tr_count)) 549 break; 550 } 551 552 /* 553 * Otherwise we failed to acquire all the tokens. 554 * Release whatever we did get. 555 */ 556 if (lwkt_sched_debug > 0) { 557 --lwkt_sched_debug; 558 kprintf("tokb %p %s %s\n", 559 tok, tok->t_desc, td->td_comm); 560 } 561 td->td_wmesg = tok->t_desc; 562 ++tok->t_collisions; 563 while (--i >= 0) { 564 scan = sort_array[i]; 565 _lwkt_reltokref(scan, td); 566 } 567 return(FALSE); 568 } 569 } 570 571 /* 572 * We were successful, there is no need for another core to signal 573 * us. 574 */ 575 return (TRUE); 576 } 577 578 /* 579 * Get a serializing token. This routine can block. 580 */ 581 void 582 lwkt_gettoken(lwkt_token_t tok) 583 { 584 thread_t td = curthread; 585 lwkt_tokref_t ref; 586 587 ref = td->td_toks_stop; 588 KKASSERT(ref < &td->td_toks_end); 589 ++td->td_toks_stop; 590 cpu_ccfence(); 591 _lwkt_tokref_init(ref, tok, td, TOK_EXCLUSIVE|TOK_EXCLREQ); 592 593 #ifdef DEBUG_LOCKS 594 /* 595 * Taking an exclusive token after holding it shared will 596 * livelock. Scan for that case and assert. 597 */ 598 lwkt_tokref_t tk; 599 int found = 0; 600 for (tk = &td->td_toks_base; tk < ref; tk++) { 601 if (tk->tr_tok != tok) 602 continue; 603 604 found++; 605 if (tk->tr_count & TOK_EXCLUSIVE) 606 goto good; 607 } 608 /* We found only shared instances of this token if found >0 here */ 609 KASSERT((found == 0), ("Token %p s/x livelock", tok)); 610 good: 611 #endif 612 613 if (_lwkt_trytokref_spin(ref, td, TOK_EXCLUSIVE|TOK_EXCLREQ)) 614 return; 615 616 /* 617 * Give up running if we can't acquire the token right now. 618 * 619 * Since the tokref is already active the scheduler now 620 * takes care of acquisition, so we need only call 621 * lwkt_switch(). 622 * 623 * Since we failed this was not a recursive token so upon 624 * return tr_tok->t_ref should be assigned to this specific 625 * ref. 626 */ 627 td->td_wmesg = tok->t_desc; 628 ++tok->t_collisions; 629 logtoken(fail, ref); 630 td->td_toks_have = td->td_toks_stop - 1; 631 lwkt_switch(); 632 logtoken(succ, ref); 633 KKASSERT(tok->t_ref == ref); 634 } 635 636 /* 637 * Similar to gettoken but we acquire a shared token instead of an exclusive 638 * token. 639 */ 640 void 641 lwkt_gettoken_shared(lwkt_token_t tok) 642 { 643 thread_t td = curthread; 644 lwkt_tokref_t ref; 645 646 ref = td->td_toks_stop; 647 KKASSERT(ref < &td->td_toks_end); 648 ++td->td_toks_stop; 649 cpu_ccfence(); 650 _lwkt_tokref_init(ref, tok, td, TOK_EXCLREQ); 651 652 #ifdef DEBUG_LOCKS 653 /* 654 * Taking a pool token in shared mode is a bad idea; other 655 * addresses deeper in the call stack may hash to the same pool 656 * token and you may end up with an exclusive-shared livelock. 657 * Warn in this condition. 658 */ 659 if ((tok >= &pool_tokens[0]) && 660 (tok < &pool_tokens[LWKT_NUM_POOL_TOKENS])) 661 kprintf("Warning! Taking pool token %p in shared mode\n", tok); 662 #endif 663 664 665 if (_lwkt_trytokref_spin(ref, td, TOK_EXCLREQ)) 666 return; 667 668 /* 669 * Give up running if we can't acquire the token right now. 670 * 671 * Since the tokref is already active the scheduler now 672 * takes care of acquisition, so we need only call 673 * lwkt_switch(). 674 * 675 * Since we failed this was not a recursive token so upon 676 * return tr_tok->t_ref should be assigned to this specific 677 * ref. 678 */ 679 td->td_wmesg = tok->t_desc; 680 ++tok->t_collisions; 681 logtoken(fail, ref); 682 td->td_toks_have = td->td_toks_stop - 1; 683 lwkt_switch(); 684 logtoken(succ, ref); 685 } 686 687 /* 688 * Attempt to acquire a token, return TRUE on success, FALSE on failure. 689 * 690 * We setup the tokref in case we actually get the token (if we switch later 691 * it becomes mandatory so we set TOK_EXCLREQ), but we call trytokref without 692 * TOK_EXCLREQ in case we fail. 693 */ 694 int 695 lwkt_trytoken(lwkt_token_t tok) 696 { 697 thread_t td = curthread; 698 lwkt_tokref_t ref; 699 700 ref = td->td_toks_stop; 701 KKASSERT(ref < &td->td_toks_end); 702 ++td->td_toks_stop; 703 cpu_ccfence(); 704 _lwkt_tokref_init(ref, tok, td, TOK_EXCLUSIVE|TOK_EXCLREQ); 705 706 if (_lwkt_trytokref(ref, td, TOK_EXCLUSIVE)) 707 return TRUE; 708 709 /* 710 * Failed, unpend the request 711 */ 712 cpu_ccfence(); 713 --td->td_toks_stop; 714 ++tok->t_collisions; 715 return FALSE; 716 } 717 718 719 void 720 lwkt_gettoken_hard(lwkt_token_t tok) 721 { 722 lwkt_gettoken(tok); 723 crit_enter_hard(); 724 } 725 726 lwkt_token_t 727 lwkt_getpooltoken(void *ptr) 728 { 729 lwkt_token_t tok; 730 731 tok = _lwkt_token_pool_lookup(ptr); 732 lwkt_gettoken(tok); 733 return (tok); 734 } 735 736 /* 737 * Release a serializing token. 738 * 739 * WARNING! All tokens must be released in reverse order. This will be 740 * asserted. 741 */ 742 void 743 lwkt_reltoken(lwkt_token_t tok) 744 { 745 thread_t td = curthread; 746 lwkt_tokref_t ref; 747 748 /* 749 * Remove ref from thread token list and assert that it matches 750 * the token passed in. Tokens must be released in reverse order. 751 */ 752 ref = td->td_toks_stop - 1; 753 KKASSERT(ref >= &td->td_toks_base && ref->tr_tok == tok); 754 _lwkt_reltokref(ref, td); 755 cpu_sfence(); 756 td->td_toks_stop = ref; 757 } 758 759 void 760 lwkt_reltoken_hard(lwkt_token_t tok) 761 { 762 lwkt_reltoken(tok); 763 crit_exit_hard(); 764 } 765 766 /* 767 * It is faster for users of lwkt_getpooltoken() to use the returned 768 * token and just call lwkt_reltoken(), but for convenience we provide 769 * this function which looks the token up based on the ident. 770 */ 771 void 772 lwkt_relpooltoken(void *ptr) 773 { 774 lwkt_token_t tok = _lwkt_token_pool_lookup(ptr); 775 lwkt_reltoken(tok); 776 } 777 778 /* 779 * Return a count of the number of token refs the thread has to the 780 * specified token, whether it currently owns the token or not. 781 */ 782 int 783 lwkt_cnttoken(lwkt_token_t tok, thread_t td) 784 { 785 lwkt_tokref_t scan; 786 int count = 0; 787 788 for (scan = &td->td_toks_base; scan < td->td_toks_stop; ++scan) { 789 if (scan->tr_tok == tok) 790 ++count; 791 } 792 return(count); 793 } 794 795 /* 796 * Pool tokens are used to provide a type-stable serializing token 797 * pointer that does not race against disappearing data structures. 798 * 799 * This routine is called in early boot just after we setup the BSP's 800 * globaldata structure. 801 */ 802 void 803 lwkt_token_pool_init(void) 804 { 805 int i; 806 807 for (i = 0; i < LWKT_NUM_POOL_TOKENS; ++i) 808 lwkt_token_init(&pool_tokens[i], "pool"); 809 } 810 811 lwkt_token_t 812 lwkt_token_pool_lookup(void *ptr) 813 { 814 return (_lwkt_token_pool_lookup(ptr)); 815 } 816 817 /* 818 * Initialize a token. 819 */ 820 void 821 lwkt_token_init(lwkt_token_t tok, const char *desc) 822 { 823 tok->t_count = 0; 824 tok->t_ref = NULL; 825 tok->t_collisions = 0; 826 tok->t_desc = desc; 827 } 828 829 void 830 lwkt_token_uninit(lwkt_token_t tok) 831 { 832 /* empty */ 833 } 834 835 /* 836 * Exchange the two most recent tokens on the tokref stack. This allows 837 * you to release a token out of order. 838 * 839 * We have to be careful about the case where the top two tokens are 840 * the same token. In this case tok->t_ref will point to the deeper 841 * ref and must remain pointing to the deeper ref. If we were to swap 842 * it the first release would clear the token even though a second 843 * ref is still present. 844 * 845 * Only exclusively held tokens contain a reference to the tokref which 846 * has to be flipped along with the swap. 847 */ 848 void 849 lwkt_token_swap(void) 850 { 851 lwkt_tokref_t ref1, ref2; 852 lwkt_token_t tok1, tok2; 853 long count1, count2; 854 thread_t td = curthread; 855 856 crit_enter(); 857 858 ref1 = td->td_toks_stop - 1; 859 ref2 = td->td_toks_stop - 2; 860 KKASSERT(ref1 >= &td->td_toks_base); 861 KKASSERT(ref2 >= &td->td_toks_base); 862 863 tok1 = ref1->tr_tok; 864 tok2 = ref2->tr_tok; 865 count1 = ref1->tr_count; 866 count2 = ref2->tr_count; 867 868 if (tok1 != tok2) { 869 ref1->tr_tok = tok2; 870 ref1->tr_count = count2; 871 ref2->tr_tok = tok1; 872 ref2->tr_count = count1; 873 if (tok1->t_ref == ref1) 874 tok1->t_ref = ref2; 875 if (tok2->t_ref == ref2) 876 tok2->t_ref = ref1; 877 } 878 879 crit_exit(); 880 } 881