|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1993-1995, 1999-2000 Apple Computer, Inc. ! 3: * All rights reserved. ! 4: * ! 5: * @APPLE_LICENSE_HEADER_START@ ! 6: * ! 7: * The contents of this file constitute Original Code as defined in and ! 8: * are subject to the Apple Public Source License Version 1.1 (the ! 9: * "License"). You may not use this file except in compliance with the ! 10: * License. Please obtain a copy of the License at ! 11: * http://www.apple.com/publicsource and read it before using this file. ! 12: * ! 13: * This Original Code and all software distributed under the License are ! 14: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 15: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 16: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 17: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 18: * License for the specific language governing rights and limitations ! 19: * under the License. ! 20: * ! 21: * @APPLE_LICENSE_HEADER_END@ ! 22: */ ! 23: /* ! 24: * Thread-based callout module. ! 25: * ! 26: * HISTORY ! 27: * ! 28: * 10 July 1999 (debo) ! 29: * Pulled into Mac OS X (microkernel). ! 30: * ! 31: * 3 July 1993 (debo) ! 32: * Created. ! 33: */ ! 34: ! 35: #include <mach/mach_types.h> ! 36: ! 37: #include <kern/sched_prim.h> ! 38: #include <kern/clock.h> ! 39: #include <kern/task.h> ! 40: #include <kern/thread.h> ! 41: ! 42: #include <kern/thread_call.h> ! 43: #include <kern/thread_call_private.h> ! 44: ! 45: #define internal_call_num 768 ! 46: ! 47: #define thread_call_thread_min 4 ! 48: ! 49: static ! 50: struct thread_call ! 51: internal_call_storage[internal_call_num]; ! 52: ! 53: decl_simple_lock_data(static,thread_call_lock) ! 54: ! 55: static ! 56: queue_head_t ! 57: internal_call_free_queue, ! 58: pending_call_queue, delayed_call_queue; ! 59: ! 60: static ! 61: queue_head_t ! 62: idle_thread_queue; ! 63: ! 64: static ! 65: thread_t ! 66: activate_thread; ! 67: ! 68: static ! 69: boolean_t ! 70: activate_thread_awake; ! 71: ! 72: static struct { ! 73: int pending_num, ! 74: pending_hiwat; ! 75: int active_num, ! 76: active_hiwat; ! 77: int delayed_num, ! 78: delayed_hiwat; ! 79: int idle_thread_num; ! 80: int thread_num, ! 81: thread_hiwat, ! 82: thread_lowat; ! 83: } thread_calls; ! 84: ! 85: static boolean_t ! 86: thread_call_initialized = FALSE; ! 87: ! 88: static __inline__ thread_call_t ! 89: _internal_call_allocate(void); ! 90: ! 91: static __inline__ thread_call_t ! 92: thread_call_release( ! 93: thread_call_t call ! 94: ); ! 95: ! 96: static __inline__ void ! 97: _pending_call_enqueue( ! 98: thread_call_t call ! 99: ), ! 100: _pending_call_dequeue( ! 101: thread_call_t call ! 102: ), ! 103: _delayed_call_enqueue( ! 104: thread_call_t call ! 105: ), ! 106: _delayed_call_dequeue( ! 107: thread_call_t call ! 108: ); ! 109: ! 110: static void __inline__ ! 111: _set_delayed_call_timer( ! 112: thread_call_t call ! 113: ); ! 114: ! 115: static boolean_t ! 116: _remove_from_pending_queue( ! 117: thread_call_func_t func, ! 118: thread_call_param_t param0, ! 119: boolean_t remove_all ! 120: ), ! 121: _remove_from_delayed_queue( ! 122: thread_call_func_t func, ! 123: thread_call_param_t param0, ! 124: boolean_t remove_all ! 125: ); ! 126: ! 127: static __inline__ void ! 128: _call_thread_wake(void); ! 129: ! 130: static void ! 131: _call_thread(void), ! 132: _activate_thread(void); ! 133: ! 134: static void ! 135: _delayed_call_interrupt( ! 136: AbsoluteTime timestamp ! 137: ); ! 138: ! 139: #define qe(x) ((queue_entry_t)(x)) ! 140: #define TC(x) ((thread_call_t)(x)) ! 141: ! 142: static mk_sp_attribute_struct_t thread_call_attributes; ! 143: ! 144: /* ! 145: * Routine: thread_call_initialize [public] ! 146: * ! 147: * Description: Initialize this module, called ! 148: * early during system initialization. ! 149: * ! 150: * Preconditions: None. ! 151: * ! 152: * Postconditions: None. ! 153: */ ! 154: ! 155: void ! 156: thread_call_initialize(void) ! 157: { ! 158: thread_call_t call; ! 159: spl_t s; ! 160: ! 161: if (thread_call_initialized) ! 162: panic("thread_call_initialize"); ! 163: ! 164: simple_lock_init(&thread_call_lock, ETAP_MISC_TIMER); ! 165: ! 166: s = splsched(); ! 167: simple_lock(&thread_call_lock); ! 168: ! 169: queue_init(&pending_call_queue); ! 170: queue_init(&delayed_call_queue); ! 171: ! 172: queue_init(&internal_call_free_queue); ! 173: for ( ! 174: call = internal_call_storage; ! 175: call < &internal_call_storage[internal_call_num]; ! 176: call++) { ! 177: ! 178: enqueue_tail(&internal_call_free_queue, qe(call)); ! 179: } ! 180: ! 181: clock_set_timer_func((clock_timer_func_t)_delayed_call_interrupt); ! 182: ! 183: queue_init(&idle_thread_queue); ! 184: thread_calls.thread_lowat = thread_call_thread_min; ! 185: ! 186: thread_call_attributes.policy_id = POLICY_FIFO; ! 187: thread_call_attributes.priority = ! 188: thread_call_attributes.max_priority = BASEPRI_KERNEL-2; ! 189: thread_call_attributes.sched_data = ! 190: thread_call_attributes.unconsumed_quantum = 0; ! 191: activate_thread_awake = TRUE; ! 192: ! 193: thread_call_initialized = TRUE; ! 194: ! 195: simple_unlock(&thread_call_lock); ! 196: splx(s); ! 197: ! 198: activate_thread = ! 199: kernel_thread_with_attributes(kernel_task, ! 200: (sp_attributes_t)&thread_call_attributes, ! 201: _activate_thread, TRUE); ! 202: } ! 203: ! 204: /* ! 205: * Routine: _internal_call_allocate [private, inline] ! 206: * ! 207: * Purpose: Allocate an internal callout entry. ! 208: * ! 209: * Preconditions: thread_call_lock held. ! 210: * ! 211: * Postconditions: None. ! 212: */ ! 213: ! 214: static __inline__ thread_call_t ! 215: _internal_call_allocate(void) ! 216: { ! 217: thread_call_t call; ! 218: ! 219: if (queue_empty(&internal_call_free_queue)) ! 220: panic("_internal_call_allocate"); ! 221: ! 222: call = TC(dequeue_head(&internal_call_free_queue)); ! 223: ! 224: return (call); ! 225: } ! 226: ! 227: /* ! 228: * Routine: thread_call_release [private, inline] ! 229: * ! 230: * Purpose: Release a callout entry which is no ! 231: * longer pending (or delayed). Returns ! 232: * its argument for external entries, zero ! 233: * otherwise. ! 234: * ! 235: * Preconditions: thread_call_lock held. ! 236: * ! 237: * Postconditions: None. ! 238: */ ! 239: ! 240: static __inline__ ! 241: thread_call_t ! 242: thread_call_release( ! 243: thread_call_t call ! 244: ) ! 245: { ! 246: if ( call >= internal_call_storage && ! 247: call < &internal_call_storage[internal_call_num] ) { ! 248: ! 249: enqueue_tail(&internal_call_free_queue, qe(call)); ! 250: ! 251: return (NULL); ! 252: } ! 253: ! 254: return (call); ! 255: } ! 256: ! 257: /* ! 258: * Routine: _pending_call_enqueue [private, inline] ! 259: * ! 260: * Purpose: Place an entry at the end of the ! 261: * pending queue, to be executed soon. ! 262: * ! 263: * Preconditions: thread_call_lock held. ! 264: * ! 265: * Postconditions: None. ! 266: */ ! 267: ! 268: static __inline__ ! 269: void ! 270: _pending_call_enqueue( ! 271: thread_call_t call ! 272: ) ! 273: { ! 274: enqueue_tail(&pending_call_queue, qe(call)); ! 275: if (++thread_calls.pending_num > thread_calls.pending_hiwat) ! 276: thread_calls.pending_hiwat = thread_calls.pending_num; ! 277: ! 278: call->status = PENDING; ! 279: } ! 280: ! 281: /* ! 282: * Routine: _pending_call_dequeue [private, inline] ! 283: * ! 284: * Purpose: Remove an entry from the pending queue, ! 285: * effectively unscheduling it. ! 286: * ! 287: * Preconditions: thread_call_lock held. ! 288: * ! 289: * Postconditions: None. ! 290: */ ! 291: ! 292: static __inline__ ! 293: void ! 294: _pending_call_dequeue( ! 295: thread_call_t call ! 296: ) ! 297: { ! 298: remqueue(&pending_call_queue, qe(call)); ! 299: thread_calls.pending_num--; ! 300: ! 301: call->status = IDLE; ! 302: } ! 303: ! 304: /* ! 305: * Routine: _delayed_call_enqueue [private, inline] ! 306: * ! 307: * Purpose: Place an entry on the delayed queue, ! 308: * after existing entries with an earlier ! 309: * (or identical) deadline. ! 310: * ! 311: * Preconditions: thread_call_lock held. ! 312: * ! 313: * Postconditions: None. ! 314: */ ! 315: ! 316: static __inline__ ! 317: void ! 318: _delayed_call_enqueue( ! 319: thread_call_t call ! 320: ) ! 321: { ! 322: thread_call_t current; ! 323: int deadline_cmp; ! 324: ! 325: current = TC(queue_first(&delayed_call_queue)); ! 326: ! 327: while (TRUE) { ! 328: if ( queue_end(&delayed_call_queue, qe(current)) || ! 329: (deadline_cmp = ! 330: CMP_ABSOLUTETIME(&call->deadline, ! 331: ¤t->deadline)) < 0 ) { ! 332: current = TC(queue_prev(qe(current))); ! 333: break; ! 334: } ! 335: else if (deadline_cmp == 0) ! 336: break; ! 337: ! 338: current = TC(queue_next(qe(current))); ! 339: } ! 340: ! 341: insque(qe(call), qe(current)); ! 342: if (++thread_calls.delayed_num > thread_calls.delayed_hiwat) ! 343: thread_calls.delayed_hiwat = thread_calls.delayed_num; ! 344: ! 345: call->status = DELAYED; ! 346: } ! 347: ! 348: /* ! 349: * Routine: _delayed_call_dequeue [private, inline] ! 350: * ! 351: * Purpose: Remove an entry from the delayed queue, ! 352: * effectively unscheduling it. ! 353: * ! 354: * Preconditions: thread_call_lock held. ! 355: * ! 356: * Postconditions: None. ! 357: */ ! 358: ! 359: static __inline__ ! 360: void ! 361: _delayed_call_dequeue( ! 362: thread_call_t call ! 363: ) ! 364: { ! 365: remqueue(&delayed_call_queue, qe(call)); ! 366: thread_calls.delayed_num--; ! 367: ! 368: call->status = IDLE; ! 369: } ! 370: ! 371: /* ! 372: * Routine: _set_delayed_call_timer [private] ! 373: * ! 374: * Purpose: Reset the timer so that it ! 375: * next expires when the entry is due. ! 376: * ! 377: * Preconditions: thread_call_lock held. ! 378: * ! 379: * Postconditions: None. ! 380: */ ! 381: ! 382: static __inline__ void ! 383: _set_delayed_call_timer( ! 384: thread_call_t call ! 385: ) ! 386: { ! 387: clock_set_timer_deadline(call->deadline); ! 388: } ! 389: ! 390: /* ! 391: * Routine: _remove_from_pending_queue [private] ! 392: * ! 393: * Purpose: Remove the first (or all) matching ! 394: * entries from the pending queue, ! 395: * effectively unscheduling them. ! 396: * Returns whether any matching entries ! 397: * were found. ! 398: * ! 399: * Preconditions: thread_call_lock held. ! 400: * ! 401: * Postconditions: None. ! 402: */ ! 403: ! 404: static ! 405: boolean_t ! 406: _remove_from_pending_queue( ! 407: thread_call_func_t func, ! 408: thread_call_param_t param0, ! 409: boolean_t remove_all ! 410: ) ! 411: { ! 412: boolean_t call_removed = FALSE; ! 413: thread_call_t call; ! 414: ! 415: call = TC(queue_first(&pending_call_queue)); ! 416: ! 417: while (!queue_end(&pending_call_queue, qe(call))) { ! 418: if ( call->func == func && ! 419: call->param0 == param0 ) { ! 420: thread_call_t next = TC(queue_next(qe(call))); ! 421: ! 422: _pending_call_dequeue(call); ! 423: ! 424: thread_call_release(call); ! 425: ! 426: call_removed = TRUE; ! 427: if (!remove_all) ! 428: break; ! 429: ! 430: call = next; ! 431: } ! 432: else ! 433: call = TC(queue_next(qe(call))); ! 434: } ! 435: ! 436: return (call_removed); ! 437: } ! 438: ! 439: /* ! 440: * Routine: _remove_from_delayed_queue [private] ! 441: * ! 442: * Purpose: Remove the first (or all) matching ! 443: * entries from the delayed queue, ! 444: * effectively unscheduling them. ! 445: * Returns whether any matching entries ! 446: * were found. ! 447: * ! 448: * Preconditions: thread_call_lock held. ! 449: * ! 450: * Postconditions: None. ! 451: */ ! 452: ! 453: static ! 454: boolean_t ! 455: _remove_from_delayed_queue( ! 456: thread_call_func_t func, ! 457: thread_call_param_t param0, ! 458: boolean_t remove_all ! 459: ) ! 460: { ! 461: boolean_t call_removed = FALSE; ! 462: thread_call_t call; ! 463: ! 464: call = TC(queue_first(&delayed_call_queue)); ! 465: ! 466: while (!queue_end(&delayed_call_queue, qe(call))) { ! 467: if ( call->func == func && ! 468: call->param0 == param0 ) { ! 469: thread_call_t next = TC(queue_next(qe(call))); ! 470: ! 471: _delayed_call_dequeue(call); ! 472: ! 473: thread_call_release(call); ! 474: ! 475: call_removed = TRUE; ! 476: if (!remove_all) ! 477: break; ! 478: ! 479: call = next; ! 480: } ! 481: else ! 482: call = TC(queue_next(qe(call))); ! 483: } ! 484: ! 485: return (call_removed); ! 486: } ! 487: ! 488: /* ! 489: * Routine: thread_call_func [public] ! 490: * ! 491: * Purpose: Schedule a function callout. ! 492: * Guarantees { function, argument } ! 493: * uniqueness if unique_call is TRUE. ! 494: * ! 495: * Preconditions: Callable from an interrupt context ! 496: * below splsched. ! 497: * ! 498: * Postconditions: None. ! 499: */ ! 500: ! 501: void ! 502: thread_call_func( ! 503: thread_call_func_t func, ! 504: thread_call_param_t param, ! 505: boolean_t unique_call ! 506: ) ! 507: { ! 508: thread_call_t call; ! 509: int s; ! 510: ! 511: if (!thread_call_initialized) ! 512: panic("thread_call_func"); ! 513: ! 514: s = splsched(); ! 515: simple_lock(&thread_call_lock); ! 516: ! 517: call = TC(queue_first(&pending_call_queue)); ! 518: ! 519: while (unique_call && !queue_end(&pending_call_queue, qe(call))) { ! 520: if ( call->func == func && ! 521: call->param0 == param ) { ! 522: break; ! 523: } ! 524: ! 525: call = TC(queue_next(qe(call))); ! 526: } ! 527: ! 528: if (!unique_call || queue_end(&pending_call_queue, qe(call))) { ! 529: call = _internal_call_allocate(); ! 530: call->func = func; ! 531: call->param0 = param; ! 532: call->param1 = 0; ! 533: ! 534: _pending_call_enqueue(call); ! 535: ! 536: _call_thread_wake(); ! 537: } ! 538: ! 539: simple_unlock(&thread_call_lock); ! 540: splx(s); ! 541: } ! 542: ! 543: /* ! 544: * Routine: thread_call_func_delayed [public] ! 545: * ! 546: * Purpose: Schedule a function callout to ! 547: * occur at the stated time. ! 548: * ! 549: * Preconditions: Callable from an interrupt context ! 550: * below splsched. ! 551: * ! 552: * Postconditions: None. ! 553: */ ! 554: ! 555: void ! 556: thread_call_func_delayed( ! 557: thread_call_func_t func, ! 558: thread_call_param_t param, ! 559: AbsoluteTime deadline ! 560: ) ! 561: { ! 562: thread_call_t call; ! 563: int s; ! 564: ! 565: if (!thread_call_initialized) ! 566: panic("thread_call_func_delayed"); ! 567: ! 568: s = splsched(); ! 569: simple_lock(&thread_call_lock); ! 570: ! 571: call = _internal_call_allocate(); ! 572: call->func = func; ! 573: call->param0 = param; ! 574: call->param1 = 0; ! 575: call->deadline = deadline; ! 576: ! 577: _delayed_call_enqueue(call); ! 578: ! 579: if (queue_first(&delayed_call_queue) == qe(call)) ! 580: _set_delayed_call_timer(call); ! 581: ! 582: simple_unlock(&thread_call_lock); ! 583: splx(s); ! 584: } ! 585: ! 586: /* ! 587: * Routine: thread_call_func_cancel [public] ! 588: * ! 589: * Purpose: Unschedule a function callout. ! 590: * Removes one (or all) ! 591: * { function, argument } ! 592: * instance(s) from either (or both) ! 593: * the pending and the delayed queue, ! 594: * in that order. Returns a boolean ! 595: * indicating whether any calls were ! 596: * cancelled. ! 597: * ! 598: * Preconditions: Callable from an interrupt context ! 599: * below splsched. ! 600: * ! 601: * Postconditions: None. ! 602: */ ! 603: ! 604: boolean_t ! 605: thread_call_func_cancel( ! 606: thread_call_func_t func, ! 607: thread_call_param_t param, ! 608: boolean_t cancel_all ! 609: ) ! 610: { ! 611: boolean_t result; ! 612: int s; ! 613: ! 614: s = splsched(); ! 615: simple_lock(&thread_call_lock); ! 616: ! 617: if (cancel_all) ! 618: result = _remove_from_pending_queue(func, param, cancel_all) | ! 619: _remove_from_delayed_queue(func, param, cancel_all); ! 620: else ! 621: result = _remove_from_pending_queue(func, param, cancel_all) || ! 622: _remove_from_delayed_queue(func, param, cancel_all); ! 623: ! 624: simple_unlock(&thread_call_lock); ! 625: splx(s); ! 626: ! 627: return (result); ! 628: } ! 629: ! 630: /* ! 631: * Routine: thread_call_allocate [public] ! 632: * ! 633: * Purpose: Allocate an external callout ! 634: * entry. ! 635: * ! 636: * Preconditions: None. ! 637: * ! 638: * Postconditions: None. ! 639: */ ! 640: ! 641: thread_call_t ! 642: thread_call_allocate( ! 643: thread_call_func_t func, ! 644: thread_call_param_t param0 ! 645: ) ! 646: { ! 647: thread_call_t call = (void *)kalloc(sizeof (struct thread_call)); ! 648: ! 649: call->func = func; ! 650: call->param0 = param0; ! 651: call->status = IDLE; ! 652: ! 653: return (call); ! 654: } ! 655: ! 656: /* ! 657: * Routine: thread_call_free [public] ! 658: * ! 659: * Purpose: Free an external callout ! 660: * entry. ! 661: * ! 662: * Preconditions: None. ! 663: * ! 664: * Postconditions: None. ! 665: */ ! 666: ! 667: boolean_t ! 668: thread_call_free( ! 669: thread_call_t call ! 670: ) ! 671: { ! 672: int s; ! 673: ! 674: s = splsched(); ! 675: simple_lock(&thread_call_lock); ! 676: ! 677: if (call->status != IDLE) { ! 678: simple_unlock(&thread_call_lock); ! 679: splx(s); ! 680: ! 681: return (FALSE); ! 682: } ! 683: ! 684: simple_unlock(&thread_call_lock); ! 685: splx(s); ! 686: ! 687: kfree((vm_offset_t)call, sizeof (struct thread_call)); ! 688: ! 689: return (TRUE); ! 690: } ! 691: ! 692: /* ! 693: * Routine: thread_call_enter [public] ! 694: * ! 695: * Purpose: Schedule an external callout ! 696: * entry to occur "soon". ! 697: * ! 698: * Preconditions: Callable from an interrupt context ! 699: * below splsched. ! 700: * ! 701: * Postconditions: None. ! 702: */ ! 703: ! 704: void ! 705: thread_call_enter( ! 706: thread_call_t call ! 707: ) ! 708: { ! 709: int s; ! 710: ! 711: s = splsched(); ! 712: simple_lock(&thread_call_lock); ! 713: ! 714: if (call->status != PENDING) { ! 715: if (call->status == DELAYED) ! 716: _delayed_call_dequeue(call); ! 717: ! 718: call->param1 = 0; ! 719: ! 720: _pending_call_enqueue(call); ! 721: ! 722: _call_thread_wake(); ! 723: } ! 724: ! 725: simple_unlock(&thread_call_lock); ! 726: splx(s); ! 727: } ! 728: ! 729: void ! 730: thread_call_enter1( ! 731: thread_call_t call, ! 732: thread_call_param_t param1 ! 733: ) ! 734: { ! 735: int s; ! 736: ! 737: s = splsched(); ! 738: simple_lock(&thread_call_lock); ! 739: ! 740: if (call->status != PENDING) { ! 741: if (call->status == DELAYED) ! 742: _delayed_call_dequeue(call); ! 743: ! 744: call->param1 = param1; ! 745: ! 746: _pending_call_enqueue(call); ! 747: ! 748: _call_thread_wake(); ! 749: } ! 750: ! 751: simple_unlock(&thread_call_lock); ! 752: splx(s); ! 753: } ! 754: ! 755: /* ! 756: * Routine: thread_call_enter_delayed [public] ! 757: * ! 758: * Purpose: Schedule an external callout ! 759: * entry to occur at the stated time. ! 760: * ! 761: * Preconditions: Callable from an interrupt context ! 762: * below splsched. ! 763: * ! 764: * Postconditions: None. ! 765: */ ! 766: ! 767: void ! 768: thread_call_enter_delayed( ! 769: thread_call_t call, ! 770: AbsoluteTime deadline ! 771: ) ! 772: { ! 773: int s; ! 774: ! 775: s = splsched(); ! 776: simple_lock(&thread_call_lock); ! 777: ! 778: if (call->status == PENDING) ! 779: _pending_call_dequeue(call); ! 780: else if (call->status == DELAYED) ! 781: _delayed_call_dequeue(call); ! 782: ! 783: call->param1 = 0; ! 784: call->deadline = deadline; ! 785: ! 786: _delayed_call_enqueue(call); ! 787: ! 788: if (queue_first(&delayed_call_queue) == qe(call)) ! 789: _set_delayed_call_timer(call); ! 790: ! 791: simple_unlock(&thread_call_lock); ! 792: splx(s); ! 793: } ! 794: ! 795: void ! 796: thread_call_enter1_delayed( ! 797: thread_call_t call, ! 798: thread_call_param_t param1, ! 799: AbsoluteTime deadline ! 800: ) ! 801: { ! 802: int s; ! 803: ! 804: s = splsched(); ! 805: simple_lock(&thread_call_lock); ! 806: ! 807: if (call->status == PENDING) ! 808: _pending_call_dequeue(call); ! 809: else if (call->status == DELAYED) ! 810: _delayed_call_dequeue(call); ! 811: ! 812: call->param1 = param1; ! 813: call->deadline = deadline; ! 814: ! 815: _delayed_call_enqueue(call); ! 816: ! 817: if (queue_first(&delayed_call_queue) == qe(call)) ! 818: _set_delayed_call_timer(call); ! 819: ! 820: simple_unlock(&thread_call_lock); ! 821: splx(s); ! 822: } ! 823: ! 824: /* ! 825: * Routine: thread_call_cancel [public] ! 826: * ! 827: * Purpose: Unschedule a callout entry. ! 828: * Returns a boolean indicating ! 829: * whether the call had actually ! 830: * been scheduled. ! 831: * ! 832: * Preconditions: Callable from an interrupt context ! 833: * below splsched. ! 834: * ! 835: * Postconditions: None. ! 836: */ ! 837: ! 838: boolean_t ! 839: thread_call_cancel( ! 840: thread_call_t call ! 841: ) ! 842: { ! 843: boolean_t result = TRUE; ! 844: int s; ! 845: ! 846: s = splsched(); ! 847: simple_lock(&thread_call_lock); ! 848: ! 849: if (call->status == PENDING) { ! 850: _pending_call_dequeue(call); ! 851: ! 852: thread_call_release(call); ! 853: } ! 854: else if (call->status == DELAYED) { ! 855: _delayed_call_dequeue(call); ! 856: ! 857: thread_call_release(call); ! 858: } ! 859: else ! 860: result = FALSE; ! 861: ! 862: simple_unlock(&thread_call_lock); ! 863: splx(s); ! 864: ! 865: return (result); ! 866: } ! 867: ! 868: boolean_t ! 869: thread_call_is_delayed( ! 870: thread_call_t call, ! 871: AbsoluteTime *deadline) ! 872: { ! 873: boolean_t result = FALSE; ! 874: int s; ! 875: ! 876: s = splsched(); ! 877: simple_lock(&thread_call_lock); ! 878: ! 879: if (call->status == DELAYED) { ! 880: if (deadline != NULL) ! 881: *deadline = call->deadline; ! 882: result = TRUE; ! 883: } ! 884: ! 885: simple_unlock(&thread_call_lock); ! 886: splx(s); ! 887: ! 888: return (result); ! 889: } ! 890: ! 891: /* ! 892: * Routine: _call_thread_wake [private] ! 893: * ! 894: * Purpose: Wake a callout thread to service ! 895: * newly pending callout entries. May wake ! 896: * the activate thread to either wake or ! 897: * create additional callout threads. ! 898: * ! 899: * Preconditions: thread_call_lock held. ! 900: * ! 901: * Postconditions: None. ! 902: */ ! 903: ! 904: static __inline__ ! 905: void ! 906: _call_thread_wake(void) ! 907: { ! 908: thread_t thread_to_wake; ! 909: ! 910: if (!queue_empty(&idle_thread_queue)) { ! 911: queue_remove_first( ! 912: &idle_thread_queue, thread_to_wake, thread_t, wait_link); ! 913: clear_wait(thread_to_wake, THREAD_AWAKENED, FALSE); ! 914: thread_calls.idle_thread_num--; ! 915: } ! 916: else ! 917: thread_to_wake = THREAD_NULL; ! 918: ! 919: if (!activate_thread_awake && ! 920: (thread_to_wake == THREAD_NULL || thread_calls.thread_num < ! 921: (thread_calls.active_num + thread_calls.pending_num))) { ! 922: clear_wait(activate_thread, THREAD_AWAKENED, FALSE); ! 923: activate_thread_awake = TRUE; ! 924: } ! 925: } ! 926: ! 927: #define NO_CONTINUATIONS (0) ! 928: ! 929: /* ! 930: * Routine: _call_thread [private] ! 931: * ! 932: * Purpose: Executed by a callout thread. ! 933: * ! 934: * Preconditions: None. ! 935: * ! 936: * Postconditions: None. ! 937: */ ! 938: ! 939: static ! 940: void ! 941: _call_thread_continue(void) ! 942: { ! 943: thread_t self = current_thread(); ! 944: ! 945: #if NO_CONTINUATIONS ! 946: loop: ! 947: #endif ! 948: (void) splsched(); ! 949: simple_lock(&thread_call_lock); ! 950: ! 951: while (thread_calls.pending_num > 0) { ! 952: thread_call_t call; ! 953: thread_call_func_t func; ! 954: thread_call_param_t param0, param1; ! 955: ! 956: call = TC(dequeue_head(&pending_call_queue)); ! 957: thread_calls.pending_num--; ! 958: ! 959: func = call->func; ! 960: param0 = call->param0; ! 961: param1 = call->param1; ! 962: ! 963: call->status = IDLE; ! 964: ! 965: thread_call_release(call); ! 966: ! 967: if (++thread_calls.active_num > thread_calls.active_hiwat) ! 968: thread_calls.active_hiwat = thread_calls.active_num; ! 969: ! 970: if (thread_calls.pending_num > 0) ! 971: _call_thread_wake(); ! 972: ! 973: simple_unlock(&thread_call_lock); ! 974: (void) spllo(); ! 975: ! 976: (*func)(param0, param1); ! 977: ! 978: (void) splsched(); ! 979: simple_lock(&thread_call_lock); ! 980: ! 981: thread_calls.active_num--; ! 982: } ! 983: ! 984: if ((thread_calls.thread_num - thread_calls.active_num) <= ! 985: thread_calls.thread_lowat) { ! 986: queue_enter(&idle_thread_queue, self, thread_t, wait_link); ! 987: thread_calls.idle_thread_num++; ! 988: ! 989: assert_wait(&idle_thread_queue, THREAD_INTERRUPTIBLE); ! 990: ! 991: simple_unlock(&thread_call_lock); ! 992: (void) spllo(); ! 993: ! 994: #if NO_CONTINUATIONS ! 995: thread_block((void (*)(void)) 0); ! 996: goto loop; ! 997: #else ! 998: thread_block(_call_thread_continue); ! 999: #endif ! 1000: /* NOTREACHED */ ! 1001: } ! 1002: ! 1003: thread_calls.thread_num--; ! 1004: ! 1005: simple_unlock(&thread_call_lock); ! 1006: (void) spllo(); ! 1007: ! 1008: (void) thread_terminate(self->top_act); ! 1009: /* NOTREACHED */ ! 1010: } ! 1011: ! 1012: static ! 1013: void ! 1014: _call_thread(void) ! 1015: { ! 1016: thread_t self = current_thread(); ! 1017: ! 1018: stack_privilege(self); ! 1019: ! 1020: _call_thread_continue(); ! 1021: /* NOTREACHED */ ! 1022: } ! 1023: ! 1024: /* ! 1025: * Routine: _activate_thread [private] ! 1026: * ! 1027: * Purpose: Executed by the activate thread. ! 1028: * ! 1029: * Preconditions: None. ! 1030: * ! 1031: * Postconditions: Never terminates. ! 1032: */ ! 1033: ! 1034: static ! 1035: void ! 1036: _activate_thread_continue(void) ! 1037: { ! 1038: #if NO_CONTINUATIONS ! 1039: loop: ! 1040: #endif ! 1041: (void) splsched(); ! 1042: simple_lock(&thread_call_lock); ! 1043: ! 1044: if (thread_calls.thread_num < ! 1045: (thread_calls.active_num + thread_calls.pending_num)) { ! 1046: ! 1047: if (++thread_calls.thread_num > thread_calls.thread_hiwat) ! 1048: thread_calls.thread_hiwat = thread_calls.thread_num; ! 1049: ! 1050: simple_unlock(&thread_call_lock); ! 1051: (void) spllo(); ! 1052: ! 1053: (void) kernel_thread_with_attributes(kernel_task, ! 1054: (sp_attributes_t)&thread_call_attributes, ! 1055: _call_thread, TRUE); ! 1056: #if NO_CONTINUATIONS ! 1057: thread_block((void (*)(void)) 0); ! 1058: goto loop; ! 1059: #else ! 1060: thread_block(_activate_thread_continue); ! 1061: #endif ! 1062: /* NOTREACHED */ ! 1063: } ! 1064: else if (thread_calls.pending_num > 0) { ! 1065: _call_thread_wake(); ! 1066: ! 1067: simple_unlock(&thread_call_lock); ! 1068: (void) spllo(); ! 1069: ! 1070: #if NO_CONTINUATIONS ! 1071: thread_block((void (*)(void)) 0); ! 1072: goto loop; ! 1073: #else ! 1074: thread_block(_activate_thread_continue); ! 1075: #endif ! 1076: /* NOTREACHED */ ! 1077: } ! 1078: ! 1079: assert_wait(&activate_thread_awake, THREAD_INTERRUPTIBLE); ! 1080: activate_thread_awake = FALSE; ! 1081: ! 1082: simple_unlock(&thread_call_lock); ! 1083: (void) spllo(); ! 1084: ! 1085: #if NO_CONTINUATIONS ! 1086: thread_block((void (*)(void)) 0); ! 1087: goto loop; ! 1088: #else ! 1089: thread_block(_activate_thread_continue); ! 1090: #endif ! 1091: /* NOTREACHED */ ! 1092: } ! 1093: ! 1094: static ! 1095: void ! 1096: _activate_thread(void) ! 1097: { ! 1098: thread_t self = current_thread(); ! 1099: ! 1100: self->vm_privilege = TRUE; ! 1101: vm_page_free_reserve(2); /* XXX */ ! 1102: stack_privilege(self); ! 1103: ! 1104: /* ! 1105: * Set scheduling priority for ! 1106: * call threads. ! 1107: */ ! 1108: thread_call_attributes.priority = ! 1109: thread_call_attributes.max_priority = BASEPRI_KERNEL-1; ! 1110: ! 1111: _activate_thread_continue(); ! 1112: /* NOTREACHED */ ! 1113: } ! 1114: ! 1115: static ! 1116: void ! 1117: _delayed_call_interrupt( ! 1118: AbsoluteTime timestamp ! 1119: ) ! 1120: { ! 1121: thread_call_t call; ! 1122: int s; ! 1123: ! 1124: s = splsched(); ! 1125: simple_lock(&thread_call_lock); ! 1126: ! 1127: call = TC(queue_first(&delayed_call_queue)); ! 1128: ! 1129: while (!queue_end(&delayed_call_queue, qe(call))) { ! 1130: if (CMP_ABSOLUTETIME(&call->deadline, ×tamp) <= 0) { ! 1131: _delayed_call_dequeue(call); ! 1132: ! 1133: _pending_call_enqueue(call); ! 1134: } ! 1135: else ! 1136: break; ! 1137: ! 1138: call = TC(queue_first(&delayed_call_queue)); ! 1139: } ! 1140: ! 1141: if (!queue_end(&delayed_call_queue, qe(call))) ! 1142: _set_delayed_call_timer(call); ! 1143: ! 1144: _call_thread_wake(); ! 1145: ! 1146: simple_unlock(&thread_call_lock); ! 1147: splx(s); ! 1148: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.