1 /* 2 * Copyright (c) 2017 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 #ifndef _TURNSTILE_H_ 30 #define _TURNSTILE_H_ 31 32 #include <mach/mach_types.h> 33 #include <mach/kern_return.h> 34 #include <sys/cdefs.h> 35 36 __BEGIN_DECLS 37 38 #if PRIVATE 39 #define TURNSTILE_MAX_HOP_DEFAULT (10) 40 struct turnstile_stats { 41 uint64_t ts_priority_propagation; 42 uint64_t ts_no_inheritor; 43 uint64_t ts_thread_runnable; 44 uint64_t ts_no_priority_change_required; 45 uint64_t ts_above_ui_pri_change; 46 uint64_t ts_no_turnstile; 47 }; 48 #endif 49 50 #ifdef KERNEL_PRIVATE 51 #include <kern/queue.h> 52 #include <sys/queue.h> 53 #include <kern/waitq.h> 54 #include <kern/priority_queue.h> 55 #include <os/refcnt.h> 56 #include <kern/assert.h> 57 #include <kern/kern_types.h> 58 #include <kern/locks.h> 59 60 /* 61 * turnstile_type_t : Indicates the type of primitive the turnstile is associated with 62 * Please populate turnstile_promote_policy array if a new type is added here. 63 */ 64 typedef enum __attribute__((packed)) turnstile_type { 65 TURNSTILE_NONE = 0, 66 TURNSTILE_KERNEL_MUTEX = 1, 67 TURNSTILE_ULOCK = 2, 68 TURNSTILE_PTHREAD_MUTEX = 3, 69 TURNSTILE_SYNC_IPC = 4, 70 TURNSTILE_WORKLOOPS = 5, 71 TURNSTILE_WORKQS = 6, 72 TURNSTILE_KNOTE = 7, 73 TURNSTILE_SLEEP_INHERITOR = 8, 74 TURNSTILE_EPOCH_KERNEL = 9, 75 TURNSTILE_EPOCH_USER = 10, 76 TURNSTILE_TOTAL_TYPES = 11, 77 } turnstile_type_t; 78 79 /* 80 * For each type of turnstile, following are the type of 81 * inheritors passed: 82 * 83 * TURNSTILE_KERNEL_MUTEX 84 * Interlock: kernel mutex interlock. 85 * Inheritor: threads. 86 * Lock order: turnstile lock, thread lock. 87 * 88 * TURNSTILE_ULOCK 89 * Interlock: ulocks interlock. 90 * Inheritor: threads. 91 * Lock order: turnstile lock, thread lock. 92 * 93 * TURNSTILE_PTHREAD_MUTEX 94 * Interlock: pthread mtx interlock. 95 * Inheritor: threads. 96 * Lock order: turnstile lock, thread lock. 97 * 98 * TURNSTILE_SYNC_IPC 99 * Interlock: port's mqueue lock 100 * Inheritor: turnstile (of port in which we are enqueued or WL turnstile. 101 * Lock order: Our turnstile, then turnstile of the port we are enqueued in. 102 * Port circularity will make sure there is never a cycle formation 103 * and lock order is maintained. 104 * 105 * TURNSTILE_WORKLOOPS 106 * Interlock: 107 * - kq req lock 108 * - wq lock when "filt_wlworkq_interlock_needed() is true" 109 * Inheritor: thread, turnstile (of workq) 110 * Lock order: turnstile lock, thread lock 111 * WL turnstile lock, Workq turnstile lock 112 * 113 * TURNSTILE_WORKQS 114 * Interlock: workqueue lock 115 * Inheritor: thread 116 * Lock order: turnstile lock, thread lock. 117 * 118 * TURNSTILE_KNOTE 119 * Interlock: the knote lock 120 * Inheritor: WL turnstile 121 * 122 * TURNSTILE_SLEEP_INHERITOR 123 * Interlock: turnstile_htable bucket spinlock. 124 * Inheritor: threads. 125 * Lock order: turnstile lock, thread lock. 126 * 127 * TURNSTILE_EPOCH_KERNEL 128 * Interlock: the epoch sync interlock. 129 * Inheritor: threads. 130 * Lock order: turnstile lock, thread lock. 131 * 132 * TURNSTILE_EPOCH_USER 133 * Interlock: the epoch sync interlock. 134 * Inheritor: threads. 135 * Lock order: turnstile lock, thread lock. 136 */ 137 138 typedef enum __attribute__((flag_enum)) turnstile_promote_policy { 139 TURNSTILE_PROMOTE_NONE = 0, 140 TURNSTILE_KERNEL_PROMOTE = 0x1, 141 TURNSTILE_USER_PROMOTE = 0x2, 142 TURNSTILE_USER_IPC_PROMOTE = 0x4, 143 } turnstile_promote_policy_t; 144 145 typedef enum __attribute__((flag_enum)) turnstile_hash_lock_policy { 146 TURNSTILE_HASH_LOCK_POLICY_NONE = 0, 147 TURNSTILE_IRQ_UNSAFE_HASH = 0x1, 148 TURNSTILE_LOCKED_HASH = 0x2, 149 } turnstile_hash_lock_policy_t; 150 151 /* 152 * Turnstile state flags 153 * 154 * The turnstile state flags represent the current ownership of a turnstile. 155 * The supported flags are: 156 * - TURNSTILE_STATE_THREAD : Turnstile is attached to a thread 157 * - TURNSTILE_STATE_FREELIST : Turnstile is hanging off the freelist of another turnstile 158 * - TURNSTILE_STATE_HASHTABLE : Turnstile is in the global hash table as the turnstile for a primitive 159 * - TURNSTILE_STATE_PROPRIETOR : Turnstile is attached to a proprietor 160 * 161 * The flag updates are done while holding the primitive interlock. 162 * */ 163 164 #define TURNSTILE_STATE_THREAD 0x1 165 #define TURNSTILE_STATE_FREELIST 0x2 166 #define TURNSTILE_STATE_HASHTABLE 0x4 167 #define TURNSTILE_STATE_PROPRIETOR 0x8 168 169 /* Helper macros to set/unset turnstile state flags */ 170 #if DEVELOPMENT || DEBUG 171 172 #define turnstile_state_init(ts, state) \ 173 MACRO_BEGIN \ 174 ts->ts_state = state; \ 175 MACRO_END 176 177 #define turnstile_state_add(ts, state) \ 178 MACRO_BEGIN \ 179 assert((ts->ts_state & (state)) == 0); \ 180 ts->ts_state |= state; \ 181 MACRO_END 182 183 #define turnstile_state_remove(ts, state) \ 184 MACRO_BEGIN \ 185 assert(ts->ts_state & (state)); \ 186 ts->ts_state &= ~(state); \ 187 MACRO_END 188 189 #else /* DEVELOPMENT || DEBUG */ 190 191 #define turnstile_state_init(ts, state) \ 192 MACRO_BEGIN \ 193 (void)ts; \ 194 MACRO_END 195 196 #define turnstile_state_add(ts, state) \ 197 MACRO_BEGIN \ 198 (void)ts; \ 199 MACRO_END 200 201 #define turnstile_state_remove(ts, state) \ 202 MACRO_BEGIN \ 203 (void)ts; \ 204 MACRO_END 205 206 #endif /* DEVELOPMENT || DEBUG */ 207 208 struct knote; 209 struct turnstile; 210 211 /* 212 * Turnstile update flags 213 * 214 * TURNSTILE_IMMEDIATE_UPDATE 215 * When passed to turnstile_update_inheritor 216 * update the inheritor of the turnstile in 217 * the same call. 218 * 219 * TURNSTILE_DELAYED_UPDATE 220 * When passed to turnstile_update_inheritor 221 * it stashed the inheritor on the thread and 222 * turnstile's inheritor is updated in 223 * assert wait. 224 * 225 * TURNSTILE_INHERITOR_THREAD 226 * The turnstile inheritor is of type thread. 227 * 228 * TURNSTILE_INHERITOR_TURNSTILE 229 * The turnstile inheritor is of type turnstile. 230 * 231 * TURNSTILE_INHERITOR_WORKQ 232 * The turnstile inheritor is of type workqueue 233 * 234 * TURNSTILE_INHERITOR_NEEDS_PRI_UPDATE 235 * The inheritor needs a chain priority update. 236 * 237 * TURNSTILE_NEEDS_PRI_UPDATE 238 * Current turnstile needs a chain priority update. 239 * 240 * Locking order for passing thread and turnstile as inheritor 241 * 242 * Thread as an inheritor: 243 * When thread is passed as an inheritor of a turnstile 244 * turnstile lock is taken and then thread lock. 245 * 246 * Turnstile as in inheritor: 247 * When turnstile (T1) is passed as an inheritor of 248 * a turnstile (T2), turnstile lock of T2 is taken 249 * and then turnstile lock of T1 is taken. 250 * 251 * Caution: While passing turnstile as an inheritor, its 252 * job of the adopter to make sure that there is no 253 * lock inversion. 254 */ 255 typedef enum __attribute__((flag_enum)) __attribute__((packed)) turnstile_update_flags { 256 TURNSTILE_UPDATE_FLAGS_NONE = 0, 257 TURNSTILE_IMMEDIATE_UPDATE = 0x1, 258 TURNSTILE_DELAYED_UPDATE = 0x2, 259 TURNSTILE_INHERITOR_THREAD = 0x4, 260 TURNSTILE_INHERITOR_TURNSTILE = 0x8, 261 TURNSTILE_INHERITOR_NEEDS_PRI_UPDATE = 0x10, 262 TURNSTILE_NEEDS_PRI_UPDATE = 0x20, 263 TURNSTILE_INHERITOR_WORKQ = 0x40, 264 TURNSTILE_UPDATE_BOOST = 0x80, 265 } turnstile_update_flags_t; 266 267 #define TURNSTILE_NULL ((struct turnstile *)0) 268 269 typedef void * turnstile_inheritor_t; 270 271 #define TURNSTILE_INHERITOR_NULL NULL 272 273 #ifdef XNU_KERNEL_PRIVATE 274 #pragma GCC visibility push(hidden) 275 276 /* Turnstile stats update flags 277 * 278 * TSU_TURNSTILE_BLOCK_COUNT 279 * thread blocking on turnstile waitq, increment global 280 * thread block on turnstile count. 281 * 282 * TSU_REGULAR_WAITQ_BLOCK_COUNT 283 * thread blocking on regular waitq, increment global 284 * thread block on regular waitq count. 285 * 286 * TSU_PRI_PROPAGATION 287 * turnstile propagation update stopped at nth hop, update 288 * priority change count for nth element in stats array. 289 * 290 * TSU_NO_INHERITOR 291 * turnstile propagation update stopped due to turnstile 292 * not having an inheritor after nth hop, update the no 293 * inheritor count for nth element in the stats array. 294 * 295 * TSU_NO_TURNSTILE 296 * turnstile propagation update stopped due to thread 297 * not blocked on a turnstile waitq after nth hop, update 298 * the no turnstile count for the nth element in the stats 299 * array. 300 * 301 * TSU_NO_PRI_CHANGE_NEEDED 302 * turnstile propagation update stopped due to thread or 303 * turnstile having the correct priority or not blocked. 304 * update the no priority change count for the nth element 305 * in the stats array. 306 * 307 * TSU_THREAD_RUNNABLE 308 * turnstile propagation update stopped due to thread 309 * being runnable, update the thread runnable count for 310 * the nth element in the stats array. 311 * 312 * TSU_ABOVE_UI_PRI_CHANGE 313 * turnstile propagation caused an above UI priority change. 314 */ 315 typedef enum __attribute__((flag_enum)) turnstile_stats_update_flags { 316 TSU_FLAGS_NONE = 0, 317 TSU_TURNSTILE_BLOCK_COUNT = 0x1, 318 TSU_REGULAR_WAITQ_BLOCK_COUNT = 0x2, 319 TSU_PRI_PROPAGATION = 0x4, 320 TSU_NO_INHERITOR = 0x8, 321 TSU_NO_TURNSTILE = 0x10, 322 TSU_NO_PRI_CHANGE_NEEDED = 0x20, 323 TSU_THREAD_RUNNABLE = 0x40, 324 TSU_ABOVE_UI_PRI_CHANGE = 0x80, 325 TSU_THREAD_ARG = 0x100, 326 TSU_TURNSTILE_ARG = 0x200, 327 TSU_BOOST_ARG = 0x400, 328 } turnstile_stats_update_flags_t; 329 330 SLIST_HEAD(turnstile_list, turnstile); 331 332 #define CTSID_BITS 20 333 #define CTSID_MASK ((1u << CTSID_BITS) - 1) 334 #define CTSID_MAX (CTSID_MASK - 1) 335 336 struct turnstile { 337 union { 338 /* 339 * The waitq_eventmask field is only used on the global queues. 340 * We hence repurpose all those bits for our own use. 341 */ 342 #if MACH_KERNEL_PRIVATE 343 WAITQ_FLAGS(ts_waitq 344 , __ts_unused_bits: 7 345 , ts_compact_id: CTSID_BITS); 346 #endif 347 struct waitq ts_waitq; /* waitq embedded in turnstile */ 348 }; 349 #define ts_inheritor ts_waitq.waitq_inheritor /* thread/turnstile inheriting the priority (IL, WL) */ 350 union { 351 struct turnstile_list ts_free_turnstiles; /* turnstile free list (IL) */ 352 SLIST_ENTRY(turnstile) ts_free_elm; /* turnstile free list element (IL) */ 353 }; 354 struct priority_queue_sched_max ts_inheritor_queue; /* Queue of turnstile with us as an inheritor (WL) */ 355 struct priority_queue_entry_sched ts_inheritor_links; /* Inheritor queue links */ 356 SLIST_ENTRY(turnstile) ts_htable_link; /* linkage for turnstile in global hash table */ 357 uintptr_t ts_proprietor; /* hash key lookup turnstile (IL) */ 358 os_ref_atomic_t ts_refcount; /* reference count for turnstiles */ 359 _Atomic uint32_t ts_type_gencount; /* gen count used for priority chaining (IL), type of turnstile (IL) */ 360 uint32_t ts_prim_count; /* counter used by the primitive */ 361 turnstile_update_flags_t ts_inheritor_flags; /* flags for turnstile inheritor (IL, WL) */ 362 uint8_t ts_priority; /* priority of turnstile (WL) */ 363 364 #if DEVELOPMENT || DEBUG 365 uint8_t ts_state; /* current state of turnstile (IL) */ 366 thread_t ts_thread; /* thread the turnstile is attached to */ 367 thread_t ts_prev_thread; /* thread the turnstile was attached before donation */ 368 #endif 369 }; 370 371 #define waitq_to_turnstile(waitq) __container_of(waitq, struct turnstile, ts_waitq) 372 373 /* IL - interlock, WL - turnstile lock i.e. waitq lock */ 374 375 #define TURNSTILE_PROPRIETOR_NULL 0ul 376 377 /* 378 * Name: turnstiles_init 379 * 380 * Description: Initialize turnstile sub system. 381 * 382 * Args: None. 383 * 384 * Returns: None. 385 */ 386 void 387 turnstiles_init(void); 388 389 /* 390 * Name: turnstile_alloc 391 * 392 * Description: Allocate a turnstile. 393 * 394 * Args: None. 395 * 396 * Returns: 397 * turnstile on Success. 398 */ 399 struct turnstile * 400 turnstile_alloc(void); 401 402 /* 403 * Name: turnstile_compact_id_get() 404 * 405 * Description: Allocate a compact turnstile ID slot. 406 * 407 * Args: None. 408 * 409 * Returns: 410 * A non 0 compact compact turnstile ID. 411 */ 412 uint32_t 413 turnstile_compact_id_get(void); 414 415 /* 416 * Name: turnstile_compact_id_put() 417 * 418 * Description: Frees a compact turnstile ID slot. 419 * 420 * Args: 421 * Args1: the compact ID to free. 422 */ 423 void 424 turnstile_compact_id_put(uint32_t cid); 425 426 /* 427 * Name: turnstile_get_by_id 428 * 429 * Description: Resolve a turnstile by compact ID 430 * 431 * Args: 432 * Arg1: turnstile compact ID 433 * 434 * Returns: a turnstile 435 */ 436 struct turnstile * 437 turnstile_get_by_id(uint32_t tsid); 438 439 /* 440 * Name: turnstile_reference 441 * 442 * Description: Take a reference on the turnstile. 443 * 444 * Arg1: turnstile 445 * 446 * Returns: None. 447 */ 448 void 449 turnstile_reference(struct turnstile *turnstile); 450 451 /* 452 * Name: turnstile_deallocate 453 * 454 * Description: Drop a reference on the turnstile. 455 * Destroy the turnstile if the last ref. 456 * 457 * Arg1: turnstile 458 * 459 * Returns: None. 460 */ 461 void 462 turnstile_deallocate(struct turnstile *turnstile); 463 464 /* 465 * Name: turnstile_waitq_add_thread_priority_queue 466 * 467 * Description: add thread to the turnstile waitq 468 * 469 * Arg1: waitq 470 * Arg2: thread 471 * 472 * Conditions: waitq locked 473 */ 474 void 475 turnstile_waitq_add_thread_priority_queue( 476 struct waitq* wq, 477 thread_t thread); 478 479 /* 480 * Name: turnstile_recompute_priority_locked 481 * 482 * Description: Update turnstile priority based 483 * on highest waiter thread and highest blocking 484 * turnstile. 485 * 486 * Args: turnstile 487 * 488 * Returns: TRUE: if the turnstile priority changed and needs propagation. 489 * FALSE: if the turnstile priority did not change or it does not need propagation. 490 * 491 * Condition: turnstile locked 492 */ 493 boolean_t 494 turnstile_recompute_priority_locked( 495 struct turnstile *turnstile); 496 497 /* 498 * Name: turnstile_recompute_priority 499 * 500 * Description: Update turnstile priority based 501 * on highest waiter thread and highest blocking 502 * turnstile. 503 * 504 * Args: turnstile 505 * 506 * Returns: TRUE: if the turnstile priority changed and needs propagation. 507 * FALSE: if the turnstile priority did not change or it does not need propagation. 508 */ 509 boolean_t 510 turnstile_recompute_priority( 511 struct turnstile *turnstile); 512 513 /* 514 * Name: turnstile_workq_proprietor_of_max_turnstile 515 * 516 * Description: Returns the highest priority and proprietor of a turnstile 517 * pushing on a workqueue turnstile. 518 * 519 * This will not return waiters that are at priority 520 * MAXPRI_THROTTLE or lower. 521 * 522 * Args: turnstile 523 * 524 * Returns: 525 * Priority of the max entry, or 0 526 * Pointer to the max entry proprietor 527 */ 528 int 529 turnstile_workq_proprietor_of_max_turnstile( 530 struct turnstile *turnstile, 531 uintptr_t *proprietor); 532 533 /* 534 * Name: turnstile_workloop_pusher_info 535 * 536 * Description: Returns the priority of the turnstile push for a workloop, 537 * and the thread or knote responsible for this push. 538 * 539 * Args: workloop turnstile 540 * 541 * Returns: 542 * Priority of the push or 0 543 * Thread (with a +1 reference) with that push or THREAD_NULL. 544 * Port (with a +1 reference) with that push, or IP_NULL. 545 * Sync IPC knote with the highest push (or NULL) 546 */ 547 int 548 turnstile_workloop_pusher_info( 549 struct turnstile *turnstile, 550 thread_t *thread, 551 ipc_port_t *port, 552 struct knote **knote_out); 553 554 /* 555 * Name: turnstile_cleanup 556 * 557 * Description: Update priority of a turnstile inheritor 558 * if needed. 559 * 560 * Args: inheritor and flags passed on thread struct. 561 * 562 * Returns: None. 563 */ 564 void 565 turnstile_cleanup(void); 566 567 /* 568 * Name: turnstile_update_thread_priority_chain 569 * 570 * Description: Priority of a thread blocked on a turnstile 571 * has changed, update the turnstile priority. 572 * 573 * Arg1: thread: thread whose priority has changed. 574 * 575 * Returns: None. 576 */ 577 void 578 turnstile_update_thread_priority_chain(thread_t thread); 579 580 /* 581 * Name: turnstile_update_inheritor_locked 582 * 583 * Description: Update the inheritor of the turnstile and boost the 584 * inheritor, called with turnstile locked. 585 * 586 * Args: 587 * Arg1: turnstile 588 * Implicit arg: new inheritor value is stashed in current thread's struct 589 * 590 * Returns: 591 * old inheritor reference is returned on current thread's struct. 592 */ 593 void 594 turnstile_update_inheritor_locked(struct turnstile *turnstile); 595 596 /* 597 * Name: thread_get_inheritor_turnstile_base_priority 598 * 599 * Description: Get the max base priority of all the inheritor turnstiles 600 * 601 * Arg1: thread 602 * 603 * Returns: Max base priority of all the inheritor turnstiles. 604 * 605 * Condition: thread locked 606 */ 607 int 608 thread_get_inheritor_turnstile_base_priority(thread_t thread); 609 610 /* 611 * Name: thread_get_inheritor_turnstile_sched_priority 612 * 613 * Description: Get the max sched priority of all the inheritor turnstiles 614 * 615 * Arg1: thread 616 * 617 * Returns: Max sched priority of all the inheritor turnstiles. 618 * 619 * Condition: thread locked 620 */ 621 int 622 thread_get_inheritor_turnstile_sched_priority(thread_t thread); 623 624 /* 625 * Name: thread_get_waiting_turnstile 626 * 627 * Description: Get the turnstile if the thread is waiting on a turnstile. 628 * 629 * Arg1: thread 630 * 631 * Returns: turnstile: if the thread is blocked on a turnstile. 632 * TURNSTILE_NULL: otherwise. 633 * 634 * Condition: thread locked. 635 */ 636 struct turnstile * 637 thread_get_waiting_turnstile(thread_t thread); 638 639 /* 640 * Name: turnstile_lookup_by_proprietor 641 * 642 * Description: Get turnstile for a proprietor from global 643 * turnstile hash. 644 * 645 * Arg1: port 646 * Arg2: turnstile_type_t type 647 * 648 * Returns: turnstile: if the proprietor has a turnstile. 649 * TURNSTILE_NULL: otherwise. 650 * 651 * Condition: proprietor interlock held. 652 */ 653 struct turnstile * 654 turnstile_lookup_by_proprietor(uintptr_t proprietor, turnstile_type_t type); 655 656 /* 657 * Name: turnstile_has_waiters 658 * 659 * Description: returns if there are waiters on the turnstile 660 * 661 * Arg1: turnstile: turnstile 662 * 663 * Returns: TRUE if there are waiters, FALSE otherwise. 664 */ 665 666 boolean_t 667 turnstile_has_waiters(struct turnstile *turnstile); 668 669 /* 670 * Name: turnstile_stats_update 671 * 672 * Description: Function to update turnstile stats for dev kernel. 673 * 674 * Arg1: hops : number of thread hops in priority propagation 675 * Arg2: flags : turnstile stats update flags 676 * Arg3: inheritor: inheritor 677 * 678 * Returns: Nothing 679 */ 680 void 681 turnstile_stats_update( 682 int hop __assert_only, 683 turnstile_stats_update_flags_t flags __assert_only, 684 turnstile_inheritor_t inheritor __assert_only); 685 686 #if DEVELOPMENT || DEBUG 687 688 #define SYSCTL_TURNSTILE_TEST_USER_DEFAULT 1 689 #define SYSCTL_TURNSTILE_TEST_USER_HASHTABLE 2 690 #define SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT 3 691 #define SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE 4 692 693 /* Functions used by debug test primitive exported by sysctls */ 694 int 695 tstile_test_prim_lock(int val); 696 697 int 698 tstile_test_prim_unlock(int val); 699 700 int 701 turnstile_get_boost_stats_sysctl(void *req); 702 int 703 turnstile_get_unboost_stats_sysctl(void *req); 704 #endif /* DEVELOPMENT || DEBUG */ 705 706 #pragma GCC visibility pop 707 #endif /* XNU_KERNEL_PRIVATE */ 708 709 /* Interface */ 710 711 /* 712 * Name: turnstile_hash_bucket_lock 713 * 714 * Description: locks the spinlock associated with proprietor's bucket. 715 * if proprietor is specified the index for the hash will be 716 * recomputed and returned in index_proprietor, 717 * otherwise the value save in index_proprietor is used as index. 718 * 719 * Args: 720 * Arg1: proprietor (key) for hashing 721 * Arg2: index for proprietor in the hash 722 * Arg3: turnstile type 723 * 724 * Returns: old value of irq if irq were disabled before acquiring the lock. 725 */ 726 unsigned 727 turnstile_hash_bucket_lock(uintptr_t proprietor, uint32_t *index_proprietor, turnstile_type_t type); 728 729 /* 730 * Name: turnstile_hash_bucket_unlock 731 * 732 * Description: unlocks the spinlock associated with proprietor's bucket. 733 * if proprietor is specified the index for the hash will be 734 * recomputed and returned in index_proprietor, 735 * otherwise the value save in index_proprietor is used as index. 736 * 737 * Args: 738 * Arg1: proprietor (key) for hashing 739 * Arg2: index for proprietor in the hash 740 * Arg3: turnstile type 741 * Arg4: irq value returned by turnstile_hash_bucket_lock 742 * 743 */ 744 void 745 turnstile_hash_bucket_unlock(uintptr_t proprietor, uint32_t *index_proprietor, turnstile_type_t type, unsigned s); 746 747 /* 748 * Name: turnstile_prepare 749 * 750 * Description: Transfer current thread's turnstile to primitive or it's free turnstile list. 751 * Function is called holding the interlock (spinlock) of the primitive. 752 * The turnstile returned by this function is safe to use until 753 * the thread calls turnstile_complete. 754 * When no turnstile is provided explicitly, the calling thread will not have a turnstile attached to 755 * it until it calls turnstile_complete. 756 * 757 * Args: 758 * Arg1: proprietor 759 * Arg2: pointer in primitive struct to store turnstile 760 * Arg3: turnstile to use instead of taking it from thread. 761 * Arg4: type of primitive 762 * 763 * Returns: 764 * turnstile. 765 */ 766 struct turnstile * 767 turnstile_prepare( 768 uintptr_t proprietor, 769 struct turnstile **tstore, 770 struct turnstile *turnstile, 771 turnstile_type_t type); 772 773 /* 774 * Name: turnstile_complete 775 * 776 * Description: Transfer the primitive's turnstile or from it's freelist to current thread. 777 * Function is called holding the interlock (spinlock) of the primitive. 778 * Current thread will have a turnstile attached to it after this call. 779 * 780 * Args: 781 * Arg1: proprietor 782 * Arg2: pointer in primitive struct to update turnstile 783 * Arg3: pointer to store the returned turnstile instead of attaching it to thread 784 * Arg4: type of primitive 785 * 786 * Returns: 787 * None. 788 */ 789 void 790 turnstile_complete( 791 uintptr_t proprietor, 792 struct turnstile **tstore, 793 struct turnstile **turnstile, 794 turnstile_type_t type); 795 796 /* 797 * Name: turnstile_prepare_compact_id 798 * 799 * Description: Transfer current thread's turnstile to primitive or it's free turnstile list. 800 * Function is called holding the interlock (spinlock) of the primitive. 801 * The turnstile returned by this function is safe to use until 802 * the thread calls turnstile_complete_compact_id. 803 * The calling thread will not have a turnstile attached to 804 * it until it calls turnstile_complete_compact_id. 805 * 806 * Args: 807 * Arg1: proprietor 808 * Arg2: the current compact ID for the turnstile head 809 * Arg3: type of primitive 810 * 811 * Returns: 812 * turnstile. 813 */ 814 struct turnstile * 815 turnstile_prepare_compact_id( 816 uintptr_t proprietor, 817 uint32_t compact_id, 818 turnstile_type_t type); 819 820 /* 821 * Name: turnstile_complete_compact_id 822 * 823 * Description: Transfer the primitive's turnstile or from it's freelist to current thread. 824 * Function is called holding the interlock (spinlock) of the primitive. 825 * Current thread will have a turnstile attached to it after this call. 826 * 827 * Args: 828 * Arg1: proprietor 829 * Arg2: the turnstile pointer that was returned by turnstile_prepare_compact_id() 830 * Arg3: type of primitive 831 * 832 * Returns: 833 * Whether the primitive no longer has a turnstile. 834 */ 835 bool 836 turnstile_complete_compact_id( 837 uintptr_t proprietor, 838 struct turnstile *turnstile, 839 turnstile_type_t type); 840 841 /* 842 * Name: turnstile_prepare_hash 843 * 844 * Description: Transfer current thread's turnstile to primitive or it's free turnstile list. 845 * Function is called holding the interlock (spinlock) of the primitive. 846 * The turnstile returned by this function is safe to use until 847 * the thread calls turnstile_complete_hash. 848 * The calling thread will not have a turnstile attached to 849 * it until it calls turnstile_complete_hash. 850 * 851 * The turnstile used for this proprietor will be stored in 852 * a global hash table. 853 * 854 * Args: 855 * Arg1: proprietor 856 * Arg3: type of primitive 857 * 858 * Returns: 859 * turnstile. 860 */ 861 struct turnstile * 862 turnstile_prepare_hash( 863 uintptr_t proprietor, 864 turnstile_type_t type); 865 866 /* 867 * Name: turnstile_complete_hash 868 * 869 * Description: Transfer the primitive's turnstile or from it's freelist to current thread. 870 * Function is called holding the interlock (spinlock) of the primitive. 871 * Current thread will have a turnstile attached to it after this call. 872 * 873 * Args: 874 * Arg1: proprietor 875 * Arg3: type of primitive 876 * 877 * Returns: 878 * None. 879 */ 880 void 881 turnstile_complete_hash( 882 uintptr_t proprietor, 883 turnstile_type_t type); 884 885 /* 886 * Name: turnstile_update_inheritor 887 * 888 * Description: Update the inheritor of the turnstile and boost the 889 * inheritor. It will take a thread reference on the inheritor. 890 * Called with the interlock of the primitive held. 891 * 892 * Args: 893 * Arg1: turnstile 894 * Arg2: inheritor 895 * Arg3: flags - TURNSTILE_DELAYED_UPDATE - update will happen later in assert_wait 896 * 897 * Returns: 898 * old inheritor reference is stashed on current thread's struct. 899 */ 900 void 901 turnstile_update_inheritor( 902 struct turnstile *turnstile, 903 turnstile_inheritor_t new_inheritor, 904 turnstile_update_flags_t flags); 905 906 typedef enum turnstile_update_complete_flags { 907 TURNSTILE_INTERLOCK_NOT_HELD = 0x1, 908 TURNSTILE_INTERLOCK_HELD = 0x2, 909 } turnstile_update_complete_flags_t; 910 911 /* 912 * Name: turnstile_update_inheritor_complete 913 * 914 * Description: Update turnstile inheritor's priority and propagate the 915 * priority if the inheritor is blocked on a turnstile. 916 * Consumes thread ref of old inheritor returned by 917 * turnstile_update_inheritor. Recursive priority update 918 * will only happen when called with interlock dropped. 919 * 920 * Args: 921 * Arg1: turnstile 922 * Arg2: interlock held 923 * 924 * Returns: None. 925 */ 926 void 927 turnstile_update_inheritor_complete( 928 struct turnstile *turnstile, 929 turnstile_update_complete_flags_t flags); 930 931 932 /* 933 * Name: turnstile_kernel_update_inheritor_on_wake_locked 934 * 935 * Description: Set thread as the inheritor of the turnstile and 936 * boost the inheritor. 937 * Args: 938 * Arg1: turnstile 939 * Arg2: new_inheritor 940 * Arg3: flags 941 * 942 * Called with turnstile locked 943 */ 944 void 945 turnstile_kernel_update_inheritor_on_wake_locked( 946 struct turnstile *turnstile, 947 turnstile_inheritor_t new_inheritor, 948 turnstile_update_flags_t flags); 949 950 #endif /* KERNEL_PRIVATE */ 951 #if XNU_KERNEL_PRIVATE 952 953 struct workqueue; 954 955 /* pthread_workqueue.c */ 956 extern void workq_reference(struct workqueue *wq); 957 extern void workq_deallocate_safe(struct workqueue *wq); 958 extern bool workq_is_current_thread_updating_turnstile(struct workqueue *wq); 959 extern void workq_schedule_creator_turnstile_redrive(struct workqueue *wq, 960 bool locked); 961 962 #endif /* XNU_KERNEL_PRIVATE */ 963 964 __END_DECLS 965 966 #endif /* _TURNSTILE_H_ */ 967