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