|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1993-1988 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: * File: kern/task.c ! 52: * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub, ! 53: * David Black ! 54: * ! 55: * Task management primitives implementation. ! 56: */ ! 57: ! 58: #include <mach_host.h> ! 59: #include <norma_task.h> ! 60: ! 61: #include <mach/machine/vm_types.h> ! 62: #include <mach/vm_param.h> ! 63: #include <mach/task_info.h> ! 64: #include <mach/task_special_ports.h> ! 65: #include <ipc/ipc_space.h> ! 66: #include <kern/mach_param.h> ! 67: #include <kern/task.h> ! 68: #include <kern/thread.h> ! 69: #include <kern/zalloc.h> ! 70: #include <kern/kalloc.h> ! 71: #include <kern/processor.h> ! 72: #include <kern/sched_prim.h> /* for thread_wakeup */ ! 73: #include <kern/ipc_tt.h> ! 74: #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */ ! 75: ! 76: #if NORMA_TASK ! 77: #define task_create task_create_local ! 78: #endif /* NORMA_TASK */ ! 79: ! 80: task_t kernel_task = TASK_NULL; ! 81: zone_t task_zone; ! 82: ! 83: extern zone_t u_task_zone; /* UNIX */ ! 84: ! 85: void task_init(void) ! 86: { ! 87: task_zone = zinit( ! 88: sizeof(struct task), ! 89: TASK_MAX * sizeof(struct task), ! 90: TASK_CHUNK * sizeof(struct task), ! 91: FALSE, "tasks"); ! 92: ! 93: /* ! 94: * Create the kernel task as the first task. ! 95: * Task_create must assign to kernel_task as a side effect, ! 96: * for other initialization. (:-() ! 97: */ ! 98: (void) task_create(TASK_NULL, FALSE, &kernel_task); ! 99: ! 100: kernel_task->kernel_privilege = TRUE; ! 101: kernel_task->kernel_vm_space = TRUE; ! 102: } ! 103: ! 104: /* ! 105: * Create a task running in the kernel address space. It may ! 106: * have its own map of size mem_size (if 0, it uses the kernel map), ! 107: * and may have ipc privileges. ! 108: */ ! 109: task_t kernel_task_create( ! 110: task_t parent_task, ! 111: vm_size_t map_size) ! 112: { ! 113: task_t new_task; ! 114: vm_offset_t min, max; ! 115: ! 116: /* ! 117: * Create the task. ! 118: */ ! 119: (void) task_create(parent_task, FALSE, &new_task); ! 120: task_deallocate(new_task); // extra ref for convert_task_to_port() ! 121: ! 122: /* ! 123: * Task_create creates the task with a user-space map. ! 124: * Remove the map and replace it with the kernel map ! 125: * or a submap of the kernel map. ! 126: */ ! 127: vm_map_deallocate(new_task->map); ! 128: if (map_size == 0) ! 129: new_task->map = kernel_map; ! 130: else ! 131: new_task->map = kmem_suballoc(kernel_map, &min, &max, ! 132: map_size, FALSE); ! 133: ! 134: new_task->kernel_vm_space = TRUE; ! 135: ! 136: return new_task; ! 137: } ! 138: ! 139: kern_return_t task_create( ! 140: task_t parent_task, ! 141: boolean_t inherit_memory, ! 142: task_t *child_task) /* OUT */ ! 143: { ! 144: register task_t new_task; ! 145: register processor_set_t pset; ! 146: int i; ! 147: ! 148: new_task = (task_t) zalloc(task_zone); ! 149: if (new_task == TASK_NULL) { ! 150: panic("task_create: no memory for task structure"); ! 151: } ! 152: ! 153: /* one ref for just being alive; one for our caller */ ! 154: new_task->ref_count = 2; ! 155: ! 156: if (child_task == &kernel_task) { ! 157: new_task->map = kernel_map; ! 158: } else if (inherit_memory) { ! 159: new_task->map = vm_map_fork(parent_task->map); ! 160: } else { ! 161: new_task->map = vm_map_create(pmap_create(0), ! 162: round_page(VM_MIN_ADDRESS), ! 163: trunc_page(VM_MAX_ADDRESS), TRUE); ! 164: } ! 165: ! 166: simple_lock_init(&new_task->lock); ! 167: queue_init(&new_task->thread_list); ! 168: simple_lock_init(&new_task->thread_list_lock); ! 169: new_task->suspend_count = 0; ! 170: new_task->active = TRUE; ! 171: new_task->user_stop_count = 0; ! 172: new_task->thread_count = 0; ! 173: ! 174: new_task->pcb_common = 0; ! 175: pcb_common_init(new_task); ! 176: ! 177: new_task->proc = 0; ! 178: ! 179: new_task->kernel_vm_space = FALSE; ! 180: ! 181: ipc_task_init(new_task, parent_task); ! 182: ! 183: new_task->total_user_time.seconds = 0; ! 184: new_task->total_user_time.microseconds = 0; ! 185: new_task->total_system_time.seconds = 0; ! 186: new_task->total_system_time.microseconds = 0; ! 187: ! 188: if (parent_task != TASK_NULL) { ! 189: new_task->kernel_privilege = parent_task->kernel_privilege; ! 190: task_lock(parent_task); ! 191: pset = parent_task->processor_set; ! 192: if (!pset->active) ! 193: pset = &default_pset; ! 194: pset_reference(pset); ! 195: new_task->priority = parent_task->priority; ! 196: task_unlock(parent_task); ! 197: } ! 198: else { ! 199: new_task->kernel_privilege = FALSE; ! 200: pset = &default_pset; ! 201: pset_reference(pset); ! 202: new_task->priority = BASEPRI_USER; ! 203: } ! 204: pset_lock(pset); ! 205: pset_add_task(pset, new_task); ! 206: pset_unlock(pset); ! 207: ! 208: new_task->may_assign = TRUE; ! 209: new_task->assign_active = FALSE; ! 210: ! 211: ipc_task_enable(new_task); ! 212: ! 213: #if NORMA_TASK ! 214: new_task->child_node = -1; ! 215: #endif /* NORMA_TASK */ ! 216: ! 217: *child_task = new_task; ! 218: return KERN_SUCCESS; ! 219: } ! 220: ! 221: /* ! 222: * task_deallocate: ! 223: * ! 224: * Give up a reference to the specified task and destroy it if there ! 225: * are no other references left. It is assumed that the current thread ! 226: * is never in this task. ! 227: */ ! 228: void task_deallocate( ! 229: register task_t task) ! 230: { ! 231: register int c; ! 232: register processor_set_t pset; ! 233: ! 234: if (task == TASK_NULL) ! 235: return; ! 236: ! 237: task_lock(task); ! 238: c = --(task->ref_count); ! 239: task_unlock(task); ! 240: if (c != 0) ! 241: return; ! 242: ! 243: #if NORMA_TASK ! 244: if (task->map == VM_MAP_NULL) { ! 245: /* norma placeholder task */ ! 246: zfree(task_zone, (vm_offset_t) task); ! 247: return; ! 248: } ! 249: #endif /* NORMA_TASK */ ! 250: ! 251: pset = task->processor_set; ! 252: pset_lock(pset); ! 253: pset_remove_task(pset,task); ! 254: pset_unlock(pset); ! 255: pset_deallocate(pset); ! 256: vm_map_deallocate(task->map); ! 257: is_release(task->itk_space); ! 258: pcb_common_terminate(task); ! 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: int s; ! 286: ! 287: if (task == TASK_NULL) ! 288: return KERN_INVALID_ARGUMENT; ! 289: ! 290: /* Disallow termination of U**X proc tasks */ ! 291: if (task->proc) ! 292: return KERN_FAILURE; ! 293: ! 294: list = &task->thread_list; ! 295: cur_task = current_task(); ! 296: cur_thread = current_thread(); ! 297: ! 298: /* ! 299: * Deactivate task so that it can't be terminated again, ! 300: * and so lengthy operations in progress will abort. ! 301: * ! 302: * If the current thread is in this task, remove it from ! 303: * the task's thread list to keep the thread-termination ! 304: * loop simple. ! 305: */ ! 306: if (task == cur_task) { ! 307: task_lock(task); ! 308: if (!task->active) { ! 309: /* ! 310: * Task is already being terminated. ! 311: */ ! 312: task_unlock(task); ! 313: return KERN_FAILURE; ! 314: } ! 315: /* ! 316: * Make sure current thread is not being terminated. ! 317: */ ! 318: s = splsched(); ! 319: simple_lock(&task->thread_list_lock); ! 320: thread_lock(cur_thread); ! 321: if (!cur_thread->active) { ! 322: thread_unlock(cur_thread); ! 323: simple_unlock(&task->thread_list_lock); ! 324: (void) splx(s); ! 325: task_unlock(task); ! 326: thread_terminate(cur_thread); ! 327: return KERN_FAILURE; ! 328: } ! 329: task->active = FALSE; ! 330: queue_remove(list, cur_thread, thread_t, thread_list); ! 331: thread_unlock(cur_thread); ! 332: simple_unlock(&task->thread_list_lock); ! 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_with_continuation((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: simple_lock(&task->thread_list_lock); ! 446: queue_enter(list, cur_thread, thread_t, thread_list); ! 447: simple_unlock(&task->thread_list_lock); ! 448: (void) splx(s); ! 449: task_unlock(task); ! 450: (void) thread_terminate(cur_thread); ! 451: } ! 452: ! 453: return KERN_SUCCESS; ! 454: } ! 455: ! 456: /* ! 457: * task_hold: ! 458: * ! 459: * Suspend execution of the specified task. ! 460: * This is a recursive-style suspension of the task, a count of ! 461: * suspends is maintained. ! 462: */ ! 463: kern_return_t task_hold( ! 464: register task_t task) ! 465: { ! 466: register queue_head_t *list; ! 467: register thread_t thread, cur_thread; ! 468: ! 469: cur_thread = current_thread(); ! 470: ! 471: task_lock(task); ! 472: if (!task->active) { ! 473: task_unlock(task); ! 474: return KERN_FAILURE; ! 475: } ! 476: ! 477: task->suspend_count++; ! 478: ! 479: /* ! 480: * Iterate through all the threads and hold them. ! 481: * Do not hold the current thread if it is within the ! 482: * task. ! 483: */ ! 484: list = &task->thread_list; ! 485: queue_iterate(list, thread, thread_t, thread_list) { ! 486: if (thread != cur_thread) ! 487: thread_hold(thread); ! 488: } ! 489: task_unlock(task); ! 490: return KERN_SUCCESS; ! 491: } ! 492: ! 493: /* ! 494: * task_dowait: ! 495: * ! 496: * Wait until the task has really been suspended (all of the threads ! 497: * are stopped). Skip the current thread if it is within the task. ! 498: * ! 499: * If task is deactivated while waiting, return a failure code unless ! 500: * must_wait is true. ! 501: */ ! 502: kern_return_t task_dowait( ! 503: register task_t task, ! 504: boolean_t must_wait) ! 505: { ! 506: register queue_head_t *list; ! 507: register thread_t thread, cur_thread, prev_thread; ! 508: register kern_return_t ret = KERN_SUCCESS; ! 509: ! 510: /* ! 511: * Iterate through all the threads. ! 512: * While waiting for each thread, we gain a reference to it ! 513: * to prevent it from going away on us. This guarantees ! 514: * that the "next" thread in the list will be a valid thread. ! 515: * ! 516: * We depend on the fact that if threads are created while ! 517: * we are looping through the threads, they will be held ! 518: * automatically. We don't care about threads that get ! 519: * deallocated along the way (the reference prevents it ! 520: * from happening to the thread we are working with). ! 521: * ! 522: * If the current thread is in the affected task, it is skipped. ! 523: * ! 524: * If the task is deactivated before we're done, and we don't ! 525: * have to wait for it (must_wait is FALSE), just bail out. ! 526: */ ! 527: cur_thread = current_thread(); ! 528: ! 529: list = &task->thread_list; ! 530: prev_thread = THREAD_NULL; ! 531: task_lock(task); ! 532: queue_iterate(list, thread, thread_t, thread_list) { ! 533: if (!(task->active) && !(must_wait)) { ! 534: ret = KERN_FAILURE; ! 535: break; ! 536: } ! 537: if (thread != cur_thread) { ! 538: thread_reference(thread); ! 539: task_unlock(task); ! 540: if (prev_thread != THREAD_NULL) ! 541: thread_deallocate(prev_thread); ! 542: /* may block */ ! 543: (void) thread_dowait(thread, TRUE); /* may block */ ! 544: prev_thread = thread; ! 545: task_lock(task); ! 546: } ! 547: } ! 548: task_unlock(task); ! 549: if (prev_thread != THREAD_NULL) ! 550: thread_deallocate(prev_thread); /* may block */ ! 551: return ret; ! 552: } ! 553: ! 554: kern_return_t task_release( ! 555: register task_t task) ! 556: { ! 557: register queue_head_t *list; ! 558: register thread_t thread, next; ! 559: ! 560: task_lock(task); ! 561: if (!task->active) { ! 562: task_unlock(task); ! 563: return KERN_FAILURE; ! 564: } ! 565: ! 566: task->suspend_count--; ! 567: ! 568: /* ! 569: * Iterate through all the threads and release them ! 570: */ ! 571: list = &task->thread_list; ! 572: thread = (thread_t) queue_first(list); ! 573: while (!queue_end(list, (queue_entry_t) thread)) { ! 574: next = (thread_t) queue_next(&thread->thread_list); ! 575: thread_release(thread); ! 576: thread = next; ! 577: } ! 578: task_unlock(task); ! 579: return KERN_SUCCESS; ! 580: } ! 581: ! 582: /* ! 583: * task_halt: ! 584: * ! 585: * Halt all threads in the task. Do not halt the current thread if ! 586: * it is within the task. ! 587: * ! 588: * Only called from exit(). ! 589: */ ! 590: kern_return_t task_halt(task) ! 591: register task_t task; ! 592: { ! 593: register queue_head_t *list; ! 594: register thread_t thread, cur_thread, prev_thread; ! 595: register kern_return_t ret = KERN_SUCCESS; ! 596: ! 597: /* ! 598: * Iterate through all the threads. ! 599: * While waiting for each thread, we gain a reference to it ! 600: * to prevent it from going away on us. This guarantees ! 601: * that the "next" thread in the list will be a valid thread. ! 602: * ! 603: * If the current thread is in the affected task, it is skipped. ! 604: */ ! 605: cur_thread = current_thread(); ! 606: ! 607: list = &task->thread_list; ! 608: prev_thread = THREAD_NULL; ! 609: task_lock(task); ! 610: thread = (thread_t) queue_first(list); ! 611: while (!queue_end(list, (queue_entry_t) thread)) { ! 612: if (thread != cur_thread) { ! 613: thread_reference(thread); ! 614: task_unlock(task); ! 615: if (prev_thread != THREAD_NULL) ! 616: thread_deallocate(prev_thread); /* may block */ ! 617: #if MACH_HOST ! 618: thread_freeze(thread); ! 619: if (thread->processor_set != &default_pset) ! 620: thread_doassign(thread, &default_pset, FALSE); ! 621: #endif MACH_HOST ! 622: thread_halt(thread, TRUE); /* may block */ ! 623: #if MACH_HOST ! 624: thread_unfreeze(thread); ! 625: #endif MACH_HOST ! 626: prev_thread = thread; ! 627: task_lock(task); ! 628: } ! 629: thread = (thread_t) queue_next(&thread->thread_list); ! 630: } ! 631: task_unlock(task); ! 632: if (prev_thread != THREAD_NULL) ! 633: thread_deallocate(prev_thread); /* may block */ ! 634: return(ret); ! 635: } ! 636: ! 637: kern_return_t task_threads( ! 638: task_t task, ! 639: thread_array_t *thread_list, ! 640: natural_t *count) ! 641: { ! 642: unsigned int actual; /* this many threads */ ! 643: thread_t thread; ! 644: thread_t *threads; ! 645: int i; ! 646: ! 647: vm_size_t size, size_needed; ! 648: vm_offset_t addr; ! 649: ! 650: if (task == TASK_NULL) ! 651: return KERN_INVALID_ARGUMENT; ! 652: ! 653: size = 0; addr = 0; ! 654: ! 655: for (;;) { ! 656: task_lock(task); ! 657: if (!task->active) { ! 658: task_unlock(task); ! 659: return KERN_FAILURE; ! 660: } ! 661: ! 662: actual = task->thread_count; ! 663: ! 664: /* do we have the memory we need? */ ! 665: ! 666: size_needed = actual * sizeof(mach_port_t); ! 667: if (size_needed <= size) ! 668: break; ! 669: ! 670: /* unlock the task and allocate more memory */ ! 671: task_unlock(task); ! 672: ! 673: if (size != 0) ! 674: kfree(addr, size); ! 675: ! 676: assert(size_needed > 0); ! 677: size = size_needed; ! 678: ! 679: addr = kalloc(size); ! 680: if (addr == 0) ! 681: return KERN_RESOURCE_SHORTAGE; ! 682: } ! 683: ! 684: /* OK, have memory and the task is locked & active */ ! 685: ! 686: threads = (thread_t *) addr; ! 687: ! 688: for (i = 0, thread = (thread_t) queue_first(&task->thread_list); ! 689: i < actual; ! 690: i++, thread = (thread_t) queue_next(&thread->thread_list)) { ! 691: /* take ref for convert_thread_to_port */ ! 692: thread_reference(thread); ! 693: threads[i] = thread; ! 694: } ! 695: assert(queue_end(&task->thread_list, (queue_entry_t) thread)); ! 696: ! 697: /* can unlock task now that we've got the thread refs */ ! 698: task_unlock(task); ! 699: ! 700: if (actual == 0) { ! 701: /* no threads, so return null pointer and deallocate memory */ ! 702: ! 703: *thread_list = 0; ! 704: *count = 0; ! 705: ! 706: if (size != 0) ! 707: kfree(addr, size); ! 708: } else { ! 709: /* if we allocated too much, must copy */ ! 710: ! 711: if (size_needed < size) { ! 712: vm_offset_t newaddr; ! 713: ! 714: newaddr = kalloc(size_needed); ! 715: if (newaddr == 0) { ! 716: for (i = 0; i < actual; i++) ! 717: thread_deallocate(threads[i]); ! 718: kfree(addr, size); ! 719: return KERN_RESOURCE_SHORTAGE; ! 720: } ! 721: ! 722: bcopy((char *) addr, (char *) newaddr, size_needed); ! 723: kfree(addr, size); ! 724: threads = (thread_t *) newaddr; ! 725: } ! 726: ! 727: *thread_list = (mach_port_t *) threads; ! 728: *count = actual; ! 729: ! 730: /* do the conversion that Mig should handle */ ! 731: ! 732: for (i = 0; i < actual; i++) ! 733: ((ipc_port_t *) threads)[i] = ! 734: convert_thread_to_port(threads[i]); ! 735: } ! 736: ! 737: return KERN_SUCCESS; ! 738: } ! 739: ! 740: kern_return_t task_suspend( ! 741: register task_t task) ! 742: { ! 743: register boolean_t hold; ! 744: ! 745: if (task == TASK_NULL) ! 746: return KERN_INVALID_ARGUMENT; ! 747: ! 748: hold = FALSE; ! 749: task_lock(task); ! 750: if ((task->user_stop_count)++ == 0) ! 751: hold = TRUE; ! 752: task_unlock(task); ! 753: ! 754: /* ! 755: * If the stop count was positive, the task is ! 756: * already stopped and we can exit. ! 757: */ ! 758: if (!hold) { ! 759: return KERN_SUCCESS; ! 760: } ! 761: ! 762: /* ! 763: * Hold all of the threads in the task, and wait for ! 764: * them to stop. If the current thread is within ! 765: * this task, hold it separately so that all of the ! 766: * other threads can stop first. ! 767: */ ! 768: ! 769: if (task_hold(task) != KERN_SUCCESS) ! 770: return KERN_FAILURE; ! 771: ! 772: if (task_dowait(task, FALSE) != KERN_SUCCESS) ! 773: return KERN_FAILURE; ! 774: ! 775: if (current_task() == task) { ! 776: int s; ! 777: ! 778: thread_hold(current_thread()); ! 779: /* ! 780: * We want to call thread_block on our way out, ! 781: * to stop running. ! 782: */ ! 783: s = splsched(); ! 784: ast_on(cpu_number(), AST_BLOCK); ! 785: (void) splx(s); ! 786: } ! 787: ! 788: return KERN_SUCCESS; ! 789: } ! 790: ! 791: kern_return_t task_resume( ! 792: register task_t task) ! 793: { ! 794: register boolean_t release; ! 795: ! 796: if (task == TASK_NULL) ! 797: return KERN_INVALID_ARGUMENT; ! 798: ! 799: release = FALSE; ! 800: task_lock(task); ! 801: if (task->user_stop_count > 0) { ! 802: if (--(task->user_stop_count) == 0) ! 803: release = TRUE; ! 804: } ! 805: else { ! 806: task_unlock(task); ! 807: return KERN_FAILURE; ! 808: } ! 809: task_unlock(task); ! 810: ! 811: /* ! 812: * Release the task if necessary. ! 813: */ ! 814: if (release) ! 815: return task_release(task); ! 816: ! 817: return KERN_SUCCESS; ! 818: } ! 819: ! 820: kern_return_t task_info( ! 821: task_t task, ! 822: int flavor, ! 823: task_info_t task_info_out, /* pointer to OUT array */ ! 824: natural_t *task_info_count) /* IN/OUT */ ! 825: { ! 826: vm_map_t map; ! 827: ! 828: if (task == TASK_NULL) ! 829: return KERN_INVALID_ARGUMENT; ! 830: ! 831: switch (flavor) { ! 832: case TASK_BASIC_INFO: ! 833: { ! 834: register task_basic_info_t basic_info; ! 835: ! 836: if (*task_info_count < TASK_BASIC_INFO_COUNT) { ! 837: return KERN_INVALID_ARGUMENT; ! 838: } ! 839: ! 840: basic_info = (task_basic_info_t) task_info_out; ! 841: ! 842: map = (task == kernel_task) ? kernel_map : task->map; ! 843: ! 844: basic_info->virtual_size = map->size; ! 845: basic_info->resident_size = pmap_resident_count(map->pmap) ! 846: * PAGE_SIZE; ! 847: ! 848: task_lock(task); ! 849: basic_info->base_priority = task->priority; ! 850: basic_info->suspend_count = task->user_stop_count; ! 851: basic_info->user_time.seconds ! 852: = task->total_user_time.seconds; ! 853: basic_info->user_time.microseconds ! 854: = task->total_user_time.microseconds; ! 855: basic_info->system_time.seconds ! 856: = task->total_system_time.seconds; ! 857: basic_info->system_time.microseconds ! 858: = task->total_system_time.microseconds; ! 859: task_unlock(task); ! 860: ! 861: *task_info_count = TASK_BASIC_INFO_COUNT; ! 862: break; ! 863: } ! 864: ! 865: case TASK_THREAD_TIMES_INFO: ! 866: { ! 867: register task_thread_times_info_t times_info; ! 868: register thread_t thread; ! 869: ! 870: if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) { ! 871: return KERN_INVALID_ARGUMENT; ! 872: } ! 873: ! 874: times_info = (task_thread_times_info_t) task_info_out; ! 875: times_info->user_time.seconds = 0; ! 876: times_info->user_time.microseconds = 0; ! 877: times_info->system_time.seconds = 0; ! 878: times_info->system_time.microseconds = 0; ! 879: ! 880: task_lock(task); ! 881: queue_iterate(&task->thread_list, thread, ! 882: thread_t, thread_list) ! 883: { ! 884: time_value_t user_time, system_time; ! 885: int s; ! 886: ! 887: s = splsched(); ! 888: thread_lock(thread); ! 889: ! 890: thread_read_times(thread, &user_time, &system_time); ! 891: ! 892: thread_unlock(thread); ! 893: splx(s); ! 894: ! 895: time_value_add(×_info->user_time, &user_time); ! 896: time_value_add(×_info->system_time, &system_time); ! 897: } ! 898: task_unlock(task); ! 899: ! 900: *task_info_count = TASK_THREAD_TIMES_INFO_COUNT; ! 901: break; ! 902: } ! 903: ! 904: default: ! 905: return KERN_INVALID_ARGUMENT; ! 906: } ! 907: ! 908: return KERN_SUCCESS; ! 909: } ! 910: ! 911: /* ! 912: * Special version of task_suspend that doesn't wait. ! 913: * Called only from interrupt level (U*X psignal). ! 914: * Will go away when signal code becomes sane. ! 915: */ ! 916: kern_return_t task_suspend_nowait(task) ! 917: register task_t task; ! 918: { ! 919: register boolean_t hold; ! 920: ! 921: if (task == TASK_NULL) ! 922: return(KERN_INVALID_ARGUMENT); ! 923: ! 924: hold = FALSE; ! 925: task_lock(task); ! 926: if ((task->user_stop_count)++ == 0) ! 927: hold = TRUE; ! 928: task_unlock(task); ! 929: ! 930: /* ! 931: * If the stop count was positive, the task is ! 932: * already stopped and we can exit. ! 933: */ ! 934: if (!hold) { ! 935: return (KERN_SUCCESS); ! 936: } ! 937: ! 938: /* ! 939: * Hold all of the threads in the task. ! 940: * If the current thread is within ! 941: * this task, hold it separately so that all of the ! 942: * other threads can stop first. ! 943: */ ! 944: ! 945: if (task_hold(task) != KERN_SUCCESS) ! 946: return(KERN_FAILURE); ! 947: ! 948: if (current_task() == task) { ! 949: thread_hold(current_thread()); ! 950: } ! 951: ! 952: return(KERN_SUCCESS); ! 953: } ! 954: ! 955: #if MACH_HOST ! 956: /* ! 957: * task_assign: ! 958: * ! 959: * Change the assigned processor set for the task ! 960: */ ! 961: kern_return_t ! 962: task_assign( ! 963: task_t task, ! 964: processor_set_t new_pset, ! 965: boolean_t assign_threads) ! 966: { ! 967: kern_return_t ret = KERN_SUCCESS; ! 968: register thread_t thread, prev_thread; ! 969: register queue_head_t *list; ! 970: register processor_set_t pset; ! 971: ! 972: if (task == TASK_NULL || new_pset == PROCESSOR_SET_NULL) { ! 973: return KERN_INVALID_ARGUMENT; ! 974: } ! 975: ! 976: /* ! 977: * Freeze task`s assignment. Prelude to assigning ! 978: * task. Only one freeze may be held per task. ! 979: */ ! 980: ! 981: task_lock(task); ! 982: while (task->may_assign == FALSE) { ! 983: task->assign_active = TRUE; ! 984: assert_wait((event_t)&task->assign_active, TRUE); ! 985: task_unlock(task); ! 986: thread_block((void (*)()) 0); ! 987: task_lock(task); ! 988: } ! 989: ! 990: /* ! 991: * Avoid work if task already in this processor set. ! 992: */ ! 993: if (task->processor_set == new_pset) { ! 994: /* ! 995: * No need for task->assign_active wakeup: ! 996: * task->may_assign is still TRUE. ! 997: */ ! 998: task_unlock(task); ! 999: return KERN_SUCCESS; ! 1000: } ! 1001: ! 1002: task->may_assign = FALSE; ! 1003: task_unlock(task); ! 1004: ! 1005: /* ! 1006: * Safe to get the task`s pset: it cannot change while ! 1007: * task is frozen. ! 1008: */ ! 1009: pset = task->processor_set; ! 1010: ! 1011: /* ! 1012: * Lock both psets now. Use ordering to avoid deadlock. ! 1013: */ ! 1014: Restart: ! 1015: if ((vm_offset_t) pset < (vm_offset_t) new_pset) { ! 1016: pset_lock(pset); ! 1017: pset_lock(new_pset); ! 1018: } ! 1019: else { ! 1020: pset_lock(new_pset); ! 1021: pset_lock(pset); ! 1022: } ! 1023: ! 1024: /* ! 1025: * Check if new_pset is ok to assign to. If not, ! 1026: * reassign to default_pset. ! 1027: */ ! 1028: if (!new_pset->active) { ! 1029: pset_unlock(pset); ! 1030: pset_unlock(new_pset); ! 1031: new_pset = &default_pset; ! 1032: goto Restart; ! 1033: } ! 1034: ! 1035: pset_reference(new_pset); ! 1036: ! 1037: /* ! 1038: * Now grab the task lock and move the task. ! 1039: */ ! 1040: ! 1041: task_lock(task); ! 1042: pset_remove_task(pset, task); ! 1043: pset_add_task(new_pset, task); ! 1044: ! 1045: pset_unlock(pset); ! 1046: pset_unlock(new_pset); ! 1047: ! 1048: if (assign_threads == FALSE) { ! 1049: /* ! 1050: * We leave existing threads at their ! 1051: * old assignments. Unfreeze task`s ! 1052: * assignment. ! 1053: */ ! 1054: task->may_assign = TRUE; ! 1055: if (task->assign_active) { ! 1056: task->assign_active = FALSE; ! 1057: thread_wakeup((event_t) &task->assign_active); ! 1058: } ! 1059: task_unlock(task); ! 1060: pset_deallocate(pset); ! 1061: return KERN_SUCCESS; ! 1062: } ! 1063: ! 1064: /* ! 1065: * If current thread is in task, freeze its assignment. ! 1066: */ ! 1067: if (current_thread()->task == task) { ! 1068: task_unlock(task); ! 1069: thread_freeze(current_thread()); ! 1070: task_lock(task); ! 1071: } ! 1072: ! 1073: /* ! 1074: * Iterate down the thread list reassigning all the threads. ! 1075: * New threads pick up task's new processor set automatically. ! 1076: * Do current thread last because new pset may be empty. ! 1077: */ ! 1078: list = &task->thread_list; ! 1079: prev_thread = THREAD_NULL; ! 1080: queue_iterate(list, thread, thread_t, thread_list) { ! 1081: if (!(task->active)) { ! 1082: ret = KERN_FAILURE; ! 1083: break; ! 1084: } ! 1085: if (thread != current_thread()) { ! 1086: thread_reference(thread); ! 1087: task_unlock(task); ! 1088: if (prev_thread != THREAD_NULL) ! 1089: thread_deallocate(prev_thread); /* may block */ ! 1090: thread_assign(thread,new_pset); /* may block */ ! 1091: prev_thread = thread; ! 1092: task_lock(task); ! 1093: } ! 1094: } ! 1095: ! 1096: /* ! 1097: * Done, wakeup anyone waiting for us. ! 1098: */ ! 1099: task->may_assign = TRUE; ! 1100: if (task->assign_active) { ! 1101: task->assign_active = FALSE; ! 1102: thread_wakeup((event_t)&task->assign_active); ! 1103: } ! 1104: task_unlock(task); ! 1105: if (prev_thread != THREAD_NULL) ! 1106: thread_deallocate(prev_thread); /* may block */ ! 1107: ! 1108: /* ! 1109: * Finish assignment of current thread. ! 1110: */ ! 1111: if (current_thread()->task == task) ! 1112: thread_doassign(current_thread(), new_pset, TRUE); ! 1113: ! 1114: pset_deallocate(pset); ! 1115: ! 1116: return ret; ! 1117: } ! 1118: #else /* MACH_HOST */ ! 1119: /* ! 1120: * task_assign: ! 1121: * ! 1122: * Change the assigned processor set for the task ! 1123: */ ! 1124: kern_return_t ! 1125: task_assign( ! 1126: task_t task, ! 1127: processor_set_t new_pset, ! 1128: boolean_t assign_threads) ! 1129: { ! 1130: return KERN_FAILURE; ! 1131: } ! 1132: #endif /* MACH_HOST */ ! 1133: ! 1134: ! 1135: /* ! 1136: * task_assign_default: ! 1137: * ! 1138: * Version of task_assign to assign to default processor set. ! 1139: */ ! 1140: kern_return_t ! 1141: task_assign_default( ! 1142: task_t task, ! 1143: boolean_t assign_threads) ! 1144: { ! 1145: return task_assign(task, &default_pset, assign_threads); ! 1146: } ! 1147: ! 1148: /* ! 1149: * task_get_assignment ! 1150: * ! 1151: * Return name of processor set that task is assigned to. ! 1152: */ ! 1153: kern_return_t task_get_assignment( ! 1154: task_t task, ! 1155: processor_set_t *pset) ! 1156: { ! 1157: if (!task->active) ! 1158: return KERN_FAILURE; ! 1159: ! 1160: *pset = task->processor_set; ! 1161: pset_reference(*pset); ! 1162: return KERN_SUCCESS; ! 1163: } ! 1164: ! 1165: /* ! 1166: * task_priority ! 1167: * ! 1168: * Set priority of task; used only for newly created threads. ! 1169: * Optionally change priorities of threads. ! 1170: */ ! 1171: kern_return_t ! 1172: task_priority( ! 1173: task_t task, ! 1174: int priority, ! 1175: boolean_t change_threads) ! 1176: { ! 1177: kern_return_t ret = KERN_SUCCESS; ! 1178: ! 1179: if (task == TASK_NULL || invalid_pri(priority)) ! 1180: return KERN_INVALID_ARGUMENT; ! 1181: ! 1182: task_lock(task); ! 1183: task->priority = priority; ! 1184: ! 1185: if (change_threads) { ! 1186: register thread_t thread; ! 1187: register queue_head_t *list; ! 1188: ! 1189: list = &task->thread_list; ! 1190: queue_iterate(list, thread, thread_t, thread_list) { ! 1191: if (thread_priority(thread, priority, FALSE) ! 1192: != KERN_SUCCESS) ! 1193: ret = KERN_FAILURE; ! 1194: } ! 1195: } ! 1196: ! 1197: task_unlock(task); ! 1198: return ret; ! 1199: } ! 1200: ! 1201: task_t current_task_EXTERNAL() ! 1202: { ! 1203: return current_task(); ! 1204: } ! 1205: ! 1206: /* ! 1207: * Loadable servers need to be able to find their task map. ! 1208: */ ! 1209: vm_map_t current_map_EXTERNAL() ! 1210: { ! 1211: return current_task()->map; ! 1212: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.