|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_FREE_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989,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: * Copyright (c) 1993 The University of Utah and ! 59: * the Computer Systems Laboratory (CSL). All rights reserved. ! 60: * ! 61: * Permission to use, copy, modify and distribute this software and its ! 62: * documentation is hereby granted, provided that both the copyright ! 63: * notice and this permission notice appear in all copies of the ! 64: * software, derivative works or modified versions, and any portions ! 65: * thereof, and that both notices appear in supporting documentation. ! 66: * ! 67: * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS ! 68: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF ! 69: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 70: * ! 71: * CSL requests users of this software to return to [email protected] any ! 72: * improvements that they make and grant CSL redistribution rights. ! 73: * ! 74: */ ! 75: ! 76: #include <mach_kdb.h> ! 77: #include <mach_host.h> ! 78: #include <mach_prof.h> ! 79: #include <fast_tas.h> ! 80: #include <task_swapper.h> ! 81: #include <platforms.h> ! 82: ! 83: #include <mach/boolean.h> ! 84: #include <mach/machine/vm_types.h> ! 85: #include <mach/vm_param.h> ! 86: #include <mach/task_info.h> ! 87: #include <mach/task_special_ports.h> ! 88: #include <mach/mach_types.h> ! 89: #include <mach/machine/rpc.h> ! 90: #include <ipc/ipc_space.h> ! 91: #include <ipc/ipc_entry.h> ! 92: #include <kern/mach_param.h> ! 93: #include <kern/misc_protos.h> ! 94: #include <kern/task.h> ! 95: #include <kern/thread.h> ! 96: #include <kern/zalloc.h> ! 97: #include <kern/kalloc.h> ! 98: #include <kern/rtmalloc.h> ! 99: #include <kern/processor.h> ! 100: #include <kern/sched_prim.h> /* for thread_wakeup */ ! 101: #include <kern/sf.h> ! 102: #include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/ ! 103: #include <kern/ipc_tt.h> ! 104: #include <kern/ledger.h> ! 105: #include <kern/host.h> ! 106: #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */ ! 107: #include <kern/profile.h> ! 108: #include <kern/assert.h> ! 109: #include <kern/sync_lock.h> ! 110: #include <kern/sync_sema.h> ! 111: #if MACH_KDB ! 112: #include <ddb/db_sym.h> ! 113: #endif /* MACH_KDB */ ! 114: ! 115: #if TASK_SWAPPER ! 116: #include <kern/task_swap.h> ! 117: #endif /* TASK_SWAPPER */ ! 118: ! 119: /* ! 120: * Exported interfaces ! 121: */ ! 122: ! 123: #include <mach/task_server.h> ! 124: #include <mach/mach_host_server.h> ! 125: #include <mach/host_security_server.h> ! 126: ! 127: security_token_t DEFAULT_USER_SECURITY_TOKEN = { {930624, 610120} }; ! 128: ! 129: task_t kernel_task; ! 130: zone_t task_zone; ! 131: ! 132: /* Forwards */ ! 133: ! 134: kern_return_t task_hold_locked( ! 135: task_t task); ! 136: void task_wait_locked( ! 137: task_t task); ! 138: kern_return_t task_release( ! 139: task_t task); ! 140: void task_collect_scan(void); ! 141: void task_act_iterate( ! 142: task_t task, ! 143: kern_return_t (*func)(thread_act_t inc)); ! 144: void task_free( ! 145: task_t task ); ! 146: void task_synchronizer_destroy_all( ! 147: task_t task); ! 148: void task_subsystem_destroy_all( ! 149: task_t task); ! 150: ! 151: kern_return_t task_set_ledger( ! 152: task_t task, ! 153: ledger_t wired, ! 154: ledger_t paged); ! 155: ! 156: void ! 157: task_init(void) ! 158: { ! 159: task_zone = zinit( ! 160: sizeof(struct task), ! 161: TASK_MAX * sizeof(struct task), ! 162: TASK_CHUNK * sizeof(struct task), ! 163: "tasks"); ! 164: ! 165: eml_init(); ! 166: ! 167: /* ! 168: * Create the kernel task as the first task. ! 169: * Task_create_local must assign to kernel_task as a side effect, ! 170: * for other initialization. (:-() ! 171: */ ! 172: if (task_create_local( ! 173: TASK_NULL, FALSE, FALSE, &kernel_task) != KERN_SUCCESS) ! 174: panic("task_init\n"); ! 175: vm_map_deallocate(kernel_task->map); ! 176: kernel_task->map = kernel_map; ! 177: ! 178: #if MACH_ASSERT ! 179: if (watchacts & WA_TASK) ! 180: printf("task_init: kernel_task = %x map=%x\n", ! 181: kernel_task, kernel_map); ! 182: #endif /* MACH_ASSERT */ ! 183: } ! 184: ! 185: #if MACH_HOST ! 186: void ! 187: task_freeze( ! 188: task_t task) ! 189: { ! 190: task_lock(task); ! 191: /* ! 192: * If may_assign is false, task is already being assigned, ! 193: * wait for that to finish. ! 194: */ ! 195: while (task->may_assign == FALSE) { ! 196: task->assign_active = TRUE; ! 197: thread_sleep_mutex((event_t) &task->assign_active, ! 198: &task->lock, THREAD_INTERRUPTIBLE); ! 199: task_lock(task); ! 200: } ! 201: task->may_assign = FALSE; ! 202: task_unlock(task); ! 203: ! 204: return; ! 205: } ! 206: ! 207: void ! 208: task_unfreeze( ! 209: task_t task) ! 210: { ! 211: task_lock(task); ! 212: assert(task->may_assign == FALSE); ! 213: task->may_assign = TRUE; ! 214: if (task->assign_active == TRUE) { ! 215: task->assign_active = FALSE; ! 216: thread_wakeup((event_t)&task->assign_active); ! 217: } ! 218: task_unlock(task); ! 219: ! 220: return; ! 221: } ! 222: #endif /* MACH_HOST */ ! 223: ! 224: /* ! 225: * Create a task running in the kernel address space. It may ! 226: * have its own map of size mem_size and may have ipc privileges. ! 227: */ ! 228: kern_return_t ! 229: kernel_task_create( ! 230: task_t parent_task, ! 231: vm_offset_t map_base, ! 232: vm_size_t map_size, ! 233: task_t *child_task) ! 234: { ! 235: kern_return_t result; ! 236: task_t new_task; ! 237: vm_map_t old_map; ! 238: ! 239: /* ! 240: * Create the task. ! 241: */ ! 242: result = task_create_local(parent_task, FALSE, TRUE, &new_task); ! 243: if (result != KERN_SUCCESS) ! 244: return (result); ! 245: ! 246: /* ! 247: * Task_create_local creates the task with a user-space map. ! 248: * We attempt to replace the map and free it afterwards; else ! 249: * task_deallocate will free it (can NOT set map to null before ! 250: * task_deallocate, this impersonates a norma placeholder task). ! 251: * _Mark the memory as pageable_ -- this is what we ! 252: * want for images (like servers) loaded into the kernel. ! 253: */ ! 254: if (map_size == 0) { ! 255: vm_map_deallocate(new_task->map); ! 256: new_task->map = kernel_map; ! 257: *child_task = new_task; ! 258: } else { ! 259: old_map = new_task->map; ! 260: if ((result = kmem_suballoc(kernel_map, &map_base, ! 261: map_size, TRUE, FALSE, ! 262: &new_task->map)) != KERN_SUCCESS) { ! 263: /* ! 264: * New task created with ref count of 2 -- decrement by ! 265: * one to force task deletion. ! 266: */ ! 267: printf("kmem_suballoc(%x,%x,%x,1,0,&new) Fails\n", ! 268: kernel_map, map_base, map_size); ! 269: --new_task->ref_count; ! 270: task_deallocate(new_task); ! 271: return (result); ! 272: } ! 273: vm_map_deallocate(old_map); ! 274: *child_task = new_task; ! 275: } ! 276: return (KERN_SUCCESS); ! 277: } ! 278: ! 279: kern_return_t ! 280: task_create( ! 281: task_t parent_task, ! 282: ledger_port_array_t ledger_ports, ! 283: mach_msg_type_number_t num_ledger_ports, ! 284: boolean_t inherit_memory, ! 285: task_t *child_task) /* OUT */ ! 286: { ! 287: if (parent_task == TASK_NULL) ! 288: return(KERN_INVALID_ARGUMENT); ! 289: ! 290: return task_create_local( ! 291: parent_task, inherit_memory, FALSE, child_task); ! 292: } ! 293: ! 294: kern_return_t ! 295: host_security_create_task_token( ! 296: host_security_t host_security, ! 297: task_t parent_task, ! 298: security_token_t sec_token, ! 299: ledger_port_array_t ledger_ports, ! 300: mach_msg_type_number_t num_ledger_ports, ! 301: boolean_t inherit_memory, ! 302: task_t *child_task) /* OUT */ ! 303: { ! 304: kern_return_t result; ! 305: ! 306: if (parent_task == TASK_NULL) ! 307: return(KERN_INVALID_ARGUMENT); ! 308: ! 309: if (host_security == HOST_NULL) ! 310: return(KERN_INVALID_SECURITY); ! 311: ! 312: result = task_create_local( ! 313: parent_task, inherit_memory, FALSE, child_task); ! 314: ! 315: if (result != KERN_SUCCESS) ! 316: return(result); ! 317: result = host_security_set_task_token(host_security, ! 318: *child_task, ! 319: sec_token); ! 320: return(result); ! 321: } ! 322: ! 323: kern_return_t ! 324: task_create_local( ! 325: task_t parent_task, ! 326: boolean_t inherit_memory, ! 327: boolean_t kernel_loaded, ! 328: task_t *child_task) /* OUT */ ! 329: { ! 330: task_t new_task; ! 331: processor_set_t pset; ! 332: ! 333: new_task = (task_t) zalloc(task_zone); ! 334: ! 335: if (new_task == TASK_NULL) ! 336: return(KERN_RESOURCE_SHORTAGE); ! 337: ! 338: /* one ref for just being alive; one for our caller */ ! 339: new_task->ref_count = 2; ! 340: ! 341: if (inherit_memory) ! 342: new_task->map = vm_map_fork(parent_task->map); ! 343: else ! 344: new_task->map = vm_map_create(pmap_create(0), ! 345: round_page(VM_MIN_ADDRESS), ! 346: trunc_page(VM_MAX_ADDRESS), TRUE); ! 347: ! 348: mutex_init(&new_task->lock, ETAP_THREAD_TASK_NEW); ! 349: queue_init(&new_task->subsystem_list); ! 350: queue_init(&new_task->thr_acts); ! 351: mutex_init(&new_task->act_list_lock, ETAP_THREAD_ACT_LIST); ! 352: new_task->suspend_count = 0; ! 353: new_task->thr_act_count = 0; ! 354: new_task->user_stop_count = 0; ! 355: new_task->active = TRUE; ! 356: new_task->kernel_loaded = kernel_loaded; ! 357: new_task->user_data = 0; ! 358: new_task->faults = 0; ! 359: new_task->cow_faults = 0; ! 360: new_task->pageins = 0; ! 361: new_task->messages_sent = 0; ! 362: new_task->messages_received = 0; ! 363: new_task->syscalls_mach = 0; ! 364: new_task->syscalls_unix=0; ! 365: new_task->csw=0; ! 366: ! 367: #ifdef MACH_BSD ! 368: new_task->bsd_info = 0; ! 369: #endif /* MACH_BSD */ ! 370: ! 371: new_task->res_act_count = 0; /* used unconditionally */ ! 372: #if TASK_SWAPPER ! 373: new_task->swap_state = TASK_SW_IN; ! 374: new_task->swap_flags = 0; ! 375: new_task->swap_ast_waiting = 0; ! 376: new_task->swap_stamp = sched_tick; ! 377: new_task->swap_rss = 0; ! 378: new_task->swap_nswap = 0; ! 379: #endif /* TASK_SWAPPER */ ! 380: ! 381: queue_init(&new_task->semaphore_list); ! 382: queue_init(&new_task->lock_set_list); ! 383: new_task->semaphores_owned = 0; ! 384: new_task->lock_sets_owned = 0; ! 385: ! 386: #if MACH_HOST ! 387: new_task->may_assign = TRUE; ! 388: new_task->assign_active = FALSE; ! 389: #endif /* MACH_HOST */ ! 390: eml_task_reference(new_task, parent_task); ! 391: ! 392: ipc_task_init(new_task, parent_task); ! 393: ! 394: new_task->total_user_time.seconds = 0; ! 395: new_task->total_user_time.microseconds = 0; ! 396: new_task->total_system_time.seconds = 0; ! 397: new_task->total_system_time.microseconds = 0; ! 398: ! 399: task_prof_init(new_task); ! 400: ! 401: if (parent_task != TASK_NULL) { ! 402: #if MACH_HOST ! 403: /* ! 404: * Freeze the parent, so that parent_task->processor_set ! 405: * cannot change. ! 406: */ ! 407: task_freeze(parent_task); ! 408: #endif /* MACH_HOST */ ! 409: pset = parent_task->processor_set; ! 410: if (!pset->active) ! 411: pset = &default_pset; ! 412: new_task->policy = parent_task->policy; ! 413: ! 414: /* allocate space for scheduling attributes */ ! 415: new_task->sp_attributes = (sp_attributes_t)kalloc( ! 416: sched_policy[new_task->policy].sched_attributes_size); ! 417: ! 418: if (new_task->sp_attributes == SP_ATTRIBUTES_NULL) { ! 419: zfree(task_zone, (vm_offset_t) new_task); ! 420: ! 421: return(KERN_RESOURCE_SHORTAGE); ! 422: } ! 423: ! 424: /* initialize scheduling attributes */ ! 425: bcopy((char *)parent_task->sp_attributes, ! 426: (char *)new_task->sp_attributes, ! 427: sched_policy[new_task->policy].sched_attributes_size); ! 428: ! 429: new_task->sec_token = parent_task->sec_token; ! 430: new_task->wired_ledger_port = ledger_copy( ! 431: convert_port_to_ledger(parent_task->wired_ledger_port)); ! 432: new_task->paged_ledger_port = ledger_copy( ! 433: convert_port_to_ledger(parent_task->paged_ledger_port)); ! 434: } ! 435: else { ! 436: pset = &default_pset; ! 437: /*** ??? fix me, so that I am policy independent ***/ ! 438: if (kernel_task == TASK_NULL) ! 439: new_task->policy = POLICY_FIFO; ! 440: else ! 441: new_task->policy = POLICY_TIMESHARE; ! 442: ! 443: /* allocate space for scheduling attributes */ ! 444: new_task->sp_attributes = ! 445: (sp_attributes_t)kalloc(sizeof(mk_sp_attribute_struct_t)); ! 446: ! 447: if (new_task->sp_attributes == SP_ATTRIBUTES_NULL) { ! 448: zfree(task_zone, (vm_offset_t) new_task); ! 449: ! 450: return(KERN_RESOURCE_SHORTAGE); ! 451: } ! 452: ! 453: /* initialize scheduling attributes */ ! 454: { ! 455: /*** ??? fix me ***/ ! 456: mk_sp_attributes_t sched_attribute; ! 457: ! 458: sched_attribute = (mk_sp_attributes_t)new_task->sp_attributes; ! 459: if (kernel_task == TASK_NULL) { ! 460: sched_attribute->policy_id = POLICY_FIFO; ! 461: sched_attribute->priority = BASEPRI_SYSTEM; ! 462: sched_attribute->max_priority = BASEPRI_SYSTEM; ! 463: } ! 464: else { ! 465: sched_attribute->policy_id = POLICY_TIMESHARE; ! 466: sched_attribute->priority = BASEPRI_USER; ! 467: sched_attribute->max_priority = BASEPRI_USER; ! 468: } ! 469: ! 470: sched_attribute->sched_data = 0; ! 471: sched_attribute->unconsumed_quantum = 0; ! 472: } ! 473: ! 474: new_task->sec_token = DEFAULT_USER_SECURITY_TOKEN; ! 475: new_task->wired_ledger_port = ledger_copy(root_wired_ledger); ! 476: new_task->paged_ledger_port = ledger_copy(root_paged_ledger); ! 477: } ! 478: pset_lock(pset); ! 479: pset_add_task(pset, new_task); ! 480: pset_unlock(pset); ! 481: #if MACH_HOST ! 482: if (parent_task != TASK_NULL) ! 483: task_unfreeze(parent_task); ! 484: #endif /* MACH_HOST */ ! 485: ! 486: #if FAST_TAS ! 487: if (inherit_memory) { ! 488: new_task->fast_tas_base = parent_task->fast_tas_base; ! 489: new_task->fast_tas_end = parent_task->fast_tas_end; ! 490: } else { ! 491: new_task->fast_tas_base = (vm_offset_t)0; ! 492: new_task->fast_tas_end = (vm_offset_t)0; ! 493: } ! 494: #endif /* FAST_TAS */ ! 495: ! 496: ipc_task_enable(new_task); ! 497: ! 498: #if TASK_SWAPPER ! 499: task_swapout_eligible(new_task); ! 500: #endif /* TASK_SWAPPER */ ! 501: ! 502: #if MACH_ASSERT ! 503: if (watchacts & WA_TASK) ! 504: printf("*** task_create_local(par=%x inh=%x) == 0x%x\n", ! 505: parent_task, inherit_memory, new_task); ! 506: #endif /* MACH_ASSERT */ ! 507: ! 508: *child_task = new_task; ! 509: return(KERN_SUCCESS); ! 510: } ! 511: ! 512: /* ! 513: * task_free: ! 514: * ! 515: * Called by task_deallocate when the task's reference count drops to zero. ! 516: * Task is locked. ! 517: */ ! 518: void ! 519: task_free( ! 520: task_t task) ! 521: { ! 522: processor_set_t pset; ! 523: ! 524: #if MACH_ASSERT ! 525: assert(task != 0); ! 526: if (watchacts & (WA_EXIT|WA_TASK)) ! 527: printf("task_free(%x(%d)) map ref %d\n", task, task->ref_count, ! 528: task->map->ref_count); ! 529: #endif /* MACH_ASSERT */ ! 530: ! 531: #if TASK_SWAPPER ! 532: /* task_terminate guarantees that this task is off the list */ ! 533: assert((task->swap_state & TASK_SW_ELIGIBLE) == 0); ! 534: #endif /* TASK_SWAPPER */ ! 535: ! 536: eml_task_deallocate(task); ! 537: ! 538: /* ! 539: * Temporarily restore the reference we dropped above, then ! 540: * freeze the task so that the task->processor_set field ! 541: * cannot change. In the !MACH_HOST case, the logic can be ! 542: * simplified, since the default_pset is the only pset. ! 543: */ ! 544: ++task->ref_count; ! 545: task_unlock(task); ! 546: #if MACH_HOST ! 547: task_freeze(task); ! 548: #endif /* MACH_HOST */ ! 549: ! 550: pset = task->processor_set; ! 551: pset_lock(pset); ! 552: task_lock(task); ! 553: if (--task->ref_count > 0) { ! 554: /* ! 555: * A new reference appeared (probably from the pset). ! 556: * Back out. Must unfreeze inline since we'already ! 557: * dropped our reference. ! 558: */ ! 559: #if MACH_HOST ! 560: assert(task->may_assign == FALSE); ! 561: task->may_assign = TRUE; ! 562: if (task->assign_active == TRUE) { ! 563: task->assign_active = FALSE; ! 564: thread_wakeup((event_t)&task->assign_active); ! 565: } ! 566: #endif /* MACH_HOST */ ! 567: task_unlock(task); ! 568: pset_unlock(pset); ! 569: return; ! 570: } ! 571: ipc_port_release_send(task->wired_ledger_port); ! 572: ipc_port_release_send(task->paged_ledger_port); ! 573: pset_remove_task(pset,task); ! 574: task_unlock(task); ! 575: pset_unlock(pset); ! 576: pset_deallocate(pset); ! 577: if (task->kernel_loaded) ! 578: vm_map_remove(kernel_map, task->map->min_offset, ! 579: task->map->max_offset, VM_MAP_NO_FLAGS); ! 580: vm_map_deallocate(task->map); ! 581: is_release(task->itk_space); ! 582: task_prof_deallocate(task); ! 583: kfree((vm_offset_t)task->sp_attributes, ! 584: sched_policy[task->policy].sched_attributes_size); ! 585: zfree(task_zone, (vm_offset_t) task); ! 586: } ! 587: ! 588: /* ! 589: * task_act_iterate ! 590: * ! 591: * Ignores returncodes from called function. ! 592: * Already locked: Task ! 593: */ ! 594: void ! 595: task_act_iterate( ! 596: task_t task, ! 597: kern_return_t (*func)(thread_act_t inc)) ! 598: { ! 599: thread_act_t inc, ninc; ! 600: #if MACH_ASSERT ! 601: int c1 = task->thr_act_count, c2 = 0; ! 602: if (watchacts & WA_TASK) ! 603: printf("\ttask_act_iterate(task=%x, func=%x)\n", task, func); ! 604: #endif /* MACH_ASSERT */ ! 605: ! 606: /* During iteration, find the next act _before_ calling the function, ! 607: because the function might remove the act from the task. */ ! 608: for (inc = (thread_act_t)queue_first(&task->thr_acts); ! 609: inc != (thread_act_t)&task->thr_acts; ! 610: inc = ninc) { ! 611: ninc = (thread_act_t)queue_next(&inc->thr_acts); ! 612: #if MACH_ASSERT ! 613: c2++; ! 614: #endif ! 615: (void) (*func)(inc); ! 616: } ! 617: ! 618: #if MACH_ASSERT ! 619: if (c1 != c2) { ! 620: printf("task_act_iterate: thr_act_count %d not %d\n", c1, c2); ! 621: /* Recount in case above (*func)() changed list */ ! 622: for (c2 = 0, inc = (thread_act_t)queue_first(&task->thr_acts); ! 623: inc != (thread_act_t)&task->thr_acts; inc = ninc) { ! 624: ninc = (thread_act_t)queue_next(&inc->thr_acts); ! 625: c2++; ! 626: } ! 627: printf("\t reset thr_act_count to %d\n", ! 628: task->thr_act_count = c2); ! 629: } ! 630: #endif ! 631: } ! 632: ! 633: void ! 634: task_deallocate( ! 635: task_t task) ! 636: { ! 637: if (task != TASK_NULL) { ! 638: int c; ! 639: ! 640: task_lock(task); ! 641: c = --task->ref_count; ! 642: if (c == 0) ! 643: task_free(task); /* unlocks task */ ! 644: else ! 645: task_unlock(task); ! 646: } ! 647: } ! 648: ! 649: void ! 650: task_reference( ! 651: task_t task) ! 652: { ! 653: if (task != TASK_NULL) { ! 654: task_lock(task); ! 655: task->ref_count++; ! 656: task_unlock(task); ! 657: } ! 658: } ! 659: ! 660: /* ! 661: * task_terminate: ! 662: * ! 663: * Terminate the specified task. See comments on thread_terminate ! 664: * (kern/thread.c) about problems with terminating the "current task." ! 665: */ ! 666: ! 667: kern_return_t ! 668: task_terminate( ! 669: task_t task) ! 670: { ! 671: if (task == TASK_NULL) ! 672: return(KERN_INVALID_ARGUMENT); ! 673: if (task->bsd_info) ! 674: return(KERN_FAILURE); ! 675: return (task_terminate_internal(task)); ! 676: } ! 677: ! 678: kern_return_t ! 679: task_terminate_internal( ! 680: task_t task) ! 681: { ! 682: register thread_t thread, cur_thread; ! 683: register queue_head_t *list; ! 684: register task_t cur_task; ! 685: thread_act_t thr_act, next_thr_act, cur_thr_act; ! 686: spl_t s; ! 687: ! 688: assert(task != kernel_task); ! 689: ! 690: list = &task->thr_acts; ! 691: cur_task = current_task(); ! 692: cur_thr_act = current_thread()->top_act; ! 693: ! 694: #if TASK_SWAPPER ! 695: /* ! 696: * If task is not resident (swapped out, or being swapped ! 697: * out), we want to bring it back in (this can block). ! 698: * NOTE: The only way that this can happen in the current ! 699: * system is if the task is swapped while it has a thread ! 700: * in exit(), and the thread does not hit a clean point ! 701: * to swap itself before getting here. ! 702: * Terminating other tasks is another way to this code, but ! 703: * it is not yet fully supported. ! 704: * The task_swapin is unconditional. It used to be done ! 705: * only if the task is not resident. Swapping in a ! 706: * resident task will prevent it from being swapped out ! 707: * while it terminates. ! 708: */ ! 709: task_swapin(task, TRUE); /* TRUE means make it unswappable */ ! 710: #endif /* TASK_SWAPPER */ ! 711: ! 712: /* ! 713: * Deactivate task so that it can't be terminated again, ! 714: * and so lengthy operations in progress will abort. ! 715: * ! 716: * If the current thread is in this task, remove it from ! 717: * the task's thread list to keep the thread-termination ! 718: * loop simple. ! 719: */ ! 720: if (task == cur_task) { ! 721: task_lock(task); ! 722: if (!task->active) { ! 723: /* ! 724: * Task is already being terminated. ! 725: */ ! 726: task_unlock(task); ! 727: thread_block((void (*)(void)) 0); ! 728: return(KERN_FAILURE); ! 729: } ! 730: ! 731: task_hold_locked(task); ! 732: ! 733: task->active = FALSE; ! 734: ! 735: /* ! 736: * Make sure current thread is not being terminated. ! 737: */ ! 738: mutex_lock(&task->act_list_lock); ! 739: cur_thread = act_lock_thread(cur_thr_act); ! 740: if (!cur_thr_act->active) { ! 741: act_unlock_thread(cur_thr_act); ! 742: mutex_unlock(&task->act_list_lock); ! 743: task_unlock(task); ! 744: task_release(task); ! 745: thread_terminate(cur_thr_act); ! 746: return(KERN_FAILURE); ! 747: } ! 748: ! 749: /* ! 750: * make sure that this thread is the last one in the list ! 751: */ ! 752: queue_remove(list, cur_thr_act, thread_act_t, thr_acts); ! 753: queue_enter(list, cur_thr_act, thread_act_t, thr_acts); ! 754: act_unlock_thread(cur_thr_act); ! 755: mutex_unlock(&task->act_list_lock); ! 756: ! 757: /* ! 758: * Shut down this thread's ipc now because it must ! 759: * be left alone to terminate the task. ! 760: */ ! 761: ipc_thr_act_disable(cur_thr_act); ! 762: ipc_thr_act_terminate(cur_thr_act); ! 763: } ! 764: else { ! 765: /* ! 766: * Lock both current and victim task to check for ! 767: * potential deadlock. ! 768: */ ! 769: if (task < cur_task) { ! 770: task_lock(task); ! 771: task_lock(cur_task); ! 772: } ! 773: else { ! 774: task_lock(cur_task); ! 775: task_lock(task); ! 776: } ! 777: /* ! 778: * Check if current thread_act or task is being terminated. ! 779: */ ! 780: cur_thread = act_lock_thread(cur_thr_act); ! 781: if ((!cur_task->active) || (!cur_thr_act->active)) { ! 782: /* ! 783: * Current task or thread is being terminated. ! 784: */ ! 785: act_unlock_thread(cur_thr_act); ! 786: task_unlock(task); ! 787: task_unlock(cur_task); ! 788: return(KERN_FAILURE); ! 789: } ! 790: act_unlock_thread(cur_thr_act); ! 791: task_unlock(cur_task); ! 792: ! 793: if (!task->active) { ! 794: /* ! 795: * Task is already being terminated. ! 796: */ ! 797: task_unlock(task); ! 798: thread_block((void (*)(void)) 0); ! 799: return(KERN_FAILURE); ! 800: } ! 801: task_hold_locked(task); ! 802: task->active = FALSE; ! 803: } ! 804: ! 805: /* ! 806: * Prevent further execution of the task. ipc_task_disable ! 807: * prevents further task operations via the task port. ! 808: * If this is the current task, the current thread will ! 809: * be left running. ! 810: */ ! 811: ipc_task_disable(task); ! 812: task_wait_locked(task); ! 813: ! 814: /* ! 815: * Terminate each thread in the task. Depending on the ! 816: * state of the thread, this can mean a number of things. ! 817: * However, we just call thread_terminate(), which ! 818: * takes care of all cases (see that code for details). ! 819: * ! 820: * The task_port is closed down, so no more thread_create ! 821: * operations can be done. Thread_terminate closes the ! 822: * thread port for each thread; when that is done, the ! 823: * thread will eventually disappear. Thus the loop will ! 824: * terminate. ! 825: * Need to call thread_block() inside loop because some ! 826: * other thread (e.g., the reaper) may have to run to get rid ! 827: * of all references to the thread; it won't vanish from ! 828: * the task's thread list until the last one is gone. ! 829: */ ! 830: thr_act = (thread_act_t)queue_first(&task->thr_acts); ! 831: while ( thr_act!= (thread_act_t)&task->thr_acts) { ! 832: act_reference(thr_act); ! 833: next_thr_act = (thread_act_t)queue_next(&thr_act->thr_acts); ! 834: task_unlock(task); ! 835: thread_terminate(thr_act); ! 836: act_deallocate(thr_act); ! 837: task_lock(task); ! 838: thr_act = next_thr_act; ! 839: } ! 840: ! 841: task_unlock(task); ! 842: ! 843: /* ! 844: * Destroy all synchronizers owned by the task. ! 845: */ ! 846: task_synchronizer_destroy_all(task); ! 847: ! 848: /* ! 849: * Shut down IPC. ! 850: */ ! 851: ipc_task_terminate(task); ! 852: ! 853: /* ! 854: * Deallocate all subsystems owned by the task. ! 855: */ ! 856: task_subsystem_destroy_all(task); ! 857: ! 858: /* ! 859: * If the current thread is a member of the task ! 860: * being terminated, then the last reference to ! 861: * the task will not be dropped until the thread ! 862: * is finally reaped. To avoid incurring the ! 863: * expense of removing the address space regions ! 864: * at reap time, we do it explictly here. ! 865: */ ! 866: (void) vm_map_remove(task->map, ! 867: task->map->min_offset, ! 868: task->map->max_offset, VM_MAP_NO_FLAGS); ! 869: ! 870: /* ! 871: * Deallocate the task's reference to itself. ! 872: */ ! 873: task_deallocate(task); ! 874: ! 875: return(KERN_SUCCESS); ! 876: } ! 877: ! 878: /* ! 879: * Wait for all threads in task to terminate (except current). ! 880: * We rely on the fact that all the other threads cache references ! 881: * to the task's VM map, and when we are alone in the task the ! 882: * reference count on the map should reach two (one for the task ! 883: * itself and one for the current act). ! 884: */ ! 885: void ! 886: task_halt_wait( ! 887: register task_t task) ! 888: { ! 889: vm_map_t map = task->map; ! 890: ! 891: assert(current_thread()->top_act->task == task); ! 892: ! 893: /* ! 894: * Wait for the current thread to become the only thread in ! 895: * this task. ! 896: */ ! 897: /* ! 898: * Now wait for the map users to settle down. ! 899: */ ! 900: mutex_lock(&map->s_lock); ! 901: while (map->ref_count > 2) { ! 902: assert_wait(&map->ref_count, THREAD_UNINT); ! 903: mutex_unlock(&map->s_lock); ! 904: thread_block(0); ! 905: mutex_lock(&map->s_lock); ! 906: } ! 907: mutex_unlock(&map->s_lock); ! 908: } ! 909: ! 910: /* ! 911: * task_halt - Shut the current task down (except for the current thread) in ! 912: * preparation for dramatic changes to the task (probably exec). ! 913: * We hold the task, terminate all other threads in the task and ! 914: * wait for them to terminate, clean up the portspace, and when ! 915: * all done, let the current thread go. ! 916: */ ! 917: kern_return_t ! 918: task_halt( ! 919: task_t task) ! 920: { ! 921: register thread_t thread, cur_thread; ! 922: register queue_head_t *list; ! 923: register task_t cur_task; ! 924: thread_act_t thr_act, cur_thr_act; ! 925: spl_t s; ! 926: ! 927: assert(task != kernel_task); ! 928: ! 929: cur_task = current_task(); ! 930: if (task != cur_task) { ! 931: return(KERN_INVALID_ARGUMENT); ! 932: } ! 933: ! 934: #if TASK_SWAPPER ! 935: /* ! 936: * If task is not resident (swapped out, or being swapped ! 937: * out), we want to bring it back in (this can block). ! 938: * NOTE: The only way that this can happen in the current ! 939: * system is if the task is swapped while it has a thread ! 940: * in exit(), and the thread does not hit a clean point ! 941: * to swap itself before getting here. ! 942: * Terminating other tasks is another way to this code, but ! 943: * it is not yet fully supported. ! 944: * The task_swapin is unconditional. It used to be done ! 945: * only if the task is not resident. Swapping in a ! 946: * resident task will prevent it from being swapped out ! 947: * while it terminates. ! 948: */ ! 949: task_swapin(task, TRUE); /* TRUE means make it unswappable */ ! 950: #endif /* TASK_SWAPPER */ ! 951: ! 952: /* ! 953: * Deactivate task so that it can't be terminated again, ! 954: * and so lengthy operations in progress will abort. ! 955: * ! 956: * If the current thread is in this task, remove it from ! 957: * the task's thread list to keep the thread-termination ! 958: * loop simple. ! 959: */ ! 960: task_lock(task); ! 961: if (!task->active) { ! 962: /* ! 963: * Task is already being terminated. ! 964: */ ! 965: task_unlock(task); ! 966: thread_block((void (*)(void)) 0); ! 967: return(KERN_FAILURE); ! 968: } ! 969: task_hold_locked(task); ! 970: ! 971: /* ! 972: * Make sure current thread is not being terminated. ! 973: */ ! 974: cur_thr_act = current_thread()->top_act; ! 975: mutex_lock(&task->act_list_lock); ! 976: cur_thread = act_lock_thread(cur_thr_act); ! 977: if (!cur_thr_act->active) { ! 978: act_unlock_thread(cur_thr_act); ! 979: mutex_unlock(&task->act_list_lock); ! 980: task_unlock(task); ! 981: task_release(task); ! 982: thread_terminate(cur_thr_act); ! 983: return(KERN_FAILURE); ! 984: } ! 985: ! 986: task->active = FALSE; ! 987: ! 988: /* ! 989: * Make sure that this thread is the last one in the list ! 990: */ ! 991: list = &task->thr_acts; ! 992: queue_remove(list, cur_thr_act, thread_act_t, thr_acts); ! 993: queue_enter(list, cur_thr_act, thread_act_t, thr_acts); ! 994: act_unlock_thread(cur_thr_act); ! 995: mutex_unlock(&task->act_list_lock); ! 996: ! 997: /* ! 998: * Wait for threads to get to clean points. ! 999: */ ! 1000: task_wait_locked(task); ! 1001: ! 1002: /* ! 1003: * Now that each thread in the task is at a clean point (and the ! 1004: * task is temporarily marked inactive so no new threads can be ! 1005: * created), we terminate each of those other threads. ! 1006: */ ! 1007: for (thr_act = (thread_act_t)queue_first(&task->thr_acts); ! 1008: thr_act != (thread_act_t)cur_thr_act; ! 1009: thr_act = (thread_act_t)queue_next(&thr_act->thr_acts)) { ! 1010: act_reference(thr_act); ! 1011: task_unlock(task); ! 1012: thread_terminate(thr_act); ! 1013: act_deallocate(thr_act); ! 1014: task_lock(task); ! 1015: } ! 1016: task_unlock(task); ! 1017: ! 1018: /* ! 1019: * Wait for the the other threads to exit. ! 1020: */ ! 1021: task_halt_wait(task); ! 1022: ! 1023: /* ! 1024: * Put it back as active and release the hold on the task ! 1025: */ ! 1026: task_lock(task); ! 1027: task->active = TRUE; ! 1028: task_unlock(task); ! 1029: task_release(task); ! 1030: return(KERN_SUCCESS); ! 1031: } ! 1032: ! 1033: /* ! 1034: * Clean up a task for possible reuse (like after exec). ! 1035: */ ! 1036: void ! 1037: task_ipc_cleanup( ! 1038: task_t task) ! 1039: { ! 1040: /* ! 1041: * Remove all the port rights from the task's IPC port space. ! 1042: */ ! 1043: ipc_space_clean(task->itk_space); ! 1044: ! 1045: /* ! 1046: * Destroy all synchronizers owned by the task. ! 1047: */ ! 1048: task_synchronizer_destroy_all(task); ! 1049: ! 1050: /* ! 1051: * Deallocate all subsystems owned by the task. ! 1052: */ ! 1053: task_subsystem_destroy_all(task); ! 1054: ! 1055: } ! 1056: ! 1057: /* ! 1058: * task_hold_locked: ! 1059: * ! 1060: * Suspend execution of the specified task. ! 1061: * This is a recursive-style suspension of the task, a count of ! 1062: * suspends is maintained. ! 1063: * ! 1064: * CONDITIONS: the task is locked. ! 1065: */ ! 1066: kern_return_t ! 1067: task_hold_locked( ! 1068: register task_t task) ! 1069: { ! 1070: register queue_head_t *list; ! 1071: register thread_act_t thr_act, cur_thr_act; ! 1072: ! 1073: cur_thr_act = current_act(); ! 1074: ! 1075: if (!task->active) { ! 1076: return(KERN_FAILURE); ! 1077: } ! 1078: ! 1079: task->suspend_count++; ! 1080: ! 1081: /* ! 1082: * Iterate through all the thread_act's and hold them. ! 1083: * Do not hold the current thread_act if it is within the ! 1084: * task. ! 1085: */ ! 1086: list = &task->thr_acts; ! 1087: thr_act = (thread_act_t) queue_first(list); ! 1088: while (!queue_end(list, (queue_entry_t) thr_act)) { ! 1089: (void)act_lock_thread(thr_act); ! 1090: thread_hold(thr_act); ! 1091: act_unlock_thread(thr_act); ! 1092: thr_act = (thread_act_t) queue_next(&thr_act->thr_acts); ! 1093: } ! 1094: return(KERN_SUCCESS); ! 1095: } ! 1096: ! 1097: kern_return_t ! 1098: task_release( ! 1099: register task_t task) ! 1100: { ! 1101: register queue_head_t *list; ! 1102: register thread_act_t thr_act, next; ! 1103: ! 1104: task_lock(task); ! 1105: if (!task->active) { ! 1106: task_unlock(task); ! 1107: return(KERN_FAILURE); ! 1108: } ! 1109: ! 1110: task->suspend_count--; ! 1111: ! 1112: /* ! 1113: * Iterate through all the thread_act's and release them. ! 1114: */ ! 1115: list = &task->thr_acts; ! 1116: thr_act = (thread_act_t) queue_first(list); ! 1117: while (!queue_end(list, (queue_entry_t) thr_act)) { ! 1118: next = (thread_act_t) queue_next(&thr_act->thr_acts); ! 1119: (void)act_lock_thread(thr_act); ! 1120: thread_release(thr_act); ! 1121: act_unlock_thread(thr_act); ! 1122: thr_act = next; ! 1123: } ! 1124: task_unlock(task); ! 1125: return(KERN_SUCCESS); ! 1126: } ! 1127: ! 1128: kern_return_t ! 1129: task_threads( ! 1130: task_t task, ! 1131: thread_act_array_t *thr_act_list, ! 1132: mach_msg_type_number_t *count) ! 1133: { ! 1134: unsigned int actual; /* this many thr_acts */ ! 1135: thread_act_t thr_act; ! 1136: thread_act_t *thr_acts; ! 1137: thread_t thread; ! 1138: int i, j; ! 1139: boolean_t rt = FALSE; /* ### This boolean is FALSE, because there ! 1140: * currently exists no mechanism to determine ! 1141: * whether or not the reply port is an RT port ! 1142: */ ! 1143: ! 1144: ! 1145: vm_size_t size, size_needed; ! 1146: vm_offset_t addr; ! 1147: ! 1148: if (task == TASK_NULL) ! 1149: return KERN_INVALID_ARGUMENT; ! 1150: ! 1151: size = 0; addr = 0; ! 1152: ! 1153: for (;;) { ! 1154: task_lock(task); ! 1155: if (!task->active) { ! 1156: task_unlock(task); ! 1157: if (size != 0) ! 1158: KFREE(addr, size, rt); ! 1159: return KERN_FAILURE; ! 1160: } ! 1161: ! 1162: actual = task->thr_act_count; ! 1163: ! 1164: /* do we have the memory we need? */ ! 1165: size_needed = actual * sizeof(mach_port_t); ! 1166: if (size_needed <= size) ! 1167: break; ! 1168: ! 1169: /* unlock the task and allocate more memory */ ! 1170: task_unlock(task); ! 1171: ! 1172: if (size != 0) ! 1173: KFREE(addr, size, rt); ! 1174: ! 1175: assert(size_needed > 0); ! 1176: size = size_needed; ! 1177: ! 1178: addr = KALLOC(size, rt); ! 1179: if (addr == 0) ! 1180: return KERN_RESOURCE_SHORTAGE; ! 1181: } ! 1182: ! 1183: /* OK, have memory and the task is locked & active */ ! 1184: thr_acts = (thread_act_t *) addr; ! 1185: ! 1186: for (i = j = 0, thr_act = (thread_act_t) queue_first(&task->thr_acts); ! 1187: i < actual; ! 1188: i++, thr_act = (thread_act_t) queue_next(&thr_act->thr_acts)) { ! 1189: act_reference(thr_act); ! 1190: thr_acts[j++] = thr_act; ! 1191: } ! 1192: assert(queue_end(&task->thr_acts, (queue_entry_t) thr_act)); ! 1193: actual = j; ! 1194: ! 1195: /* can unlock task now that we've got the thr_act refs */ ! 1196: task_unlock(task); ! 1197: ! 1198: if (actual == 0) { ! 1199: /* no thr_acts, so return null pointer and deallocate memory */ ! 1200: ! 1201: *thr_act_list = 0; ! 1202: *count = 0; ! 1203: ! 1204: if (size != 0) ! 1205: KFREE(addr, size, rt); ! 1206: } else { ! 1207: /* if we allocated too much, must copy */ ! 1208: ! 1209: if (size_needed < size) { ! 1210: vm_offset_t newaddr; ! 1211: ! 1212: newaddr = KALLOC(size_needed, rt); ! 1213: if (newaddr == 0) { ! 1214: for (i = 0; i < actual; i++) ! 1215: act_deallocate(thr_acts[i]); ! 1216: KFREE(addr, size, rt); ! 1217: return KERN_RESOURCE_SHORTAGE; ! 1218: } ! 1219: ! 1220: bcopy((char *) addr, (char *) newaddr, size_needed); ! 1221: KFREE(addr, size, rt); ! 1222: thr_acts = (thread_act_t *) newaddr; ! 1223: } ! 1224: ! 1225: *thr_act_list = thr_acts; ! 1226: *count = actual; ! 1227: ! 1228: /* do the conversion that Mig should handle */ ! 1229: ! 1230: for (i = 0; i < actual; i++) ! 1231: ((ipc_port_t *) thr_acts)[i] = ! 1232: convert_act_to_port(thr_acts[i]); ! 1233: } ! 1234: ! 1235: return KERN_SUCCESS; ! 1236: } ! 1237: ! 1238: kern_return_t ! 1239: task_suspend( ! 1240: register task_t task) ! 1241: { ! 1242: if (task == TASK_NULL) ! 1243: return (KERN_INVALID_ARGUMENT); ! 1244: ! 1245: task_lock(task); ! 1246: if (!task->active) { ! 1247: task_unlock(task); ! 1248: return (KERN_FAILURE); ! 1249: } ! 1250: if ((task->user_stop_count)++ > 0) { ! 1251: /* ! 1252: * If the stop count was positive, the task is ! 1253: * already stopped and we can exit. ! 1254: */ ! 1255: task_unlock(task); ! 1256: return (KERN_SUCCESS); ! 1257: } ! 1258: ! 1259: /* ! 1260: * Hold all of the threads in the task, and wait for ! 1261: * them to stop. If the current thread is within ! 1262: * this task, hold it separately so that all of the ! 1263: * other threads can stop first. ! 1264: */ ! 1265: if (task_hold_locked(task) != KERN_SUCCESS) { ! 1266: task_unlock(task); ! 1267: return (KERN_FAILURE); ! 1268: } ! 1269: ! 1270: task_wait_locked(task); ! 1271: task_unlock(task); ! 1272: return (KERN_SUCCESS); ! 1273: } ! 1274: ! 1275: /* ! 1276: * Wait for all threads in task to stop. Called with task locked. ! 1277: */ ! 1278: void ! 1279: task_wait_locked( ! 1280: register task_t task) ! 1281: { ! 1282: register queue_head_t *list; ! 1283: register thread_act_t thr_act, refd_thr_act; ! 1284: register thread_t thread, cur_thr; ! 1285: ! 1286: cur_thr = current_thread(); ! 1287: /* ! 1288: * Iterate through all the thread's and wait for them to ! 1289: * stop. Do not wait for the current thread if it is within ! 1290: * the task. ! 1291: */ ! 1292: list = &task->thr_acts; ! 1293: refd_thr_act = THR_ACT_NULL; ! 1294: for (;;) { ! 1295: thr_act = (thread_act_t) queue_first(list); ! 1296: while (!queue_end(list, (queue_entry_t) thr_act)) { ! 1297: thread = act_lock_thread(thr_act); ! 1298: if (refd_thr_act != THR_ACT_NULL) { ! 1299: act_deallocate(refd_thr_act); ! 1300: refd_thr_act = THR_ACT_NULL; ! 1301: } ! 1302: if (thread != THREAD_NULL && ! 1303: thr_act == thread->top_act && ! 1304: thread != cur_thr) { ! 1305: refd_thr_act = thr_act; ! 1306: act_locked_act_reference(thr_act); ! 1307: act_unlock_thread(thr_act); ! 1308: task_unlock(task); ! 1309: (void)thread_wait(thread); ! 1310: task_lock(task); ! 1311: thread = act_lock_thread(thr_act); ! 1312: if (!thr_act->active) { ! 1313: act_unlock_thread(thr_act); ! 1314: /* drop reference to act immediately */ ! 1315: task_unlock(task); ! 1316: act_deallocate(refd_thr_act); ! 1317: refd_thr_act = THR_ACT_NULL; ! 1318: task_lock(task); ! 1319: break; ! 1320: } ! 1321: } ! 1322: act_unlock_thread(thr_act); ! 1323: thr_act = (thread_act_t)queue_next(&thr_act->thr_acts); ! 1324: } ! 1325: if (queue_end(list, (queue_entry_t)thr_act)) ! 1326: break; ! 1327: } ! 1328: if (refd_thr_act != THR_ACT_NULL) { ! 1329: act_deallocate(refd_thr_act); ! 1330: refd_thr_act = THR_ACT_NULL; ! 1331: } ! 1332: } ! 1333: ! 1334: kern_return_t ! 1335: task_resume(register task_t task) ! 1336: { ! 1337: register boolean_t release; ! 1338: ! 1339: if (task == TASK_NULL) ! 1340: return(KERN_INVALID_ARGUMENT); ! 1341: ! 1342: release = FALSE; ! 1343: task_lock(task); ! 1344: if (!task->active) { ! 1345: task_unlock(task); ! 1346: return(KERN_FAILURE); ! 1347: } ! 1348: if (task->user_stop_count > 0) { ! 1349: if (--(task->user_stop_count) == 0) ! 1350: release = TRUE; ! 1351: } ! 1352: else { ! 1353: task_unlock(task); ! 1354: return(KERN_FAILURE); ! 1355: } ! 1356: task_unlock(task); ! 1357: ! 1358: /* ! 1359: * Release the task if necessary. ! 1360: */ ! 1361: if (release) ! 1362: return(task_release(task)); ! 1363: ! 1364: return(KERN_SUCCESS); ! 1365: } ! 1366: ! 1367: kern_return_t ! 1368: host_security_set_task_token( ! 1369: host_security_t host_security, ! 1370: task_t task, ! 1371: security_token_t sec_token) ! 1372: { ! 1373: if (task == TASK_NULL) ! 1374: return(KERN_INVALID_ARGUMENT); ! 1375: ! 1376: if (host_security == HOST_NULL) ! 1377: return(KERN_INVALID_SECURITY); ! 1378: ! 1379: task_lock(task); ! 1380: task->sec_token = sec_token; ! 1381: task_unlock(task); ! 1382: ! 1383: return(KERN_SUCCESS); ! 1384: } ! 1385: ! 1386: /* ! 1387: * Utility routine to set a ledger ! 1388: */ ! 1389: kern_return_t ! 1390: task_set_ledger( ! 1391: task_t task, ! 1392: ledger_t wired, ! 1393: ledger_t paged) ! 1394: { ! 1395: if (task == TASK_NULL) ! 1396: return(KERN_INVALID_ARGUMENT); ! 1397: ! 1398: task_lock(task); ! 1399: if (wired) { ! 1400: ipc_port_release_send(task->wired_ledger_port); ! 1401: task->wired_ledger_port = ledger_copy(wired); ! 1402: } ! 1403: if (paged) { ! 1404: ipc_port_release_send(task->paged_ledger_port); ! 1405: task->paged_ledger_port = ledger_copy(paged); ! 1406: } ! 1407: task_unlock(task); ! 1408: ! 1409: return(KERN_SUCCESS); ! 1410: } ! 1411: ! 1412: /* ! 1413: * This routine was added, pretty much exclusively, for registering the ! 1414: * RPC glue vector for in-kernel short circuited tasks. Rather than ! 1415: * removing it completely, I have only disabled that feature (which was ! 1416: * the only feature at the time). It just appears that we are going to ! 1417: * want to add some user data to tasks in the future (i.e. bsd info, ! 1418: * task names, etc...), so I left it in the formal task interface. ! 1419: */ ! 1420: kern_return_t ! 1421: task_set_info( ! 1422: task_t task, ! 1423: task_flavor_t flavor, ! 1424: task_info_t task_info_in, /* pointer to IN array */ ! 1425: mach_msg_type_number_t task_info_count) ! 1426: { ! 1427: vm_map_t map; ! 1428: ! 1429: if (task == TASK_NULL) ! 1430: return(KERN_INVALID_ARGUMENT); ! 1431: ! 1432: switch (flavor) { ! 1433: default: ! 1434: return (KERN_INVALID_ARGUMENT); ! 1435: } ! 1436: return (KERN_SUCCESS); ! 1437: } ! 1438: ! 1439: kern_return_t ! 1440: task_info( ! 1441: task_t task, ! 1442: task_flavor_t flavor, ! 1443: task_info_t task_info_out, ! 1444: mach_msg_type_number_t *task_info_count) ! 1445: { ! 1446: thread_t thread; ! 1447: vm_map_t map; ! 1448: ! 1449: if (task == TASK_NULL) ! 1450: return(KERN_INVALID_ARGUMENT); ! 1451: ! 1452: switch (flavor) { ! 1453: ! 1454: case TASK_BASIC_INFO: ! 1455: { ! 1456: register task_basic_info_t basic_info; ! 1457: ! 1458: if (*task_info_count < TASK_BASIC_INFO_COUNT) { ! 1459: return(KERN_INVALID_ARGUMENT); ! 1460: } ! 1461: ! 1462: basic_info = (task_basic_info_t) task_info_out; ! 1463: ! 1464: map = (task == kernel_task) ? kernel_map : task->map; ! 1465: ! 1466: basic_info->virtual_size = map->size; ! 1467: basic_info->resident_size = pmap_resident_count(map->pmap) ! 1468: * PAGE_SIZE; ! 1469: ! 1470: task_lock(task); ! 1471: basic_info->policy = task->policy; ! 1472: basic_info->suspend_count = task->user_stop_count; ! 1473: basic_info->user_time.seconds ! 1474: = task->total_user_time.seconds; ! 1475: basic_info->user_time.microseconds ! 1476: = task->total_user_time.microseconds; ! 1477: basic_info->system_time.seconds ! 1478: = task->total_system_time.seconds; ! 1479: basic_info->system_time.microseconds ! 1480: = task->total_system_time.microseconds; ! 1481: task_unlock(task); ! 1482: ! 1483: *task_info_count = TASK_BASIC_INFO_COUNT; ! 1484: break; ! 1485: } ! 1486: ! 1487: case TASK_THREAD_TIMES_INFO: ! 1488: { ! 1489: register task_thread_times_info_t times_info; ! 1490: register thread_t thread; ! 1491: register thread_act_t thr_act; ! 1492: ! 1493: if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) { ! 1494: return (KERN_INVALID_ARGUMENT); ! 1495: } ! 1496: ! 1497: times_info = (task_thread_times_info_t) task_info_out; ! 1498: times_info->user_time.seconds = 0; ! 1499: times_info->user_time.microseconds = 0; ! 1500: times_info->system_time.seconds = 0; ! 1501: times_info->system_time.microseconds = 0; ! 1502: ! 1503: task_lock(task); ! 1504: queue_iterate(&task->thr_acts, thr_act, ! 1505: thread_act_t, thr_acts) ! 1506: { ! 1507: time_value_t user_time, system_time; ! 1508: spl_t s; ! 1509: ! 1510: thread = act_lock_thread(thr_act); ! 1511: ! 1512: /* Skip empty threads and threads that have migrated ! 1513: * into this task: ! 1514: */ ! 1515: if (thr_act->pool_port) { ! 1516: act_unlock_thread(thr_act); ! 1517: continue; ! 1518: } ! 1519: assert(thread); /* Must have thread, if no thread_pool*/ ! 1520: s = splsched(); ! 1521: thread_lock(thread); ! 1522: ! 1523: thread_read_times(thread, &user_time, &system_time); ! 1524: ! 1525: thread_unlock(thread); ! 1526: splx(s); ! 1527: act_unlock_thread(thr_act); ! 1528: ! 1529: time_value_add(×_info->user_time, &user_time); ! 1530: time_value_add(×_info->system_time, &system_time); ! 1531: } ! 1532: task_unlock(task); ! 1533: ! 1534: *task_info_count = TASK_THREAD_TIMES_INFO_COUNT; ! 1535: break; ! 1536: } ! 1537: ! 1538: case TASK_SCHED_FIFO_INFO: ! 1539: { ! 1540: register policy_fifo_base_t fifo_base; ! 1541: ! 1542: if (*task_info_count < POLICY_FIFO_BASE_COUNT) ! 1543: return(KERN_INVALID_ARGUMENT); ! 1544: ! 1545: fifo_base = (policy_fifo_base_t) task_info_out; ! 1546: ! 1547: task_lock(task); ! 1548: if (task->policy != POLICY_FIFO) { ! 1549: task_unlock(task); ! 1550: return(KERN_INVALID_POLICY); ! 1551: } ! 1552: /*** ??? fix me ***/ ! 1553: assert(task->sp_attributes != SP_ATTRIBUTES_NULL); ! 1554: fifo_base->base_priority = ! 1555: ((mk_sp_attributes_t)task->sp_attributes)->priority; ! 1556: task_unlock(task); ! 1557: ! 1558: *task_info_count = POLICY_FIFO_BASE_COUNT; ! 1559: break; ! 1560: } ! 1561: ! 1562: case TASK_SCHED_RR_INFO: ! 1563: { ! 1564: register policy_rr_base_t rr_base; ! 1565: ! 1566: if (*task_info_count < POLICY_RR_BASE_COUNT) ! 1567: return(KERN_INVALID_ARGUMENT); ! 1568: ! 1569: rr_base = (policy_rr_base_t) task_info_out; ! 1570: ! 1571: task_lock(task); ! 1572: if (task->policy != POLICY_RR) { ! 1573: task_unlock(task); ! 1574: return(KERN_INVALID_POLICY); ! 1575: } ! 1576: /*** ??? fix me ***/ ! 1577: assert(task->sp_attributes != SP_ATTRIBUTES_NULL); ! 1578: rr_base->base_priority = ! 1579: ((mk_sp_attributes_t)task->sp_attributes)->priority; ! 1580: rr_base->quantum = ! 1581: (((mk_sp_attributes_t)task->sp_attributes)->sched_data ! 1582: * tick) / 1000; ! 1583: task_unlock(task); ! 1584: ! 1585: *task_info_count = POLICY_RR_BASE_COUNT; ! 1586: break; ! 1587: } ! 1588: ! 1589: case TASK_SCHED_TIMESHARE_INFO: ! 1590: { ! 1591: register policy_timeshare_base_t ts_base; ! 1592: ! 1593: if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT) ! 1594: return(KERN_INVALID_ARGUMENT); ! 1595: ! 1596: ts_base = (policy_timeshare_base_t) task_info_out; ! 1597: ! 1598: task_lock(task); ! 1599: if (task->policy != POLICY_TIMESHARE) { ! 1600: task_unlock(task); ! 1601: return(KERN_INVALID_POLICY); ! 1602: } ! 1603: /*** ??? fix me ***/ ! 1604: assert(task->sp_attributes != SP_ATTRIBUTES_NULL); ! 1605: ts_base->base_priority = ! 1606: ((mk_sp_attributes_t)task->sp_attributes)->priority; ! 1607: task_unlock(task); ! 1608: ! 1609: *task_info_count = POLICY_TIMESHARE_BASE_COUNT; ! 1610: break; ! 1611: } ! 1612: ! 1613: case TASK_SECURITY_TOKEN: ! 1614: { ! 1615: register security_token_t *sec_token_p; ! 1616: ! 1617: if (*task_info_count < TASK_SECURITY_TOKEN_COUNT) { ! 1618: return(KERN_INVALID_ARGUMENT); ! 1619: } ! 1620: ! 1621: sec_token_p = (security_token_t *) task_info_out; ! 1622: ! 1623: task_lock(task); ! 1624: *sec_token_p = task->sec_token; ! 1625: task_unlock(task); ! 1626: ! 1627: *task_info_count = TASK_SECURITY_TOKEN_COUNT; ! 1628: break; ! 1629: } ! 1630: ! 1631: case TASK_SCHED_INFO: ! 1632: { ! 1633: int count = sched_policy[task->policy].sched_attributes_size; ! 1634: ! 1635: if (*task_info_count < (((count-1)/sizeof(int)) + 1)) ! 1636: return(KERN_INVALID_ARGUMENT); ! 1637: ! 1638: task_lock(task); ! 1639: ! 1640: bcopy((char *)task->sp_attributes, ! 1641: (char *)task_info_out, ! 1642: count); ! 1643: ! 1644: task_unlock(task); ! 1645: ! 1646: *task_info_count = count; ! 1647: break; ! 1648: } ! 1649: ! 1650: case TASK_EVENTS_INFO: ! 1651: { ! 1652: register task_events_info_t events_info; ! 1653: ! 1654: if (*task_info_count < TASK_EVENTS_INFO_COUNT) { ! 1655: return(KERN_INVALID_ARGUMENT); ! 1656: } ! 1657: ! 1658: events_info = (task_events_info_t) task_info_out; ! 1659: ! 1660: task_lock(task); ! 1661: events_info->faults = task->faults; ! 1662: events_info->pageins = task->pageins; ! 1663: events_info->cow_faults = task->cow_faults; ! 1664: events_info->messages_sent = task->messages_sent; ! 1665: events_info->messages_received = task->messages_received; ! 1666: events_info->syscalls_mach = task->syscalls_mach; ! 1667: events_info->syscalls_unix = task->syscalls_unix; ! 1668: events_info->csw = task->csw; ! 1669: task_unlock(task); ! 1670: ! 1671: *task_info_count = TASK_EVENTS_INFO_COUNT; ! 1672: break; ! 1673: } ! 1674: ! 1675: default: ! 1676: return (KERN_INVALID_ARGUMENT); ! 1677: } ! 1678: ! 1679: return(KERN_SUCCESS); ! 1680: } ! 1681: ! 1682: #if MACH_HOST ! 1683: ! 1684: /* ! 1685: * task_assign: ! 1686: * ! 1687: * Change the assigned processor set for the task ! 1688: */ ! 1689: kern_return_t ! 1690: task_assign( ! 1691: task_t task, ! 1692: processor_set_t new_pset, ! 1693: boolean_t assign_threads) ! 1694: { ! 1695: kern_return_t ret = KERN_SUCCESS; ! 1696: register thread_t thread, prev_thread; ! 1697: register queue_head_t *list; ! 1698: register processor_set_t pset; ! 1699: int max_priority; ! 1700: ! 1701: if (task == TASK_NULL || new_pset == PROCESSOR_SET_NULL) { ! 1702: return(KERN_INVALID_ARGUMENT); ! 1703: } ! 1704: ! 1705: task_lock(task); ! 1706: ! 1707: /* ! 1708: * If may_assign is false, task is already being assigned, ! 1709: * wait for that to finish. ! 1710: */ ! 1711: while (task->may_assign == FALSE) { ! 1712: task->assign_active = TRUE; ! 1713: assert_wait((event_t)&task->assign_active, THREAD_ABORTSAFE); ! 1714: task_unlock(task); ! 1715: thread_block((void (*)(void)) 0); ! 1716: task_lock(task); ! 1717: } ! 1718: ! 1719: /* ! 1720: * Do assignment. If new pset is dead, redirect to default. ! 1721: */ ! 1722: pset = task->processor_set; ! 1723: pset_lock(pset); ! 1724: pset_remove_task(pset,task); ! 1725: pset_unlock(pset); ! 1726: pset_deallocate(pset); ! 1727: ! 1728: pset_lock(new_pset); ! 1729: if (!new_pset->active) { ! 1730: pset_unlock(new_pset); ! 1731: new_pset = &default_pset; ! 1732: pset_lock(new_pset); ! 1733: } ! 1734: ! 1735: /* ! 1736: * Reset policy and priorities if needed. ! 1737: * ! 1738: * There are three rules for tasks under assignment: ! 1739: * ! 1740: * (1) If the new pset has the old policy enabled, keep the ! 1741: * old policy. Otherwise, use the default policy for the pset. ! 1742: * (2) The new limits will be the pset limits for the new policy. ! 1743: * (3) The new base will be the same as the old base unless either ! 1744: * (a) the new policy changed to the pset default policy; ! 1745: * in this case, the new base is the default policy ! 1746: * base, ! 1747: * or ! 1748: * (b) the new limits are different from the old limits; ! 1749: * in this case, the new base is the new limits. ! 1750: */ ! 1751: max_priority = pset_max_priority(new_pset, task->policy); ! 1752: if ((task->policy & new_pset->policies) == 0) { ! 1753: task->policy = new_pset->policy_default; ! 1754: task->sched_data = pset_sched_data(new_pset, task->policy); ! 1755: task->priority = pset_base_priority(new_pset, task->policy); ! 1756: max_priority = pset_max_priority(new_pset, task->policy); ! 1757: } ! 1758: else if (task->max_priority != max_priority) { ! 1759: task->priority = max_priority; ! 1760: } ! 1761: ! 1762: task->max_priority = max_priority; ! 1763: ! 1764: pset_add_task(new_pset,task); ! 1765: pset_unlock(new_pset); ! 1766: ! 1767: if (assign_threads == FALSE) { ! 1768: task_unlock(task); ! 1769: return(KERN_SUCCESS); ! 1770: } ! 1771: ! 1772: /* ! 1773: * Now freeze this assignment while we get the threads ! 1774: * to catch up to it. ! 1775: */ ! 1776: task->may_assign = FALSE; ! 1777: ! 1778: /* ! 1779: * If current thread is in task, freeze its assignment. ! 1780: */ ! 1781: if (current_act()->task == task) { ! 1782: task_unlock(task); ! 1783: thread_freeze(current_thread()); ! 1784: task_lock(task); ! 1785: } ! 1786: ! 1787: /* ! 1788: * Iterate down the thread list reassigning all the threads. ! 1789: * ("Base" threads only, please; psets belong to them) ! 1790: * New threads pick up task's new processor set automatically. ! 1791: * Do current thread last because new pset may be empty. ! 1792: */ ! 1793: { thread_act_t thr_act; ! 1794: int i; ! 1795: ! 1796: prev_thread = THREAD_NULL; ! 1797: for (i = 0, thr_act = (thread_act_t) queue_first(&task->thr_acts); ! 1798: i < task->thr_act_count; ! 1799: i++, thr_act = (thread_act_t)queue_next(&thr_act->thr_acts)) { ! 1800: ! 1801: thread = act_lock_thread(thr_act); ! 1802: if (thr_act->pool_port) { ! 1803: act_unlock_thread(thr_act); ! 1804: continue; ! 1805: } ! 1806: if (!(task->active)) { ! 1807: ret = KERN_FAILURE; ! 1808: act_unlock_thread(thr_act); ! 1809: break; ! 1810: } ! 1811: assert(thread); ! 1812: if (thread == current_thread()) ! 1813: act_unlock_thread(thr_act); ! 1814: else { ! 1815: thread_reference(thread); ! 1816: task_unlock(task); ! 1817: if (prev_thread != THREAD_NULL) ! 1818: thread_deallocate(prev_thread); /* may block */ ! 1819: assert(thread->top_act); ! 1820: assert(thread->top_act->thread == thread); ! 1821: /* ! 1822: * Inline thread_assign() here to avoid silly double ! 1823: * conversion. ! 1824: */ ! 1825: thread_freeze(thread); ! 1826: thread_doassign(thread, new_pset, TRUE); ! 1827: /* ! 1828: * All thread-related locks released at this point. ! 1829: */ ! 1830: prev_thread = thread; ! 1831: task_lock(task); ! 1832: } ! 1833: } ! 1834: assert(queue_end(&task->thr_acts, (queue_entry_t)thr_act)); ! 1835: } ! 1836: ! 1837: /* ! 1838: * Done, wakeup anyone waiting for us. ! 1839: */ ! 1840: task->may_assign = TRUE; ! 1841: if (task->assign_active) { ! 1842: task->assign_active = FALSE; ! 1843: thread_wakeup((event_t)&task->assign_active); ! 1844: } ! 1845: task_unlock(task); ! 1846: if (prev_thread != THREAD_NULL) ! 1847: thread_deallocate(prev_thread); /* may block */ ! 1848: ! 1849: /* ! 1850: * Finish assignment of current thread. ! 1851: */ ! 1852: if (current_act()->task == task) { ! 1853: thread = act_lock_thread(current_act()); ! 1854: thread_doassign(thread, new_pset, TRUE); ! 1855: /* ! 1856: * All thread-related locks released at this point. ! 1857: */ ! 1858: } ! 1859: ! 1860: return(ret); ! 1861: } ! 1862: #else /* MACH_HOST */ ! 1863: /* ! 1864: * task_assign: ! 1865: * ! 1866: * Change the assigned processor set for the task ! 1867: */ ! 1868: kern_return_t ! 1869: task_assign( ! 1870: task_t task, ! 1871: processor_set_t new_pset, ! 1872: boolean_t assign_threads) ! 1873: { ! 1874: #ifdef lint ! 1875: task++; new_pset++; assign_threads++; ! 1876: #endif /* lint */ ! 1877: return(KERN_FAILURE); ! 1878: } ! 1879: #endif /* MACH_HOST */ ! 1880: ! 1881: ! 1882: /* ! 1883: * task_assign_default: ! 1884: * ! 1885: * Version of task_assign to assign to default processor set. ! 1886: */ ! 1887: kern_return_t ! 1888: task_assign_default( ! 1889: task_t task, ! 1890: boolean_t assign_threads) ! 1891: { ! 1892: return (task_assign(task, &default_pset, assign_threads)); ! 1893: } ! 1894: ! 1895: /* ! 1896: * task_get_assignment ! 1897: * ! 1898: * Return name of processor set that task is assigned to. ! 1899: */ ! 1900: kern_return_t ! 1901: task_get_assignment( ! 1902: task_t task, ! 1903: processor_set_t *pset) ! 1904: { ! 1905: if (!task->active) ! 1906: return(KERN_FAILURE); ! 1907: ! 1908: *pset = task->processor_set; ! 1909: pset_reference(*pset); ! 1910: return(KERN_SUCCESS); ! 1911: } ! 1912: ! 1913: ! 1914: /* ! 1915: * task_policy ! 1916: * ! 1917: * Set scheduling policy and parameters, both base and limit, for ! 1918: * the given task. Policy must be a policy which is enabled for the ! 1919: * processor set. Change contained threads if requested. ! 1920: */ ! 1921: kern_return_t ! 1922: task_policy( ! 1923: task_t task, ! 1924: policy_t policy_id, ! 1925: policy_base_t base, ! 1926: mach_msg_type_number_t count, ! 1927: boolean_t set_limit, ! 1928: boolean_t change) ! 1929: { ! 1930: policy_limit_t limit; ! 1931: int limcount; ! 1932: processor_set_t pset; ! 1933: kern_return_t result = KERN_SUCCESS; ! 1934: sched_policy_t *policy; ! 1935: ! 1936: if ( task == TASK_NULL || ! 1937: (pset = task->processor_set) == PROCESSOR_SET_NULL ) ! 1938: return(KERN_INVALID_ARGUMENT); ! 1939: ! 1940: if (invalid_policy(policy_id) || (pset->policies & policy_id) == 0) ! 1941: return(KERN_INVALID_POLICY); ! 1942: ! 1943: /* call policy-specific routine */ ! 1944: policy = &sched_policy[policy_id]; ! 1945: result = policy->sp_ops. ! 1946: sp_task_policy(policy, task, policy_id, ! 1947: base, count, set_limit, change, &limit, &limcount); ! 1948: ! 1949: if (result != KERN_SUCCESS) ! 1950: return(result); ! 1951: ! 1952: result = task_set_policy(task, pset, policy_id, ! 1953: base, count, limit, limcount, change); ! 1954: ! 1955: return(result); ! 1956: } ! 1957: ! 1958: /* ! 1959: * task_set_policy ! 1960: * ! 1961: * Set scheduling policy and parameters, both base and limit, for ! 1962: * the given task. Policy can be any policy implemented by the ! 1963: * processor set, whether enabled or not. Change contained threads ! 1964: * if requested. ! 1965: */ ! 1966: kern_return_t ! 1967: task_set_policy( ! 1968: task_t task, ! 1969: processor_set_t pset, ! 1970: policy_t policy_id, ! 1971: policy_base_t base, ! 1972: mach_msg_type_number_t base_count, ! 1973: policy_limit_t limit, ! 1974: mach_msg_type_number_t limit_count, ! 1975: boolean_t change) ! 1976: { ! 1977: kern_return_t result = KERN_SUCCESS; ! 1978: sched_policy_t *policy; ! 1979: ! 1980: if (task == TASK_NULL || pset == PROCESSOR_SET_NULL) ! 1981: return(KERN_INVALID_ARGUMENT); ! 1982: ! 1983: if (pset != task->processor_set) ! 1984: return(KERN_FAILURE); ! 1985: ! 1986: task_lock(task); ! 1987: ! 1988: /* call policy-specific routine */ ! 1989: policy = &sched_policy[policy_id]; ! 1990: result = policy->sp_ops. ! 1991: sp_task_set_policy(policy, task, pset, policy_id, ! 1992: base, base_count, limit, limit_count, change); ! 1993: ! 1994: if (result != KERN_SUCCESS) { ! 1995: task_unlock(task); ! 1996: return(result); ! 1997: } ! 1998: ! 1999: if (change) { ! 2000: register thread_act_t thr_act; ! 2001: register queue_head_t *list; ! 2002: ! 2003: list = &task->thr_acts; ! 2004: thr_act = (thread_act_t) queue_first(list); ! 2005: while (!queue_end(list, (queue_entry_t) thr_act)) { ! 2006: /*** ??? fix to call policy-dependent routine ***/ ! 2007: thread_set_policy(thr_act, pset, policy_id, ! 2008: base, base_count, ! 2009: limit, limit_count); ! 2010: thr_act = (thread_act_t)queue_next(&thr_act->thr_acts); ! 2011: } ! 2012: } ! 2013: ! 2014: task_unlock(task); ! 2015: return(result); ! 2016: } ! 2017: ! 2018: /* ! 2019: * task_set_sched ! 2020: * ! 2021: * Set scheduling policy and parameters for the given task. ! 2022: * Policy must be a policy which is enabled for the ! 2023: * processor set. Change contained threads if requested. ! 2024: * (This should replace `task_policy()' with the addition ! 2025: * of the MK Scheduling Framework to the kernel.) ! 2026: */ ! 2027: kern_return_t ! 2028: task_set_sched( ! 2029: task_t task, ! 2030: policy_t policy_id, ! 2031: sched_attr_t sched_attr, ! 2032: mach_msg_type_number_t sched_attrCnt, ! 2033: boolean_t set_limit, ! 2034: boolean_t change) ! 2035: { ! 2036: processor_set_t pset; ! 2037: sched_policy_t *policy; ! 2038: ! 2039: if ( task == TASK_NULL || ! 2040: (pset = task->processor_set) == PROCESSOR_SET_NULL ) ! 2041: return(KERN_INVALID_ARGUMENT); ! 2042: ! 2043: if (invalid_policy(policy_id) || (pset->policies & policy_id) == 0) ! 2044: return(KERN_INVALID_POLICY); ! 2045: ! 2046: /* call policy-specific routine */ ! 2047: policy = &sched_policy[policy_id]; ! 2048: return (policy->sp_ops.sp_task_set_sched(policy, task, policy_id, ! 2049: sched_attr, sched_attrCnt, set_limit, change)); ! 2050: } ! 2051: ! 2052: ! 2053: /* ! 2054: * task_get_sched ! 2055: * ! 2056: * Get scheduling policy and parameters for the given task. ! 2057: * (This was added as part of the MK Scheduling Framework.) ! 2058: */ ! 2059: kern_return_t ! 2060: task_get_sched( ! 2061: task_t task, ! 2062: policy_t policy_id, ! 2063: sched_attr_t sched_attr, ! 2064: mach_msg_type_number_t sched_attrCnt, ! 2065: int sched_attr_size) ! 2066: { ! 2067: processor_set_t pset; ! 2068: sched_policy_t *policy; ! 2069: ! 2070: if ( task == TASK_NULL || ! 2071: (pset = task->processor_set) == PROCESSOR_SET_NULL ) ! 2072: return(KERN_INVALID_ARGUMENT); ! 2073: ! 2074: /* call policy-specific routine */ ! 2075: policy = &sched_policy[task->policy]; ! 2076: return (policy->sp_ops.sp_task_get_sched(policy, task, policy_id, ! 2077: sched_attr, sched_attrCnt, sched_attr_size)); ! 2078: } ! 2079: ! 2080: ! 2081: /* ! 2082: * task_collect_scan: ! 2083: * ! 2084: * Attempt to free resources owned by tasks. ! 2085: */ ! 2086: ! 2087: void ! 2088: task_collect_scan(void) ! 2089: { ! 2090: register task_t task, prev_task; ! 2091: processor_set_t pset, prev_pset; ! 2092: ! 2093: prev_task = TASK_NULL; ! 2094: prev_pset = PROCESSOR_SET_NULL; ! 2095: ! 2096: mutex_lock(&all_psets_lock); ! 2097: pset = (processor_set_t) queue_first(&all_psets); ! 2098: while (!queue_end(&all_psets, (queue_entry_t) pset)) { ! 2099: pset_lock(pset); ! 2100: task = (task_t) queue_first(&pset->tasks); ! 2101: while (!queue_end(&pset->tasks, (queue_entry_t) task)) { ! 2102: task_reference(task); ! 2103: pset->ref_count++; ! 2104: pset_unlock(pset); ! 2105: mutex_unlock(&all_psets_lock); ! 2106: ! 2107: pmap_collect(task->map->pmap); ! 2108: ! 2109: if (prev_task != TASK_NULL) ! 2110: task_deallocate(prev_task); ! 2111: prev_task = task; ! 2112: ! 2113: if (prev_pset != PROCESSOR_SET_NULL) ! 2114: pset_deallocate(prev_pset); ! 2115: prev_pset = pset; ! 2116: ! 2117: mutex_lock(&all_psets_lock); ! 2118: pset_lock(pset); ! 2119: task = (task_t) queue_next(&task->pset_tasks); ! 2120: } ! 2121: pset_unlock(pset); ! 2122: pset = (processor_set_t) queue_next(&pset->all_psets); ! 2123: } ! 2124: mutex_unlock(&all_psets_lock); ! 2125: ! 2126: if (prev_task != TASK_NULL) ! 2127: task_deallocate(prev_task); ! 2128: if (prev_pset != PROCESSOR_SET_NULL) ! 2129: pset_deallocate(prev_pset); ! 2130: } ! 2131: ! 2132: boolean_t task_collect_allowed = TRUE; ! 2133: unsigned task_collect_last_tick = 0; ! 2134: unsigned task_collect_max_rate = 0; /* in ticks */ ! 2135: ! 2136: /* ! 2137: * consider_task_collect: ! 2138: * ! 2139: * Called by the pageout daemon when the system needs more free pages. ! 2140: */ ! 2141: ! 2142: void ! 2143: consider_task_collect(void) ! 2144: { ! 2145: /* ! 2146: * By default, don't attempt task collection more frequently ! 2147: * than once a second (a scheduler tick). ! 2148: */ ! 2149: ! 2150: if (task_collect_max_rate == 0) ! 2151: task_collect_max_rate = 2; /* sched_tick is a 1 second resolution 2 here insures at least 1 second interval */ ! 2152: ! 2153: if (task_collect_allowed && ! 2154: (sched_tick > (task_collect_last_tick + task_collect_max_rate))) { ! 2155: task_collect_last_tick = sched_tick; ! 2156: task_collect_scan(); ! 2157: } ! 2158: } ! 2159: ! 2160: kern_return_t ! 2161: task_set_ras_pc( ! 2162: task_t task, ! 2163: vm_offset_t pc, ! 2164: vm_offset_t endpc) ! 2165: { ! 2166: #if FAST_TAS ! 2167: extern int fast_tas_debug; ! 2168: ! 2169: if (fast_tas_debug) { ! 2170: printf("task 0x%x: setting fast_tas to [0x%x, 0x%x]\n", ! 2171: task, pc, endpc); ! 2172: } ! 2173: task_lock(task); ! 2174: task->fast_tas_base = pc; ! 2175: task->fast_tas_end = endpc; ! 2176: task_unlock(task); ! 2177: return KERN_SUCCESS; ! 2178: ! 2179: #else /* FAST_TAS */ ! 2180: #ifdef lint ! 2181: task++; ! 2182: pc++; ! 2183: endpc++; ! 2184: #endif /* lint */ ! 2185: ! 2186: return KERN_FAILURE; ! 2187: ! 2188: #endif /* FAST_TAS */ ! 2189: } ! 2190: ! 2191: void ! 2192: task_synchronizer_destroy_all(task_t task) ! 2193: { ! 2194: semaphore_t semaphore; ! 2195: lock_set_t lock_set; ! 2196: ! 2197: /* ! 2198: * Destroy owned semaphores ! 2199: */ ! 2200: ! 2201: while (!queue_empty(&task->semaphore_list)) { ! 2202: semaphore = (semaphore_t) queue_first(&task->semaphore_list); ! 2203: (void) semaphore_destroy(task, semaphore); ! 2204: } ! 2205: ! 2206: /* ! 2207: * Destroy owned lock sets ! 2208: */ ! 2209: ! 2210: while (!queue_empty(&task->lock_set_list)) { ! 2211: lock_set = (lock_set_t) queue_first(&task->lock_set_list); ! 2212: (void) lock_set_destroy(task, lock_set); ! 2213: } ! 2214: } ! 2215: ! 2216: void ! 2217: task_subsystem_destroy_all(task_t task) ! 2218: { ! 2219: subsystem_t subsystem; ! 2220: ! 2221: /* ! 2222: * Destroy owned subsystems ! 2223: */ ! 2224: ! 2225: while (!queue_empty(&task->subsystem_list)) { ! 2226: subsystem = (subsystem_t) queue_first(&task->subsystem_list); ! 2227: subsystem_deallocate(subsystem); ! 2228: } ! 2229: } ! 2230: ! 2231: /* ! 2232: * task_set_port_space: ! 2233: * ! 2234: * Set port name space of task to specified size. ! 2235: */ ! 2236: ! 2237: kern_return_t ! 2238: task_set_port_space( ! 2239: task_t task, ! 2240: int table_entries) ! 2241: { ! 2242: kern_return_t kr; ! 2243: ! 2244: is_write_lock(task->itk_space); ! 2245: kr = ipc_entry_grow_table(task->itk_space, table_entries); ! 2246: if (kr == KERN_SUCCESS) ! 2247: is_write_unlock(task->itk_space); ! 2248: return kr; ! 2249: } ! 2250: ! 2251: /* ! 2252: * We need to export some functions to other components that ! 2253: * are currently implemented in macros within the osfmk ! 2254: * component. Just export them as functions of the same name. ! 2255: */ ! 2256: boolean_t is_kerneltask(task_t t) ! 2257: { ! 2258: if (t == kernel_task) ! 2259: return(TRUE); ! 2260: else ! 2261: return((t->kernel_loaded)); ! 2262: } ! 2263: ! 2264: #undef current_task ! 2265: task_t current_task() ! 2266: { ! 2267: return (current_task_fast()); ! 2268: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.