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