|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993-1988 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: kern/task.c ! 28: * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub, ! 29: * David Black ! 30: * ! 31: * Task management primitives implementation. ! 32: */ ! 33: ! 34: #include <mach_host.h> ! 35: #include <mach_pcsample.h> ! 36: #include <norma_task.h> ! 37: #include <fast_tas.h> ! 38: #include <net_atm.h> ! 39: ! 40: #include <mach/machine/vm_types.h> ! 41: #include <mach/vm_param.h> ! 42: #include <mach/task_info.h> ! 43: #include <mach/task_special_ports.h> ! 44: #include <ipc/ipc_space.h> ! 45: #include <ipc/ipc_types.h> ! 46: #include <kern/mach_param.h> ! 47: #include <kern/task.h> ! 48: #include <kern/thread.h> ! 49: #include <kern/zalloc.h> ! 50: #include <kern/kalloc.h> ! 51: #include <kern/processor.h> ! 52: #include <kern/sched_prim.h> /* for thread_wakeup */ ! 53: #include <kern/ipc_tt.h> ! 54: #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */ ! 55: #include <machine/machspl.h> /* for splsched */ ! 56: ! 57: #if NET_ATM ! 58: #include <chips/nw_mk.h> ! 59: #endif ! 60: ! 61: #if NORMA_TASK ! 62: #define task_create task_create_local ! 63: #endif /* NORMA_TASK */ ! 64: ! 65: task_t kernel_task = TASK_NULL; ! 66: zone_t task_zone; ! 67: ! 68: extern void eml_init(void); ! 69: extern void eml_task_reference(task_t, task_t); ! 70: extern void eml_task_deallocate(task_t); ! 71: ! 72: void task_init(void) ! 73: { ! 74: task_zone = zinit( ! 75: sizeof(struct task), ! 76: TASK_MAX * sizeof(struct task), ! 77: TASK_CHUNK * sizeof(struct task), ! 78: 0, "tasks"); ! 79: ! 80: eml_init(); ! 81: machine_task_module_init (); ! 82: ! 83: /* ! 84: * Create the kernel task as the first task. ! 85: * Task_create must assign to kernel_task as a side effect, ! 86: * for other initialization. (:-() ! 87: */ ! 88: (void) task_create(TASK_NULL, FALSE, &kernel_task); ! 89: } ! 90: ! 91: /* ! 92: * Create a task running in the kernel address space. It may ! 93: * have its own map of size mem_size (if 0, it uses the kernel map), ! 94: * and may have ipc privileges. ! 95: */ ! 96: task_t kernel_task_create( ! 97: task_t parent_task, ! 98: vm_size_t map_size) ! 99: { ! 100: task_t new_task; ! 101: vm_offset_t min, max; ! 102: ! 103: /* ! 104: * Create the task. ! 105: */ ! 106: (void) task_create(parent_task, FALSE, &new_task); ! 107: ! 108: /* ! 109: * Task_create creates the task with a user-space map. ! 110: * Remove the map and replace it with the kernel map ! 111: * or a submap of the kernel map. ! 112: */ ! 113: vm_map_deallocate(new_task->map); ! 114: if (map_size == 0) ! 115: new_task->map = kernel_map; ! 116: else ! 117: new_task->map = kmem_suballoc(kernel_map, &min, &max, ! 118: map_size, FALSE); ! 119: ! 120: return new_task; ! 121: } ! 122: ! 123: kern_return_t task_create( ! 124: task_t parent_task, ! 125: boolean_t inherit_memory, ! 126: task_t *child_task) /* OUT */ ! 127: { ! 128: register task_t new_task; ! 129: register processor_set_t pset; ! 130: int i; ! 131: ! 132: new_task = (task_t) zalloc(task_zone); ! 133: if (new_task == TASK_NULL) { ! 134: panic("task_create: no memory for task structure"); ! 135: } ! 136: ! 137: /* one ref for just being alive; one for our caller */ ! 138: new_task->ref_count = 2; ! 139: ! 140: if (child_task == &kernel_task) { ! 141: new_task->map = kernel_map; ! 142: } else if (inherit_memory) { ! 143: new_task->map = vm_map_fork(parent_task->map); ! 144: } else { ! 145: new_task->map = vm_map_create(pmap_create(0), ! 146: round_page(VM_MIN_ADDRESS), ! 147: trunc_page(VM_MAX_ADDRESS), TRUE); ! 148: } ! 149: ! 150: simple_lock_init(&new_task->lock); ! 151: queue_init(&new_task->thread_list); ! 152: new_task->suspend_count = 0; ! 153: new_task->active = TRUE; ! 154: new_task->user_stop_count = 0; ! 155: new_task->thread_count = 0; ! 156: ! 157: eml_task_reference(new_task, parent_task); ! 158: ! 159: ipc_task_init(new_task, parent_task); ! 160: ! 161: #if NET_ATM ! 162: new_task->nw_ep_owned = 0; ! 163: #endif ! 164: machine_task_init (new_task); ! 165: ! 166: new_task->total_user_time.seconds = 0; ! 167: new_task->total_user_time.microseconds = 0; ! 168: new_task->total_system_time.seconds = 0; ! 169: new_task->total_system_time.microseconds = 0; ! 170: ! 171: record_time_stamp (&new_task->creation_time); ! 172: ! 173: if (parent_task != TASK_NULL) { ! 174: task_lock(parent_task); ! 175: pset = parent_task->processor_set; ! 176: if (!pset->active) ! 177: pset = &default_pset; ! 178: pset_reference(pset); ! 179: new_task->priority = parent_task->priority; ! 180: task_unlock(parent_task); ! 181: } ! 182: else { ! 183: pset = &default_pset; ! 184: pset_reference(pset); ! 185: new_task->priority = BASEPRI_USER; ! 186: } ! 187: pset_lock(pset); ! 188: pset_add_task(pset, new_task); ! 189: pset_unlock(pset); ! 190: ! 191: new_task->may_assign = TRUE; ! 192: new_task->assign_active = FALSE; ! 193: ! 194: #if MACH_PCSAMPLE ! 195: new_task->pc_sample.buffer = 0; ! 196: new_task->pc_sample.seqno = 0; ! 197: new_task->pc_sample.sampletypes = 0; ! 198: #endif /* MACH_PCSAMPLE */ ! 199: ! 200: #if FAST_TAS ! 201: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) { ! 202: if (inherit_memory) { ! 203: new_task->fast_tas_base[i] = parent_task->fast_tas_base[i]; ! 204: new_task->fast_tas_end[i] = parent_task->fast_tas_end[i]; ! 205: } else { ! 206: new_task->fast_tas_base[i] = (vm_offset_t)0; ! 207: new_task->fast_tas_end[i] = (vm_offset_t)0; ! 208: } ! 209: } ! 210: #endif /* FAST_TAS */ ! 211: ! 212: ipc_task_enable(new_task); ! 213: ! 214: #if NORMA_TASK ! 215: new_task->child_node = -1; ! 216: #endif /* NORMA_TASK */ ! 217: ! 218: *child_task = new_task; ! 219: return KERN_SUCCESS; ! 220: } ! 221: ! 222: /* ! 223: * task_deallocate: ! 224: * ! 225: * Give up a reference to the specified task and destroy it if there ! 226: * are no other references left. It is assumed that the current thread ! 227: * is never in this task. ! 228: */ ! 229: void task_deallocate( ! 230: register task_t task) ! 231: { ! 232: register int c; ! 233: register processor_set_t pset; ! 234: ! 235: if (task == TASK_NULL) ! 236: return; ! 237: ! 238: task_lock(task); ! 239: c = --(task->ref_count); ! 240: task_unlock(task); ! 241: if (c != 0) ! 242: return; ! 243: ! 244: #if NORMA_TASK ! 245: if (task->map == VM_MAP_NULL) { ! 246: /* norma placeholder task */ ! 247: zfree(task_zone, (vm_offset_t) task); ! 248: return; ! 249: } ! 250: #endif /* NORMA_TASK */ ! 251: ! 252: machine_task_terminate (task); ! 253: ! 254: eml_task_deallocate(task); ! 255: ! 256: pset = task->processor_set; ! 257: pset_lock(pset); ! 258: pset_remove_task(pset,task); ! 259: pset_unlock(pset); ! 260: pset_deallocate(pset); ! 261: vm_map_deallocate(task->map); ! 262: is_release(task->itk_space); ! 263: zfree(task_zone, (vm_offset_t) task); ! 264: } ! 265: ! 266: void task_reference( ! 267: register task_t task) ! 268: { ! 269: if (task == TASK_NULL) ! 270: return; ! 271: ! 272: task_lock(task); ! 273: task->ref_count++; ! 274: task_unlock(task); ! 275: } ! 276: ! 277: /* ! 278: * task_terminate: ! 279: * ! 280: * Terminate the specified task. See comments on thread_terminate ! 281: * (kern/thread.c) about problems with terminating the "current task." ! 282: */ ! 283: kern_return_t task_terminate( ! 284: register task_t task) ! 285: { ! 286: register thread_t thread, cur_thread; ! 287: register queue_head_t *list; ! 288: register task_t cur_task; ! 289: spl_t s; ! 290: ! 291: if (task == TASK_NULL) ! 292: return KERN_INVALID_ARGUMENT; ! 293: ! 294: list = &task->thread_list; ! 295: cur_task = current_task(); ! 296: cur_thread = current_thread(); ! 297: ! 298: #if NET_ATM ! 299: /* ! 300: * Shut down networking. ! 301: */ ! 302: mk_endpoint_collect(task); ! 303: #endif ! 304: ! 305: /* ! 306: * Deactivate task so that it can't be terminated again, ! 307: * and so lengthy operations in progress will abort. ! 308: * ! 309: * If the current thread is in this task, remove it from ! 310: * the task's thread list to keep the thread-termination ! 311: * loop simple. ! 312: */ ! 313: if (task == cur_task) { ! 314: task_lock(task); ! 315: if (!task->active) { ! 316: /* ! 317: * Task is already being terminated. ! 318: */ ! 319: task_unlock(task); ! 320: return KERN_FAILURE; ! 321: } ! 322: /* ! 323: * Make sure current thread is not being terminated. ! 324: */ ! 325: s = splsched(); ! 326: thread_lock(cur_thread); ! 327: if (!cur_thread->active) { ! 328: thread_unlock(cur_thread); ! 329: (void) splx(s); ! 330: task_unlock(task); ! 331: thread_terminate(cur_thread); ! 332: return KERN_FAILURE; ! 333: } ! 334: task->active = FALSE; ! 335: queue_remove(list, cur_thread, thread_t, thread_list); ! 336: thread_unlock(cur_thread); ! 337: (void) splx(s); ! 338: task_unlock(task); ! 339: ! 340: /* ! 341: * Shut down this thread's ipc now because it must ! 342: * be left alone to terminate the task. ! 343: */ ! 344: ipc_thread_disable(cur_thread); ! 345: ipc_thread_terminate(cur_thread); ! 346: } ! 347: else { ! 348: /* ! 349: * Lock both current and victim task to check for ! 350: * potential deadlock. ! 351: */ ! 352: if ((vm_offset_t)task < (vm_offset_t)cur_task) { ! 353: task_lock(task); ! 354: task_lock(cur_task); ! 355: } ! 356: else { ! 357: task_lock(cur_task); ! 358: task_lock(task); ! 359: } ! 360: /* ! 361: * Check if current thread or task is being terminated. ! 362: */ ! 363: s = splsched(); ! 364: thread_lock(cur_thread); ! 365: if ((!cur_task->active) ||(!cur_thread->active)) { ! 366: /* ! 367: * Current task or thread is being terminated. ! 368: */ ! 369: thread_unlock(cur_thread); ! 370: (void) splx(s); ! 371: task_unlock(task); ! 372: task_unlock(cur_task); ! 373: thread_terminate(cur_thread); ! 374: return KERN_FAILURE; ! 375: } ! 376: thread_unlock(cur_thread); ! 377: (void) splx(s); ! 378: task_unlock(cur_task); ! 379: ! 380: if (!task->active) { ! 381: /* ! 382: * Task is already being terminated. ! 383: */ ! 384: task_unlock(task); ! 385: return KERN_FAILURE; ! 386: } ! 387: task->active = FALSE; ! 388: task_unlock(task); ! 389: } ! 390: ! 391: /* ! 392: * Prevent further execution of the task. ipc_task_disable ! 393: * prevents further task operations via the task port. ! 394: * If this is the current task, the current thread will ! 395: * be left running. ! 396: */ ! 397: ipc_task_disable(task); ! 398: (void) task_hold(task); ! 399: (void) task_dowait(task,TRUE); /* may block */ ! 400: ! 401: /* ! 402: * Terminate each thread in the task. ! 403: * ! 404: * The task_port is closed down, so no more thread_create ! 405: * operations can be done. Thread_force_terminate closes the ! 406: * thread port for each thread; when that is done, the ! 407: * thread will eventually disappear. Thus the loop will ! 408: * terminate. Call thread_force_terminate instead of ! 409: * thread_terminate to avoid deadlock checks. Need ! 410: * to call thread_block() inside loop because some other ! 411: * thread (e.g., the reaper) may have to run to get rid ! 412: * of all references to the thread; it won't vanish from ! 413: * the task's thread list until the last one is gone. ! 414: */ ! 415: task_lock(task); ! 416: while (!queue_empty(list)) { ! 417: thread = (thread_t) queue_first(list); ! 418: thread_reference(thread); ! 419: task_unlock(task); ! 420: thread_force_terminate(thread); ! 421: thread_deallocate(thread); ! 422: thread_block((void (*)()) 0); ! 423: task_lock(task); ! 424: } ! 425: task_unlock(task); ! 426: ! 427: /* ! 428: * Shut down IPC. ! 429: */ ! 430: ipc_task_terminate(task); ! 431: ! 432: ! 433: /* ! 434: * Deallocate the task's reference to itself. ! 435: */ ! 436: task_deallocate(task); ! 437: ! 438: /* ! 439: * If the current thread is in this task, it has not yet ! 440: * been terminated (since it was removed from the task's ! 441: * thread-list). Put it back in the thread list (for ! 442: * completeness), and terminate it. Since it holds the ! 443: * last reference to the task, terminating it will deallocate ! 444: * the task. ! 445: */ ! 446: if (cur_thread->task == task) { ! 447: task_lock(task); ! 448: s = splsched(); ! 449: queue_enter(list, cur_thread, thread_t, thread_list); ! 450: (void) splx(s); ! 451: task_unlock(task); ! 452: (void) thread_terminate(cur_thread); ! 453: } ! 454: ! 455: return KERN_SUCCESS; ! 456: } ! 457: ! 458: /* ! 459: * task_hold: ! 460: * ! 461: * Suspend execution of the specified task. ! 462: * This is a recursive-style suspension of the task, a count of ! 463: * suspends is maintained. ! 464: */ ! 465: kern_return_t task_hold( ! 466: register task_t task) ! 467: { ! 468: register queue_head_t *list; ! 469: register thread_t thread, cur_thread; ! 470: ! 471: cur_thread = current_thread(); ! 472: ! 473: task_lock(task); ! 474: if (!task->active) { ! 475: task_unlock(task); ! 476: return KERN_FAILURE; ! 477: } ! 478: ! 479: task->suspend_count++; ! 480: ! 481: /* ! 482: * Iterate through all the threads and hold them. ! 483: * Do not hold the current thread if it is within the ! 484: * task. ! 485: */ ! 486: list = &task->thread_list; ! 487: queue_iterate(list, thread, thread_t, thread_list) { ! 488: if (thread != cur_thread) ! 489: thread_hold(thread); ! 490: } ! 491: task_unlock(task); ! 492: return KERN_SUCCESS; ! 493: } ! 494: ! 495: /* ! 496: * task_dowait: ! 497: * ! 498: * Wait until the task has really been suspended (all of the threads ! 499: * are stopped). Skip the current thread if it is within the task. ! 500: * ! 501: * If task is deactivated while waiting, return a failure code unless ! 502: * must_wait is true. ! 503: */ ! 504: kern_return_t task_dowait( ! 505: register task_t task, ! 506: boolean_t must_wait) ! 507: { ! 508: register queue_head_t *list; ! 509: register thread_t thread, cur_thread, prev_thread; ! 510: register kern_return_t ret = KERN_SUCCESS; ! 511: ! 512: /* ! 513: * Iterate through all the threads. ! 514: * While waiting for each thread, we gain a reference to it ! 515: * to prevent it from going away on us. This guarantees ! 516: * that the "next" thread in the list will be a valid thread. ! 517: * ! 518: * We depend on the fact that if threads are created while ! 519: * we are looping through the threads, they will be held ! 520: * automatically. We don't care about threads that get ! 521: * deallocated along the way (the reference prevents it ! 522: * from happening to the thread we are working with). ! 523: * ! 524: * If the current thread is in the affected task, it is skipped. ! 525: * ! 526: * If the task is deactivated before we're done, and we don't ! 527: * have to wait for it (must_wait is FALSE), just bail out. ! 528: */ ! 529: cur_thread = current_thread(); ! 530: ! 531: list = &task->thread_list; ! 532: prev_thread = THREAD_NULL; ! 533: task_lock(task); ! 534: queue_iterate(list, thread, thread_t, thread_list) { ! 535: if (!(task->active) && !(must_wait)) { ! 536: ret = KERN_FAILURE; ! 537: break; ! 538: } ! 539: if (thread != cur_thread) { ! 540: thread_reference(thread); ! 541: task_unlock(task); ! 542: if (prev_thread != THREAD_NULL) ! 543: thread_deallocate(prev_thread); ! 544: /* may block */ ! 545: (void) thread_dowait(thread, TRUE); /* may block */ ! 546: prev_thread = thread; ! 547: task_lock(task); ! 548: } ! 549: } ! 550: task_unlock(task); ! 551: if (prev_thread != THREAD_NULL) ! 552: thread_deallocate(prev_thread); /* may block */ ! 553: return ret; ! 554: } ! 555: ! 556: kern_return_t task_release( ! 557: register task_t task) ! 558: { ! 559: register queue_head_t *list; ! 560: register thread_t thread, next; ! 561: ! 562: task_lock(task); ! 563: if (!task->active) { ! 564: task_unlock(task); ! 565: return KERN_FAILURE; ! 566: } ! 567: ! 568: task->suspend_count--; ! 569: ! 570: /* ! 571: * Iterate through all the threads and release them ! 572: */ ! 573: list = &task->thread_list; ! 574: thread = (thread_t) queue_first(list); ! 575: while (!queue_end(list, (queue_entry_t) thread)) { ! 576: next = (thread_t) queue_next(&thread->thread_list); ! 577: thread_release(thread); ! 578: thread = next; ! 579: } ! 580: task_unlock(task); ! 581: return KERN_SUCCESS; ! 582: } ! 583: ! 584: kern_return_t task_threads( ! 585: task_t task, ! 586: thread_array_t *thread_list, ! 587: natural_t *count) ! 588: { ! 589: unsigned int actual; /* this many threads */ ! 590: thread_t thread; ! 591: thread_t *threads; ! 592: int i; ! 593: ! 594: vm_size_t size, size_needed; ! 595: vm_offset_t addr; ! 596: ! 597: if (task == TASK_NULL) ! 598: return KERN_INVALID_ARGUMENT; ! 599: ! 600: size = 0; addr = 0; ! 601: ! 602: for (;;) { ! 603: task_lock(task); ! 604: if (!task->active) { ! 605: task_unlock(task); ! 606: return KERN_FAILURE; ! 607: } ! 608: ! 609: actual = task->thread_count; ! 610: ! 611: /* do we have the memory we need? */ ! 612: ! 613: size_needed = actual * sizeof(mach_port_t); ! 614: if (size_needed <= size) ! 615: break; ! 616: ! 617: /* unlock the task and allocate more memory */ ! 618: task_unlock(task); ! 619: ! 620: if (size != 0) ! 621: kfree(addr, size); ! 622: ! 623: assert(size_needed > 0); ! 624: size = size_needed; ! 625: ! 626: addr = kalloc(size); ! 627: if (addr == 0) ! 628: return KERN_RESOURCE_SHORTAGE; ! 629: } ! 630: ! 631: /* OK, have memory and the task is locked & active */ ! 632: ! 633: threads = (thread_t *) addr; ! 634: ! 635: for (i = 0, thread = (thread_t) queue_first(&task->thread_list); ! 636: i < actual; ! 637: i++, thread = (thread_t) queue_next(&thread->thread_list)) { ! 638: /* take ref for convert_thread_to_port */ ! 639: thread_reference(thread); ! 640: threads[i] = thread; ! 641: } ! 642: assert(queue_end(&task->thread_list, (queue_entry_t) thread)); ! 643: ! 644: /* can unlock task now that we've got the thread refs */ ! 645: task_unlock(task); ! 646: ! 647: if (actual == 0) { ! 648: /* no threads, so return null pointer and deallocate memory */ ! 649: ! 650: *thread_list = 0; ! 651: *count = 0; ! 652: ! 653: if (size != 0) ! 654: kfree(addr, size); ! 655: } else { ! 656: /* if we allocated too much, must copy */ ! 657: ! 658: if (size_needed < size) { ! 659: vm_offset_t newaddr; ! 660: ! 661: newaddr = kalloc(size_needed); ! 662: if (newaddr == 0) { ! 663: for (i = 0; i < actual; i++) ! 664: thread_deallocate(threads[i]); ! 665: kfree(addr, size); ! 666: return KERN_RESOURCE_SHORTAGE; ! 667: } ! 668: ! 669: bcopy((char *) addr, (char *) newaddr, size_needed); ! 670: kfree(addr, size); ! 671: threads = (thread_t *) newaddr; ! 672: } ! 673: ! 674: *thread_list = (mach_port_t *) threads; ! 675: *count = actual; ! 676: ! 677: /* do the conversion that Mig should handle */ ! 678: ! 679: for (i = 0; i < actual; i++) ! 680: ((ipc_port_t *) threads)[i] = ! 681: convert_thread_to_port(threads[i]); ! 682: } ! 683: ! 684: return KERN_SUCCESS; ! 685: } ! 686: ! 687: kern_return_t task_suspend( ! 688: register task_t task) ! 689: { ! 690: register boolean_t hold; ! 691: ! 692: if (task == TASK_NULL) ! 693: return KERN_INVALID_ARGUMENT; ! 694: ! 695: hold = FALSE; ! 696: task_lock(task); ! 697: if ((task->user_stop_count)++ == 0) ! 698: hold = TRUE; ! 699: task_unlock(task); ! 700: ! 701: /* ! 702: * If the stop count was positive, the task is ! 703: * already stopped and we can exit. ! 704: */ ! 705: if (!hold) { ! 706: return KERN_SUCCESS; ! 707: } ! 708: ! 709: /* ! 710: * Hold all of the threads in the task, and wait for ! 711: * them to stop. If the current thread is within ! 712: * this task, hold it separately so that all of the ! 713: * other threads can stop first. ! 714: */ ! 715: ! 716: if (task_hold(task) != KERN_SUCCESS) ! 717: return KERN_FAILURE; ! 718: ! 719: if (task_dowait(task, FALSE) != KERN_SUCCESS) ! 720: return KERN_FAILURE; ! 721: ! 722: if (current_task() == task) { ! 723: spl_t s; ! 724: ! 725: thread_hold(current_thread()); ! 726: /* ! 727: * We want to call thread_block on our way out, ! 728: * to stop running. ! 729: */ ! 730: s = splsched(); ! 731: ast_on(cpu_number(), AST_BLOCK); ! 732: (void) splx(s); ! 733: } ! 734: ! 735: return KERN_SUCCESS; ! 736: } ! 737: ! 738: kern_return_t task_resume( ! 739: register task_t task) ! 740: { ! 741: register boolean_t release; ! 742: ! 743: if (task == TASK_NULL) ! 744: return KERN_INVALID_ARGUMENT; ! 745: ! 746: release = FALSE; ! 747: task_lock(task); ! 748: if (task->user_stop_count > 0) { ! 749: if (--(task->user_stop_count) == 0) ! 750: release = TRUE; ! 751: } ! 752: else { ! 753: task_unlock(task); ! 754: return KERN_FAILURE; ! 755: } ! 756: task_unlock(task); ! 757: ! 758: /* ! 759: * Release the task if necessary. ! 760: */ ! 761: if (release) ! 762: return task_release(task); ! 763: ! 764: return KERN_SUCCESS; ! 765: } ! 766: ! 767: kern_return_t task_info( ! 768: task_t task, ! 769: int flavor, ! 770: task_info_t task_info_out, /* pointer to OUT array */ ! 771: natural_t *task_info_count) /* IN/OUT */ ! 772: { ! 773: vm_map_t map; ! 774: ! 775: if (task == TASK_NULL) ! 776: return KERN_INVALID_ARGUMENT; ! 777: ! 778: switch (flavor) { ! 779: case TASK_BASIC_INFO: ! 780: { ! 781: register task_basic_info_t basic_info; ! 782: ! 783: /* Allow *task_info_count to be two words smaller than ! 784: the usual amount, because creation_time is a new member ! 785: that some callers might not know about. */ ! 786: ! 787: if (*task_info_count < TASK_BASIC_INFO_COUNT - 2) { ! 788: return KERN_INVALID_ARGUMENT; ! 789: } ! 790: ! 791: basic_info = (task_basic_info_t) task_info_out; ! 792: ! 793: map = (task == kernel_task) ? kernel_map : task->map; ! 794: ! 795: basic_info->virtual_size = map->size; ! 796: basic_info->resident_size = pmap_resident_count(map->pmap) ! 797: * PAGE_SIZE; ! 798: ! 799: task_lock(task); ! 800: basic_info->base_priority = task->priority; ! 801: basic_info->suspend_count = task->user_stop_count; ! 802: basic_info->user_time.seconds ! 803: = task->total_user_time.seconds; ! 804: basic_info->user_time.microseconds ! 805: = task->total_user_time.microseconds; ! 806: basic_info->system_time.seconds ! 807: = task->total_system_time.seconds; ! 808: basic_info->system_time.microseconds ! 809: = task->total_system_time.microseconds; ! 810: basic_info->creation_time = task->creation_time; ! 811: task_unlock(task); ! 812: ! 813: if (*task_info_count > TASK_BASIC_INFO_COUNT) ! 814: *task_info_count = TASK_BASIC_INFO_COUNT; ! 815: break; ! 816: } ! 817: ! 818: case TASK_THREAD_TIMES_INFO: ! 819: { ! 820: register task_thread_times_info_t times_info; ! 821: register thread_t thread; ! 822: ! 823: if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) { ! 824: return KERN_INVALID_ARGUMENT; ! 825: } ! 826: ! 827: times_info = (task_thread_times_info_t) task_info_out; ! 828: times_info->user_time.seconds = 0; ! 829: times_info->user_time.microseconds = 0; ! 830: times_info->system_time.seconds = 0; ! 831: times_info->system_time.microseconds = 0; ! 832: ! 833: task_lock(task); ! 834: queue_iterate(&task->thread_list, thread, ! 835: thread_t, thread_list) ! 836: { ! 837: time_value_t user_time, system_time; ! 838: spl_t s; ! 839: ! 840: s = splsched(); ! 841: thread_lock(thread); ! 842: ! 843: thread_read_times(thread, &user_time, &system_time); ! 844: ! 845: thread_unlock(thread); ! 846: splx(s); ! 847: ! 848: time_value_add(×_info->user_time, &user_time); ! 849: time_value_add(×_info->system_time, &system_time); ! 850: } ! 851: task_unlock(task); ! 852: ! 853: *task_info_count = TASK_THREAD_TIMES_INFO_COUNT; ! 854: break; ! 855: } ! 856: ! 857: default: ! 858: return KERN_INVALID_ARGUMENT; ! 859: } ! 860: ! 861: return KERN_SUCCESS; ! 862: } ! 863: ! 864: #if MACH_HOST ! 865: /* ! 866: * task_assign: ! 867: * ! 868: * Change the assigned processor set for the task ! 869: */ ! 870: kern_return_t ! 871: task_assign( ! 872: task_t task, ! 873: processor_set_t new_pset, ! 874: boolean_t assign_threads) ! 875: { ! 876: kern_return_t ret = KERN_SUCCESS; ! 877: register thread_t thread, prev_thread; ! 878: register queue_head_t *list; ! 879: register processor_set_t pset; ! 880: ! 881: if (task == TASK_NULL || new_pset == PROCESSOR_SET_NULL) { ! 882: return KERN_INVALID_ARGUMENT; ! 883: } ! 884: ! 885: /* ! 886: * Freeze task`s assignment. Prelude to assigning ! 887: * task. Only one freeze may be held per task. ! 888: */ ! 889: ! 890: task_lock(task); ! 891: while (task->may_assign == FALSE) { ! 892: task->assign_active = TRUE; ! 893: assert_wait((event_t)&task->assign_active, TRUE); ! 894: task_unlock(task); ! 895: thread_block((void (*)()) 0); ! 896: task_lock(task); ! 897: } ! 898: ! 899: /* ! 900: * Avoid work if task already in this processor set. ! 901: */ ! 902: if (task->processor_set == new_pset) { ! 903: /* ! 904: * No need for task->assign_active wakeup: ! 905: * task->may_assign is still TRUE. ! 906: */ ! 907: task_unlock(task); ! 908: return KERN_SUCCESS; ! 909: } ! 910: ! 911: task->may_assign = FALSE; ! 912: task_unlock(task); ! 913: ! 914: /* ! 915: * Safe to get the task`s pset: it cannot change while ! 916: * task is frozen. ! 917: */ ! 918: pset = task->processor_set; ! 919: ! 920: /* ! 921: * Lock both psets now. Use ordering to avoid deadlock. ! 922: */ ! 923: Restart: ! 924: if ((vm_offset_t) pset < (vm_offset_t) new_pset) { ! 925: pset_lock(pset); ! 926: pset_lock(new_pset); ! 927: } ! 928: else { ! 929: pset_lock(new_pset); ! 930: pset_lock(pset); ! 931: } ! 932: ! 933: /* ! 934: * Check if new_pset is ok to assign to. If not, ! 935: * reassign to default_pset. ! 936: */ ! 937: if (!new_pset->active) { ! 938: pset_unlock(pset); ! 939: pset_unlock(new_pset); ! 940: new_pset = &default_pset; ! 941: goto Restart; ! 942: } ! 943: ! 944: pset_reference(new_pset); ! 945: ! 946: /* ! 947: * Now grab the task lock and move the task. ! 948: */ ! 949: ! 950: task_lock(task); ! 951: pset_remove_task(pset, task); ! 952: pset_add_task(new_pset, task); ! 953: ! 954: pset_unlock(pset); ! 955: pset_unlock(new_pset); ! 956: ! 957: if (assign_threads == FALSE) { ! 958: /* ! 959: * We leave existing threads at their ! 960: * old assignments. Unfreeze task`s ! 961: * assignment. ! 962: */ ! 963: task->may_assign = TRUE; ! 964: if (task->assign_active) { ! 965: task->assign_active = FALSE; ! 966: thread_wakeup((event_t) &task->assign_active); ! 967: } ! 968: task_unlock(task); ! 969: pset_deallocate(pset); ! 970: return KERN_SUCCESS; ! 971: } ! 972: ! 973: /* ! 974: * If current thread is in task, freeze its assignment. ! 975: */ ! 976: if (current_thread()->task == task) { ! 977: task_unlock(task); ! 978: thread_freeze(current_thread()); ! 979: task_lock(task); ! 980: } ! 981: ! 982: /* ! 983: * Iterate down the thread list reassigning all the threads. ! 984: * New threads pick up task's new processor set automatically. ! 985: * Do current thread last because new pset may be empty. ! 986: */ ! 987: list = &task->thread_list; ! 988: prev_thread = THREAD_NULL; ! 989: queue_iterate(list, thread, thread_t, thread_list) { ! 990: if (!(task->active)) { ! 991: ret = KERN_FAILURE; ! 992: break; ! 993: } ! 994: if (thread != current_thread()) { ! 995: thread_reference(thread); ! 996: task_unlock(task); ! 997: if (prev_thread != THREAD_NULL) ! 998: thread_deallocate(prev_thread); /* may block */ ! 999: thread_assign(thread,new_pset); /* may block */ ! 1000: prev_thread = thread; ! 1001: task_lock(task); ! 1002: } ! 1003: } ! 1004: ! 1005: /* ! 1006: * Done, wakeup anyone waiting for us. ! 1007: */ ! 1008: task->may_assign = TRUE; ! 1009: if (task->assign_active) { ! 1010: task->assign_active = FALSE; ! 1011: thread_wakeup((event_t)&task->assign_active); ! 1012: } ! 1013: task_unlock(task); ! 1014: if (prev_thread != THREAD_NULL) ! 1015: thread_deallocate(prev_thread); /* may block */ ! 1016: ! 1017: /* ! 1018: * Finish assignment of current thread. ! 1019: */ ! 1020: if (current_thread()->task == task) ! 1021: thread_doassign(current_thread(), new_pset, TRUE); ! 1022: ! 1023: pset_deallocate(pset); ! 1024: ! 1025: return ret; ! 1026: } ! 1027: #else /* MACH_HOST */ ! 1028: /* ! 1029: * task_assign: ! 1030: * ! 1031: * Change the assigned processor set for the task ! 1032: */ ! 1033: kern_return_t ! 1034: task_assign( ! 1035: task_t task, ! 1036: processor_set_t new_pset, ! 1037: boolean_t assign_threads) ! 1038: { ! 1039: return KERN_FAILURE; ! 1040: } ! 1041: #endif /* MACH_HOST */ ! 1042: ! 1043: ! 1044: /* ! 1045: * task_assign_default: ! 1046: * ! 1047: * Version of task_assign to assign to default processor set. ! 1048: */ ! 1049: kern_return_t ! 1050: task_assign_default( ! 1051: task_t task, ! 1052: boolean_t assign_threads) ! 1053: { ! 1054: return task_assign(task, &default_pset, assign_threads); ! 1055: } ! 1056: ! 1057: /* ! 1058: * task_get_assignment ! 1059: * ! 1060: * Return name of processor set that task is assigned to. ! 1061: */ ! 1062: kern_return_t task_get_assignment( ! 1063: task_t task, ! 1064: processor_set_t *pset) ! 1065: { ! 1066: if (!task->active) ! 1067: return KERN_FAILURE; ! 1068: ! 1069: *pset = task->processor_set; ! 1070: pset_reference(*pset); ! 1071: return KERN_SUCCESS; ! 1072: } ! 1073: ! 1074: /* ! 1075: * task_priority ! 1076: * ! 1077: * Set priority of task; used only for newly created threads. ! 1078: * Optionally change priorities of threads. ! 1079: */ ! 1080: kern_return_t ! 1081: task_priority( ! 1082: task_t task, ! 1083: int priority, ! 1084: boolean_t change_threads) ! 1085: { ! 1086: kern_return_t ret = KERN_SUCCESS; ! 1087: ! 1088: if (task == TASK_NULL || invalid_pri(priority)) ! 1089: return KERN_INVALID_ARGUMENT; ! 1090: ! 1091: task_lock(task); ! 1092: task->priority = priority; ! 1093: ! 1094: if (change_threads) { ! 1095: register thread_t thread; ! 1096: register queue_head_t *list; ! 1097: ! 1098: list = &task->thread_list; ! 1099: queue_iterate(list, thread, thread_t, thread_list) { ! 1100: if (thread_priority(thread, priority, FALSE) ! 1101: != KERN_SUCCESS) ! 1102: ret = KERN_FAILURE; ! 1103: } ! 1104: } ! 1105: ! 1106: task_unlock(task); ! 1107: return ret; ! 1108: } ! 1109: ! 1110: /* ! 1111: * task_collect_scan: ! 1112: * ! 1113: * Attempt to free resources owned by tasks. ! 1114: */ ! 1115: ! 1116: void task_collect_scan(void) ! 1117: { ! 1118: register task_t task, prev_task; ! 1119: processor_set_t pset, prev_pset; ! 1120: ! 1121: prev_task = TASK_NULL; ! 1122: prev_pset = PROCESSOR_SET_NULL; ! 1123: ! 1124: simple_lock(&all_psets_lock); ! 1125: queue_iterate(&all_psets, pset, processor_set_t, all_psets) { ! 1126: pset_lock(pset); ! 1127: queue_iterate(&pset->tasks, task, task_t, pset_tasks) { ! 1128: task_reference(task); ! 1129: pset_reference(pset); ! 1130: pset_unlock(pset); ! 1131: simple_unlock(&all_psets_lock); ! 1132: ! 1133: machine_task_collect (task); ! 1134: pmap_collect(task->map->pmap); ! 1135: ! 1136: if (prev_task != TASK_NULL) ! 1137: task_deallocate(prev_task); ! 1138: prev_task = task; ! 1139: ! 1140: if (prev_pset != PROCESSOR_SET_NULL) ! 1141: pset_deallocate(prev_pset); ! 1142: prev_pset = pset; ! 1143: ! 1144: simple_lock(&all_psets_lock); ! 1145: pset_lock(pset); ! 1146: } ! 1147: pset_unlock(pset); ! 1148: } ! 1149: simple_unlock(&all_psets_lock); ! 1150: ! 1151: if (prev_task != TASK_NULL) ! 1152: task_deallocate(prev_task); ! 1153: if (prev_pset != PROCESSOR_SET_NULL) ! 1154: pset_deallocate(prev_pset); ! 1155: } ! 1156: ! 1157: boolean_t task_collect_allowed = TRUE; ! 1158: unsigned task_collect_last_tick = 0; ! 1159: unsigned task_collect_max_rate = 0; /* in ticks */ ! 1160: ! 1161: /* ! 1162: * consider_task_collect: ! 1163: * ! 1164: * Called by the pageout daemon when the system needs more free pages. ! 1165: */ ! 1166: ! 1167: void consider_task_collect(void) ! 1168: { ! 1169: /* ! 1170: * By default, don't attempt task collection more frequently ! 1171: * than once a second. ! 1172: */ ! 1173: ! 1174: if (task_collect_max_rate == 0) ! 1175: task_collect_max_rate = hz; ! 1176: ! 1177: if (task_collect_allowed && ! 1178: (sched_tick > (task_collect_last_tick + task_collect_max_rate))) { ! 1179: task_collect_last_tick = sched_tick; ! 1180: task_collect_scan(); ! 1181: } ! 1182: } ! 1183: ! 1184: kern_return_t ! 1185: task_ras_control( ! 1186: task_t task, ! 1187: vm_offset_t pc, ! 1188: vm_offset_t endpc, ! 1189: int flavor) ! 1190: { ! 1191: kern_return_t ret = KERN_FAILURE; ! 1192: ! 1193: #if FAST_TAS ! 1194: int i; ! 1195: ! 1196: ret = KERN_SUCCESS; ! 1197: task_lock(task); ! 1198: switch (flavor) { ! 1199: case TASK_RAS_CONTROL_PURGE_ALL: /* remove all RAS */ ! 1200: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) { ! 1201: task->fast_tas_base[i] = task->fast_tas_end[i] = 0; ! 1202: } ! 1203: break; ! 1204: case TASK_RAS_CONTROL_PURGE_ONE: /* remove this RAS, collapse remaining */ ! 1205: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) { ! 1206: if ( (task->fast_tas_base[i] == pc) ! 1207: && (task->fast_tas_end[i] == endpc)) { ! 1208: while (i < TASK_FAST_TAS_NRAS-1) { ! 1209: task->fast_tas_base[i] = task->fast_tas_base[i+1]; ! 1210: task->fast_tas_end[i] = task->fast_tas_end[i+1]; ! 1211: i++; ! 1212: } ! 1213: task->fast_tas_base[TASK_FAST_TAS_NRAS-1] = 0; ! 1214: task->fast_tas_end[TASK_FAST_TAS_NRAS-1] = 0; ! 1215: break; ! 1216: } ! 1217: } ! 1218: if (i == TASK_FAST_TAS_NRAS) { ! 1219: ret = KERN_INVALID_ADDRESS; ! 1220: } ! 1221: break; ! 1222: case TASK_RAS_CONTROL_PURGE_ALL_AND_INSTALL_ONE: ! 1223: /* remove all RAS an install this RAS */ ! 1224: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) { ! 1225: task->fast_tas_base[i] = task->fast_tas_end[i] = 0; ! 1226: } ! 1227: /* FALL THROUGH */ ! 1228: case TASK_RAS_CONTROL_INSTALL_ONE: /* install this RAS */ ! 1229: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) { ! 1230: if ( (task->fast_tas_base[i] == pc) ! 1231: && (task->fast_tas_end[i] == endpc)) { ! 1232: /* already installed */ ! 1233: break; ! 1234: } ! 1235: if ((task->fast_tas_base[i] == 0) && (task->fast_tas_end[i] == 0)){ ! 1236: task->fast_tas_base[i] = pc; ! 1237: task->fast_tas_end[i] = endpc; ! 1238: break; ! 1239: } ! 1240: } ! 1241: if (i == TASK_FAST_TAS_NRAS) { ! 1242: ret = KERN_RESOURCE_SHORTAGE; ! 1243: } ! 1244: break; ! 1245: default: ret = KERN_INVALID_VALUE; ! 1246: break; ! 1247: } ! 1248: task_unlock(task); ! 1249: #endif ! 1250: return ret; ! 1251: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.