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