2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * @OSF_FREE_COPYRIGHT@
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
28 * All Rights Reserved.
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.
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.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
52 * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub,
55 * Task management primitives implementation.
58 * Copyright (c) 1993 The University of Utah and
59 * the Computer Systems Laboratory (CSL). All rights reserved.
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.
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.
71 * CSL requests users of this software to return to csl-dist@cs.utah.edu any
72 * improvements that they make and grant CSL redistribution rights.
77 #include <mach_host.h>
78 #include <mach_prof.h>
80 #include <task_swapper.h>
81 #include <platforms.h>
83 #include <mach/boolean.h>
84 #include <mach/machine/vm_types.h>
85 #include <mach/vm_param.h>
86 #include <mach/semaphore.h>
87 #include <mach/task_info.h>
88 #include <mach/task_special_ports.h>
89 #include <mach/mach_types.h>
90 #include <mach/machine/rpc.h>
91 #include <ipc/ipc_space.h>
92 #include <ipc/ipc_entry.h>
93 #include <kern/mach_param.h>
94 #include <kern/misc_protos.h>
95 #include <kern/task.h>
96 #include <kern/thread.h>
97 #include <kern/zalloc.h>
98 #include <kern/kalloc.h>
99 #include <kern/processor.h>
100 #include <kern/sched_prim.h> /* for thread_wakeup */
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>
111 #include <ddb/db_sym.h>
112 #endif /* MACH_KDB */
115 #include <kern/task_swap.h>
116 #endif /* TASK_SWAPPER */
119 * Exported interfaces
122 #include <mach/task_server.h>
123 #include <mach/mach_host_server.h>
124 #include <mach/host_security_server.h>
131 void task_hold_locked(
133 void task_wait_locked(
135 void task_release_locked(
137 void task_collect_scan(void);
140 void task_synchronizer_destroy_all(
142 void task_subsystem_destroy_all(
145 kern_return_t
task_set_ledger(
155 TASK_MAX
* sizeof(struct task
),
156 TASK_CHUNK
* sizeof(struct task
),
162 * Create the kernel task as the first task.
163 * Task_create_local must assign to kernel_task as a side effect,
164 * for other initialization. (:-()
166 if (task_create_local(
167 TASK_NULL
, FALSE
, FALSE
, &kernel_task
) != KERN_SUCCESS
)
168 panic("task_init\n");
169 vm_map_deallocate(kernel_task
->map
);
170 kernel_task
->map
= kernel_map
;
173 if (watchacts
& WA_TASK
)
174 printf("task_init: kernel_task = %x map=%x\n",
175 kernel_task
, kernel_map
);
176 #endif /* MACH_ASSERT */
186 * If may_assign is false, task is already being assigned,
187 * wait for that to finish.
189 while (task
->may_assign
== FALSE
) {
190 task
->assign_active
= TRUE
;
191 thread_sleep_mutex((event_t
) &task
->assign_active
,
192 &task
->lock
, THREAD_INTERRUPTIBLE
);
195 task
->may_assign
= FALSE
;
206 assert(task
->may_assign
== FALSE
);
207 task
->may_assign
= TRUE
;
208 if (task
->assign_active
== TRUE
) {
209 task
->assign_active
= FALSE
;
210 thread_wakeup((event_t
)&task
->assign_active
);
216 #endif /* MACH_HOST */
219 * Create a task running in the kernel address space. It may
220 * have its own map of size mem_size and may have ipc privileges.
225 vm_offset_t map_base
,
229 kern_return_t result
;
236 result
= task_create_local(parent_task
, FALSE
, TRUE
, &new_task
);
237 if (result
!= KERN_SUCCESS
)
241 * Task_create_local creates the task with a user-space map.
242 * We attempt to replace the map and free it afterwards; else
243 * task_deallocate will free it (can NOT set map to null before
244 * task_deallocate, this impersonates a norma placeholder task).
245 * _Mark the memory as pageable_ -- this is what we
246 * want for images (like servers) loaded into the kernel.
249 vm_map_deallocate(new_task
->map
);
250 new_task
->map
= kernel_map
;
251 *child_task
= new_task
;
253 old_map
= new_task
->map
;
254 if ((result
= kmem_suballoc(kernel_map
, &map_base
,
255 map_size
, TRUE
, FALSE
,
256 &new_task
->map
)) != KERN_SUCCESS
) {
258 * New task created with ref count of 2 -- decrement by
259 * one to force task deletion.
261 printf("kmem_suballoc(%x,%x,%x,1,0,&new) Fails\n",
262 kernel_map
, map_base
, map_size
);
263 --new_task
->ref_count
;
264 task_deallocate(new_task
);
267 vm_map_deallocate(old_map
);
268 *child_task
= new_task
;
270 return (KERN_SUCCESS
);
276 ledger_port_array_t ledger_ports
,
277 mach_msg_type_number_t num_ledger_ports
,
278 boolean_t inherit_memory
,
279 task_t
*child_task
) /* OUT */
281 if (parent_task
== TASK_NULL
)
282 return(KERN_INVALID_ARGUMENT
);
284 return task_create_local(
285 parent_task
, inherit_memory
, FALSE
, child_task
);
289 host_security_create_task_token(
290 host_security_t host_security
,
292 security_token_t sec_token
,
293 host_priv_t host_priv
,
294 ledger_port_array_t ledger_ports
,
295 mach_msg_type_number_t num_ledger_ports
,
296 boolean_t inherit_memory
,
297 task_t
*child_task
) /* OUT */
299 kern_return_t result
;
301 if (parent_task
== TASK_NULL
)
302 return(KERN_INVALID_ARGUMENT
);
304 if (host_security
== HOST_NULL
)
305 return(KERN_INVALID_SECURITY
);
307 result
= task_create_local(
308 parent_task
, inherit_memory
, FALSE
, child_task
);
310 if (result
!= KERN_SUCCESS
)
313 result
= host_security_set_task_token(host_security
,
318 if (result
!= KERN_SUCCESS
)
327 boolean_t inherit_memory
,
328 boolean_t kernel_loaded
,
329 task_t
*child_task
) /* OUT */
332 processor_set_t pset
;
334 new_task
= (task_t
) zalloc(task_zone
);
336 if (new_task
== TASK_NULL
)
337 return(KERN_RESOURCE_SHORTAGE
);
339 /* one ref for just being alive; one for our caller */
340 new_task
->ref_count
= 2;
343 new_task
->map
= vm_map_fork(parent_task
->map
);
345 new_task
->map
= vm_map_create(pmap_create(0),
346 round_page(VM_MIN_ADDRESS
),
347 trunc_page(VM_MAX_ADDRESS
), TRUE
);
349 mutex_init(&new_task
->lock
, ETAP_THREAD_TASK_NEW
);
350 queue_init(&new_task
->subsystem_list
);
351 queue_init(&new_task
->thr_acts
);
352 new_task
->suspend_count
= 0;
353 new_task
->thr_act_count
= 0;
354 new_task
->res_act_count
= 0;
355 new_task
->active_act_count
= 0;
356 new_task
->user_stop_count
= 0;
357 new_task
->importance
= 0;
358 new_task
->active
= TRUE
;
359 new_task
->kernel_loaded
= kernel_loaded
;
360 new_task
->user_data
= 0;
361 new_task
->faults
= 0;
362 new_task
->cow_faults
= 0;
363 new_task
->pageins
= 0;
364 new_task
->messages_sent
= 0;
365 new_task
->messages_received
= 0;
366 new_task
->syscalls_mach
= 0;
367 new_task
->syscalls_unix
=0;
371 new_task
->bsd_info
= 0;
372 #endif /* MACH_BSD */
375 new_task
->swap_state
= TASK_SW_IN
;
376 new_task
->swap_flags
= 0;
377 new_task
->swap_ast_waiting
= 0;
378 new_task
->swap_stamp
= sched_tick
;
379 new_task
->swap_rss
= 0;
380 new_task
->swap_nswap
= 0;
381 #endif /* TASK_SWAPPER */
383 queue_init(&new_task
->semaphore_list
);
384 queue_init(&new_task
->lock_set_list
);
385 new_task
->semaphores_owned
= 0;
386 new_task
->lock_sets_owned
= 0;
389 new_task
->may_assign
= TRUE
;
390 new_task
->assign_active
= FALSE
;
391 #endif /* MACH_HOST */
392 eml_task_reference(new_task
, parent_task
);
394 ipc_task_init(new_task
, parent_task
);
396 new_task
->total_user_time
.seconds
= 0;
397 new_task
->total_user_time
.microseconds
= 0;
398 new_task
->total_system_time
.seconds
= 0;
399 new_task
->total_system_time
.microseconds
= 0;
401 task_prof_init(new_task
);
403 if (parent_task
!= TASK_NULL
) {
406 * Freeze the parent, so that parent_task->processor_set
409 task_freeze(parent_task
);
410 #endif /* MACH_HOST */
411 pset
= parent_task
->processor_set
;
413 pset
= &default_pset
;
415 new_task
->policy
= parent_task
->policy
;
417 new_task
->priority
= parent_task
->priority
;
418 new_task
->max_priority
= parent_task
->max_priority
;
420 new_task
->sec_token
= parent_task
->sec_token
;
422 shared_region_mapping_ref(parent_task
->system_shared_region
);
423 new_task
->system_shared_region
= parent_task
->system_shared_region
;
425 new_task
->wired_ledger_port
= ledger_copy(
426 convert_port_to_ledger(parent_task
->wired_ledger_port
));
427 new_task
->paged_ledger_port
= ledger_copy(
428 convert_port_to_ledger(parent_task
->paged_ledger_port
));
431 pset
= &default_pset
;
433 if (kernel_task
== TASK_NULL
) {
434 new_task
->policy
= POLICY_RR
;
436 new_task
->priority
= MINPRI_KERNBAND
;
437 new_task
->max_priority
= MAXPRI_KERNBAND
;
440 new_task
->policy
= POLICY_TIMESHARE
;
442 new_task
->priority
= BASEPRI_DEFAULT
;
443 new_task
->max_priority
= MAXPRI_HIGHBAND
;
446 new_task
->sec_token
= KERNEL_SECURITY_TOKEN
;
447 new_task
->wired_ledger_port
= ledger_copy(root_wired_ledger
);
448 new_task
->paged_ledger_port
= ledger_copy(root_paged_ledger
);
452 pset_add_task(pset
, new_task
);
455 if (parent_task
!= TASK_NULL
)
456 task_unfreeze(parent_task
);
457 #endif /* MACH_HOST */
460 if (inherit_memory
) {
461 new_task
->fast_tas_base
= parent_task
->fast_tas_base
;
462 new_task
->fast_tas_end
= parent_task
->fast_tas_end
;
464 new_task
->fast_tas_base
= (vm_offset_t
)0;
465 new_task
->fast_tas_end
= (vm_offset_t
)0;
467 #endif /* FAST_TAS */
469 ipc_task_enable(new_task
);
472 task_swapout_eligible(new_task
);
473 #endif /* TASK_SWAPPER */
476 if (watchacts
& WA_TASK
)
477 printf("*** task_create_local(par=%x inh=%x) == 0x%x\n",
478 parent_task
, inherit_memory
, new_task
);
479 #endif /* MACH_ASSERT */
481 *child_task
= new_task
;
482 return(KERN_SUCCESS
);
488 * Called by task_deallocate when the task's reference count drops to zero.
495 processor_set_t pset
;
499 if (watchacts
& (WA_EXIT
|WA_TASK
))
500 printf("task_free(%x(%d)) map ref %d\n", task
, task
->ref_count
,
501 task
->map
->ref_count
);
502 #endif /* MACH_ASSERT */
505 /* task_terminate guarantees that this task is off the list */
506 assert((task
->swap_state
& TASK_SW_ELIGIBLE
) == 0);
507 #endif /* TASK_SWAPPER */
509 eml_task_deallocate(task
);
512 * Temporarily restore the reference we dropped above, then
513 * freeze the task so that the task->processor_set field
514 * cannot change. In the !MACH_HOST case, the logic can be
515 * simplified, since the default_pset is the only pset.
521 #endif /* MACH_HOST */
523 pset
= task
->processor_set
;
526 if (--task
->ref_count
> 0) {
528 * A new reference appeared (probably from the pset).
529 * Back out. Must unfreeze inline since we'already
530 * dropped our reference.
533 assert(task
->may_assign
== FALSE
);
534 task
->may_assign
= TRUE
;
535 if (task
->assign_active
== TRUE
) {
536 task
->assign_active
= FALSE
;
537 thread_wakeup((event_t
)&task
->assign_active
);
539 #endif /* MACH_HOST */
544 pset_remove_task(pset
,task
);
547 pset_deallocate(pset
);
549 ipc_task_terminate(task
);
550 shared_region_mapping_dealloc(task
->system_shared_region
);
552 if (task
->kernel_loaded
)
553 vm_map_remove(kernel_map
, task
->map
->min_offset
,
554 task
->map
->max_offset
, VM_MAP_NO_FLAGS
);
555 vm_map_deallocate(task
->map
);
556 is_release(task
->itk_space
);
557 task_prof_deallocate(task
);
558 zfree(task_zone
, (vm_offset_t
) task
);
565 if (task
!= TASK_NULL
) {
569 c
= --task
->ref_count
;
571 task_free(task
); /* unlocks task */
581 if (task
!= TASK_NULL
) {
592 if (task
!= TASK_NULL
) {
593 if (task_lock_try(task
)) {
605 * Terminate the specified task. See comments on thread_terminate
606 * (kern/thread.c) about problems with terminating the "current task."
613 if (task
== TASK_NULL
)
614 return(KERN_INVALID_ARGUMENT
);
616 return(KERN_FAILURE
);
617 return (task_terminate_internal(task
));
621 task_terminate_internal(
624 thread_act_t thr_act
, cur_thr_act
;
627 boolean_t interrupt_save
;
629 assert(task
!= kernel_task
);
631 cur_thr_act
= current_act();
632 cur_task
= cur_thr_act
->task
;
636 * If task is not resident (swapped out, or being swapped
637 * out), we want to bring it back in (this can block).
638 * NOTE: The only way that this can happen in the current
639 * system is if the task is swapped while it has a thread
640 * in exit(), and the thread does not hit a clean point
641 * to swap itself before getting here.
642 * Terminating other tasks is another way to this code, but
643 * it is not yet fully supported.
644 * The task_swapin is unconditional. It used to be done
645 * only if the task is not resident. Swapping in a
646 * resident task will prevent it from being swapped out
647 * while it terminates.
649 task_swapin(task
, TRUE
); /* TRUE means make it unswappable */
650 #endif /* TASK_SWAPPER */
653 * Get the task locked and make sure that we are not racing
654 * with someone else trying to terminate us.
656 if (task
== cur_task
) {
658 } else if (task
< cur_task
) {
666 if (!task
->active
|| !cur_thr_act
->active
) {
668 * Task or current act is already being terminated.
669 * Just return an error. If we are dying, this will
670 * just get us to our AST special handler and that
671 * will get us to finalize the termination of ourselves.
674 if (cur_task
!= task
)
675 task_unlock(cur_task
);
676 return(KERN_FAILURE
);
678 if (cur_task
!= task
)
679 task_unlock(cur_task
);
682 * Make sure the current thread does not get aborted out of
683 * the waits inside these operations.
685 cur_thread
= current_thread();
686 interrupt_save
= cur_thread
->interruptible
;
687 cur_thread
->interruptible
= FALSE
;
690 * Indicate that we want all the threads to stop executing
691 * at user space by holding the task (we would have held
692 * each thread independently in thread_terminate_internal -
693 * but this way we may be more likely to already find it
694 * held there). Mark the task inactive, and prevent
695 * further task operations via the task port.
697 task_hold_locked(task
);
698 task
->active
= FALSE
;
699 ipc_task_disable(task
);
702 * Terminate each activation in the task.
704 * Each terminated activation will run it's special handler
705 * when its current kernel context is unwound. That will
706 * clean up most of the thread resources. Then it will be
707 * handed over to the reaper, who will finally remove the
708 * thread from the task list and free the structures.
710 queue_iterate(&task
->thr_acts
, thr_act
, thread_act_t
, thr_acts
) {
711 thread_terminate_internal(thr_act
);
715 * Clean up any virtual machine state/resources associated
716 * with the current activation because it may hold wiring
717 * and other references on resources we will be trying to
720 if (cur_thr_act
->task
== task
)
721 act_virtual_machine_destroy(cur_thr_act
);
726 * Destroy all synchronizers owned by the task.
728 task_synchronizer_destroy_all(task
);
731 * Deallocate all subsystems owned by the task.
733 task_subsystem_destroy_all(task
);
736 * Destroy the IPC space, leaving just a reference for it.
738 if (!task
->kernel_loaded
)
739 ipc_space_destroy(task
->itk_space
);
742 * If the current thread is a member of the task
743 * being terminated, then the last reference to
744 * the task will not be dropped until the thread
745 * is finally reaped. To avoid incurring the
746 * expense of removing the address space regions
747 * at reap time, we do it explictly here.
749 (void) vm_map_remove(task
->map
,
750 task
->map
->min_offset
,
751 task
->map
->max_offset
, VM_MAP_NO_FLAGS
);
754 * We no longer need to guard against being aborted, so restore
755 * the previous interruptible state.
757 cur_thread
->interruptible
= interrupt_save
;
760 * Get rid of the task active reference on itself.
762 task_deallocate(task
);
764 return(KERN_SUCCESS
);
768 * task_halt - Shut the current task down (except for the current thread) in
769 * preparation for dramatic changes to the task (probably exec).
770 * We hold the task, terminate all other threads in the task and
771 * wait for them to terminate, clean up the portspace, and when
772 * all done, let the current thread go.
778 thread_act_t thr_act
, cur_thr_act
;
781 assert(task
!= kernel_task
);
783 cur_thr_act
= current_act();
784 cur_task
= cur_thr_act
->task
;
786 if (task
!= cur_task
) {
787 return(KERN_INVALID_ARGUMENT
);
792 * If task is not resident (swapped out, or being swapped
793 * out), we want to bring it back in and make it unswappable.
794 * This can block, so do it early.
796 task_swapin(task
, TRUE
); /* TRUE means make it unswappable */
797 #endif /* TASK_SWAPPER */
801 if (!task
->active
|| !cur_thr_act
->active
) {
803 * Task or current thread is already being terminated.
804 * Hurry up and return out of the current kernel context
805 * so that we run our AST special handler to terminate
809 return(KERN_FAILURE
);
812 if (task
->thr_act_count
> 1) {
814 * Mark all the threads to keep them from starting any more
815 * user-level execution. The thread_terminate_internal code
816 * would do this on a thread by thread basis anyway, but this
817 * gives us a better chance of not having to wait there.
819 task_hold_locked(task
);
822 * Terminate all the other activations in the task.
824 * Each terminated activation will run it's special handler
825 * when its current kernel context is unwound. That will
826 * clean up most of the thread resources. Then it will be
827 * handed over to the reaper, who will finally remove the
828 * thread from the task list and free the structures.
830 queue_iterate(&task
->thr_acts
, thr_act
, thread_act_t
,thr_acts
) {
831 if (thr_act
!= cur_thr_act
)
832 thread_terminate_internal(thr_act
);
834 task_release_locked(task
);
838 * If the current thread has any virtual machine state
839 * associated with it, we need to explicitly clean that
840 * up now (because we did not terminate the current act)
841 * before we try to clean up the task VM and port spaces.
843 act_virtual_machine_destroy(cur_thr_act
);
848 * Destroy all synchronizers owned by the task.
850 task_synchronizer_destroy_all(task
);
853 * Deallocate all subsystems owned by the task.
855 task_subsystem_destroy_all(task
);
859 * Destroy the IPC space, leaving just a reference for it.
862 * Lookupd will break if we enable this cleaning, because it
863 * uses a slimey trick that depends upon the portspace not
864 * being cleaned up across exec (it passes the lookupd server
865 * port to the child after a restart using knowledge of this
866 * bug in past implementations). We need to fix lookupd to
867 * keep from leaking ports across exec.
869 if (!task
->kernel_loaded
)
870 ipc_space_clean(task
->itk_space
);
874 * Clean out the address space, as we are going to be
877 (void) vm_map_remove(task
->map
,
878 task
->map
->min_offset
,
879 task
->map
->max_offset
, VM_MAP_NO_FLAGS
);
887 * Suspend execution of the specified task.
888 * This is a recursive-style suspension of the task, a count of
889 * suspends is maintained.
891 * CONDITIONS: the task is locked and active.
895 register task_t task
)
897 register thread_act_t thr_act
;
899 assert(task
->active
);
901 task
->suspend_count
++;
904 * Iterate through all the thread_act's and hold them.
906 queue_iterate(&task
->thr_acts
, thr_act
, thread_act_t
, thr_acts
) {
907 act_lock_thread(thr_act
);
908 thread_hold(thr_act
);
909 act_unlock_thread(thr_act
);
916 * Same as the internal routine above, except that is must lock
917 * and verify that the task is active. This differs from task_suspend
918 * in that it places a kernel hold on the task rather than just a
919 * user-level hold. This keeps users from over resuming and setting
920 * it running out from under the kernel.
922 * CONDITIONS: the caller holds a reference on the task
925 task_hold(task_t task
)
929 if (task
== TASK_NULL
)
930 return (KERN_INVALID_ARGUMENT
);
934 return (KERN_FAILURE
);
936 task_hold_locked(task
);
939 return(KERN_SUCCESS
);
943 * Routine: task_wait_locked
944 * Wait for all threads in task to stop.
947 * Called with task locked, active, and held.
951 register task_t task
)
953 register thread_act_t thr_act
, cur_thr_act
;
955 assert(task
->active
);
956 assert(task
->suspend_count
> 0);
958 cur_thr_act
= current_act();
960 * Iterate through all the thread's and wait for them to
961 * stop. Do not wait for the current thread if it is within
964 queue_iterate(&task
->thr_acts
, thr_act
, thread_act_t
, thr_acts
) {
965 if (thr_act
!= cur_thr_act
) {
966 thread_shuttle_t thr_shuttle
;
968 thr_shuttle
= act_lock_thread(thr_act
);
969 thread_wait(thr_shuttle
);
970 act_unlock_thread(thr_act
);
976 * task_release_locked:
978 * Release a kernel hold on a task.
980 * CONDITIONS: the task is locked and active
984 register task_t task
)
986 register thread_act_t thr_act
;
988 assert(task
->active
);
990 task
->suspend_count
--;
991 assert(task
->suspend_count
>= 0);
994 * Iterate through all the thread_act's and hold them.
995 * Do not hold the current thread_act if it is within the
998 queue_iterate(&task
->thr_acts
, thr_act
, thread_act_t
, thr_acts
) {
999 act_lock_thread(thr_act
);
1000 thread_release(thr_act
);
1001 act_unlock_thread(thr_act
);
1008 * Same as the internal routine above, except that it must lock
1009 * and verify that the task is active.
1011 * CONDITIONS: The caller holds a reference to the task
1014 task_release(task_t task
)
1018 if (task
== TASK_NULL
)
1019 return (KERN_INVALID_ARGUMENT
);
1021 if (!task
->active
) {
1023 return (KERN_FAILURE
);
1025 task_release_locked(task
);
1028 return(KERN_SUCCESS
);
1034 thread_act_array_t
*thr_act_list
,
1035 mach_msg_type_number_t
*count
)
1037 unsigned int actual
; /* this many thr_acts */
1038 thread_act_t thr_act
;
1039 thread_act_t
*thr_acts
;
1043 vm_size_t size
, size_needed
;
1046 if (task
== TASK_NULL
)
1047 return KERN_INVALID_ARGUMENT
;
1053 if (!task
->active
) {
1057 return KERN_FAILURE
;
1060 actual
= task
->thr_act_count
;
1062 /* do we have the memory we need? */
1063 size_needed
= actual
* sizeof(mach_port_t
);
1064 if (size_needed
<= size
)
1067 /* unlock the task and allocate more memory */
1073 assert(size_needed
> 0);
1076 addr
= kalloc(size
);
1078 return KERN_RESOURCE_SHORTAGE
;
1081 /* OK, have memory and the task is locked & active */
1082 thr_acts
= (thread_act_t
*) addr
;
1084 for (i
= j
= 0, thr_act
= (thread_act_t
) queue_first(&task
->thr_acts
);
1086 i
++, thr_act
= (thread_act_t
) queue_next(&thr_act
->thr_acts
)) {
1088 if (thr_act
->ref_count
> 0) {
1089 act_locked_act_reference(thr_act
);
1090 thr_acts
[j
++] = thr_act
;
1092 act_unlock(thr_act
);
1094 assert(queue_end(&task
->thr_acts
, (queue_entry_t
) thr_act
));
1097 size_needed
= actual
* sizeof(mach_port_t
);
1099 /* can unlock task now that we've got the thr_act refs */
1103 /* no thr_acts, so return null pointer and deallocate memory */
1111 /* if we allocated too much, must copy */
1113 if (size_needed
< size
) {
1114 vm_offset_t newaddr
;
1116 newaddr
= kalloc(size_needed
);
1118 for (i
= 0; i
< actual
; i
++)
1119 act_deallocate(thr_acts
[i
]);
1121 return KERN_RESOURCE_SHORTAGE
;
1124 bcopy((char *) addr
, (char *) newaddr
, size_needed
);
1126 thr_acts
= (thread_act_t
*) newaddr
;
1129 *thr_act_list
= thr_acts
;
1132 /* do the conversion that Mig should handle */
1134 for (i
= 0; i
< actual
; i
++)
1135 ((ipc_port_t
*) thr_acts
)[i
] =
1136 convert_act_to_port(thr_acts
[i
]);
1139 return KERN_SUCCESS
;
1143 * Routine: task_suspend
1144 * Implement a user-level suspension on a task.
1147 * The caller holds a reference to the task
1151 register task_t task
)
1153 if (task
== TASK_NULL
)
1154 return (KERN_INVALID_ARGUMENT
);
1157 if (!task
->active
) {
1159 return (KERN_FAILURE
);
1161 if ((task
->user_stop_count
)++ > 0) {
1163 * If the stop count was positive, the task is
1164 * already stopped and we can exit.
1167 return (KERN_SUCCESS
);
1171 * Put a kernel-level hold on the threads in the task (all
1172 * user-level task suspensions added together represent a
1173 * single kernel-level hold). We then wait for the threads
1174 * to stop executing user code.
1176 task_hold_locked(task
);
1177 task_wait_locked(task
);
1179 return (KERN_SUCCESS
);
1183 * Routine: task_resume
1184 * Release a kernel hold on a task.
1187 * The caller holds a reference to the task
1190 task_resume(register task_t task
)
1192 register boolean_t release
;
1194 if (task
== TASK_NULL
)
1195 return(KERN_INVALID_ARGUMENT
);
1199 if (!task
->active
) {
1201 return(KERN_FAILURE
);
1203 if (task
->user_stop_count
> 0) {
1204 if (--(task
->user_stop_count
) == 0)
1209 return(KERN_FAILURE
);
1213 * Release the task if necessary.
1216 task_release_locked(task
);
1219 return(KERN_SUCCESS
);
1223 host_security_set_task_token(
1224 host_security_t host_security
,
1226 security_token_t sec_token
,
1227 host_priv_t host_priv
)
1231 if (task
== TASK_NULL
)
1232 return(KERN_INVALID_ARGUMENT
);
1234 if (host_security
== HOST_NULL
)
1235 return(KERN_INVALID_SECURITY
);
1238 task
->sec_token
= sec_token
;
1241 if (host_priv
!= HOST_PRIV_NULL
) {
1242 kr
= task_set_special_port(task
,
1244 ipc_port_make_send(realhost
.host_priv_self
));
1246 kr
= task_set_special_port(task
,
1248 ipc_port_make_send(realhost
.host_self
));
1254 * Utility routine to set a ledger
1262 if (task
== TASK_NULL
)
1263 return(KERN_INVALID_ARGUMENT
);
1267 ipc_port_release_send(task
->wired_ledger_port
);
1268 task
->wired_ledger_port
= ledger_copy(wired
);
1271 ipc_port_release_send(task
->paged_ledger_port
);
1272 task
->paged_ledger_port
= ledger_copy(paged
);
1276 return(KERN_SUCCESS
);
1280 * This routine was added, pretty much exclusively, for registering the
1281 * RPC glue vector for in-kernel short circuited tasks. Rather than
1282 * removing it completely, I have only disabled that feature (which was
1283 * the only feature at the time). It just appears that we are going to
1284 * want to add some user data to tasks in the future (i.e. bsd info,
1285 * task names, etc...), so I left it in the formal task interface.
1290 task_flavor_t flavor
,
1291 task_info_t task_info_in
, /* pointer to IN array */
1292 mach_msg_type_number_t task_info_count
)
1296 if (task
== TASK_NULL
)
1297 return(KERN_INVALID_ARGUMENT
);
1301 return (KERN_INVALID_ARGUMENT
);
1303 return (KERN_SUCCESS
);
1309 task_flavor_t flavor
,
1310 task_info_t task_info_out
,
1311 mach_msg_type_number_t
*task_info_count
)
1316 if (task
== TASK_NULL
)
1317 return(KERN_INVALID_ARGUMENT
);
1321 case TASK_BASIC_INFO
:
1323 register task_basic_info_t basic_info
;
1325 if (*task_info_count
< TASK_BASIC_INFO_COUNT
) {
1326 return(KERN_INVALID_ARGUMENT
);
1329 basic_info
= (task_basic_info_t
) task_info_out
;
1331 map
= (task
== kernel_task
) ? kernel_map
: task
->map
;
1333 basic_info
->virtual_size
= map
->size
;
1334 basic_info
->resident_size
= pmap_resident_count(map
->pmap
)
1338 basic_info
->policy
= task
->policy
;
1339 basic_info
->suspend_count
= task
->user_stop_count
;
1340 basic_info
->user_time
.seconds
1341 = task
->total_user_time
.seconds
;
1342 basic_info
->user_time
.microseconds
1343 = task
->total_user_time
.microseconds
;
1344 basic_info
->system_time
.seconds
1345 = task
->total_system_time
.seconds
;
1346 basic_info
->system_time
.microseconds
1347 = task
->total_system_time
.microseconds
;
1350 *task_info_count
= TASK_BASIC_INFO_COUNT
;
1354 case TASK_THREAD_TIMES_INFO
:
1356 register task_thread_times_info_t times_info
;
1357 register thread_t thread
;
1358 register thread_act_t thr_act
;
1360 if (*task_info_count
< TASK_THREAD_TIMES_INFO_COUNT
) {
1361 return (KERN_INVALID_ARGUMENT
);
1364 times_info
= (task_thread_times_info_t
) task_info_out
;
1365 times_info
->user_time
.seconds
= 0;
1366 times_info
->user_time
.microseconds
= 0;
1367 times_info
->system_time
.seconds
= 0;
1368 times_info
->system_time
.microseconds
= 0;
1371 queue_iterate(&task
->thr_acts
, thr_act
,
1372 thread_act_t
, thr_acts
)
1374 time_value_t user_time
, system_time
;
1377 thread
= act_lock_thread(thr_act
);
1379 /* Skip empty threads and threads that have migrated
1382 if (!thread
|| thr_act
->pool_port
) {
1383 act_unlock_thread(thr_act
);
1386 assert(thread
); /* Must have thread, if no thread_pool*/
1388 thread_lock(thread
);
1390 thread_read_times(thread
, &user_time
, &system_time
);
1392 thread_unlock(thread
);
1394 act_unlock_thread(thr_act
);
1396 time_value_add(×_info
->user_time
, &user_time
);
1397 time_value_add(×_info
->system_time
, &system_time
);
1401 *task_info_count
= TASK_THREAD_TIMES_INFO_COUNT
;
1405 case TASK_SCHED_FIFO_INFO
:
1407 register policy_fifo_base_t fifo_base
;
1409 if (*task_info_count
< POLICY_FIFO_BASE_COUNT
)
1410 return(KERN_INVALID_ARGUMENT
);
1412 fifo_base
= (policy_fifo_base_t
) task_info_out
;
1415 if (task
->policy
!= POLICY_FIFO
) {
1417 return(KERN_INVALID_POLICY
);
1420 fifo_base
->base_priority
= task
->priority
;
1423 *task_info_count
= POLICY_FIFO_BASE_COUNT
;
1427 case TASK_SCHED_RR_INFO
:
1429 register policy_rr_base_t rr_base
;
1431 if (*task_info_count
< POLICY_RR_BASE_COUNT
)
1432 return(KERN_INVALID_ARGUMENT
);
1434 rr_base
= (policy_rr_base_t
) task_info_out
;
1437 if (task
->policy
!= POLICY_RR
) {
1439 return(KERN_INVALID_POLICY
);
1442 rr_base
->base_priority
= task
->priority
;
1445 rr_base
->quantum
= (min_quantum
* tick
) / 1000;
1447 *task_info_count
= POLICY_RR_BASE_COUNT
;
1451 case TASK_SCHED_TIMESHARE_INFO
:
1453 register policy_timeshare_base_t ts_base
;
1455 if (*task_info_count
< POLICY_TIMESHARE_BASE_COUNT
)
1456 return(KERN_INVALID_ARGUMENT
);
1458 ts_base
= (policy_timeshare_base_t
) task_info_out
;
1461 if (task
->policy
!= POLICY_TIMESHARE
) {
1463 return(KERN_INVALID_POLICY
);
1466 ts_base
->base_priority
= task
->priority
;
1469 *task_info_count
= POLICY_TIMESHARE_BASE_COUNT
;
1473 case TASK_SECURITY_TOKEN
:
1475 register security_token_t
*sec_token_p
;
1477 if (*task_info_count
< TASK_SECURITY_TOKEN_COUNT
) {
1478 return(KERN_INVALID_ARGUMENT
);
1481 sec_token_p
= (security_token_t
*) task_info_out
;
1484 *sec_token_p
= task
->sec_token
;
1487 *task_info_count
= TASK_SECURITY_TOKEN_COUNT
;
1491 case TASK_SCHED_INFO
:
1492 return(KERN_INVALID_ARGUMENT
);
1494 case TASK_EVENTS_INFO
:
1496 register task_events_info_t events_info
;
1498 if (*task_info_count
< TASK_EVENTS_INFO_COUNT
) {
1499 return(KERN_INVALID_ARGUMENT
);
1502 events_info
= (task_events_info_t
) task_info_out
;
1505 events_info
->faults
= task
->faults
;
1506 events_info
->pageins
= task
->pageins
;
1507 events_info
->cow_faults
= task
->cow_faults
;
1508 events_info
->messages_sent
= task
->messages_sent
;
1509 events_info
->messages_received
= task
->messages_received
;
1510 events_info
->syscalls_mach
= task
->syscalls_mach
;
1511 events_info
->syscalls_unix
= task
->syscalls_unix
;
1512 events_info
->csw
= task
->csw
;
1515 *task_info_count
= TASK_EVENTS_INFO_COUNT
;
1520 return (KERN_INVALID_ARGUMENT
);
1523 return(KERN_SUCCESS
);
1529 * Change the assigned processor set for the task
1534 processor_set_t new_pset
,
1535 boolean_t assign_threads
)
1538 task
++; new_pset
++; assign_threads
++;
1540 return(KERN_FAILURE
);
1544 * task_assign_default:
1546 * Version of task_assign to assign to default processor set.
1549 task_assign_default(
1551 boolean_t assign_threads
)
1553 return (task_assign(task
, &default_pset
, assign_threads
));
1557 * task_get_assignment
1559 * Return name of processor set that task is assigned to.
1562 task_get_assignment(
1564 processor_set_t
*pset
)
1567 return(KERN_FAILURE
);
1569 *pset
= task
->processor_set
;
1570 pset_reference(*pset
);
1571 return(KERN_SUCCESS
);
1578 * Set scheduling policy and parameters, both base and limit, for
1579 * the given task. Policy must be a policy which is enabled for the
1580 * processor set. Change contained threads if requested.
1587 mach_msg_type_number_t count
,
1588 boolean_t set_limit
,
1591 return(KERN_FAILURE
);
1597 * Set scheduling policy and parameters, both base and limit, for
1598 * the given task. Policy can be any policy implemented by the
1599 * processor set, whether enabled or not. Change contained threads
1605 processor_set_t pset
,
1608 mach_msg_type_number_t base_count
,
1609 policy_limit_t limit
,
1610 mach_msg_type_number_t limit_count
,
1613 return(KERN_FAILURE
);
1617 * task_collect_scan:
1619 * Attempt to free resources owned by tasks.
1623 task_collect_scan(void)
1625 register task_t task
, prev_task
;
1626 processor_set_t pset
= &default_pset
;
1628 prev_task
= TASK_NULL
;
1632 task
= (task_t
) queue_first(&pset
->tasks
);
1633 while (!queue_end(&pset
->tasks
, (queue_entry_t
) task
)) {
1634 task_reference(task
);
1637 pmap_collect(task
->map
->pmap
);
1639 if (prev_task
!= TASK_NULL
)
1640 task_deallocate(prev_task
);
1644 task
= (task_t
) queue_next(&task
->pset_tasks
);
1648 pset_deallocate(pset
);
1650 if (prev_task
!= TASK_NULL
)
1651 task_deallocate(prev_task
);
1654 boolean_t task_collect_allowed
= FALSE
;
1655 unsigned task_collect_last_tick
= 0;
1656 unsigned task_collect_max_rate
= 0; /* in ticks */
1659 * consider_task_collect:
1661 * Called by the pageout daemon when the system needs more free pages.
1665 consider_task_collect(void)
1668 * By default, don't attempt task collection more frequently
1669 * than once per second.
1672 if (task_collect_max_rate
== 0)
1673 task_collect_max_rate
= (2 << SCHED_TICK_SHIFT
);
1675 if (task_collect_allowed
&&
1676 (sched_tick
> (task_collect_last_tick
+ task_collect_max_rate
))) {
1677 task_collect_last_tick
= sched_tick
;
1678 task_collect_scan();
1689 extern int fast_tas_debug
;
1691 if (fast_tas_debug
) {
1692 printf("task 0x%x: setting fast_tas to [0x%x, 0x%x]\n",
1696 task
->fast_tas_base
= pc
;
1697 task
->fast_tas_end
= endpc
;
1699 return KERN_SUCCESS
;
1701 #else /* FAST_TAS */
1708 return KERN_FAILURE
;
1710 #endif /* FAST_TAS */
1714 task_synchronizer_destroy_all(task_t task
)
1716 semaphore_t semaphore
;
1717 lock_set_t lock_set
;
1720 * Destroy owned semaphores
1723 while (!queue_empty(&task
->semaphore_list
)) {
1724 semaphore
= (semaphore_t
) queue_first(&task
->semaphore_list
);
1725 (void) semaphore_destroy(task
, semaphore
);
1729 * Destroy owned lock sets
1732 while (!queue_empty(&task
->lock_set_list
)) {
1733 lock_set
= (lock_set_t
) queue_first(&task
->lock_set_list
);
1734 (void) lock_set_destroy(task
, lock_set
);
1739 task_subsystem_destroy_all(task_t task
)
1741 subsystem_t subsystem
;
1744 * Destroy owned subsystems
1747 while (!queue_empty(&task
->subsystem_list
)) {
1748 subsystem
= (subsystem_t
) queue_first(&task
->subsystem_list
);
1749 subsystem_deallocate(subsystem
);
1754 * task_set_port_space:
1756 * Set port name space of task to specified size.
1760 task_set_port_space(
1766 is_write_lock(task
->itk_space
);
1767 kr
= ipc_entry_grow_table(task
->itk_space
, table_entries
);
1768 if (kr
== KERN_SUCCESS
)
1769 is_write_unlock(task
->itk_space
);
1774 * We need to export some functions to other components that
1775 * are currently implemented in macros within the osfmk
1776 * component. Just export them as functions of the same name.
1778 boolean_t
is_kerneltask(task_t t
)
1780 if (t
== kernel_task
)
1783 return((t
->kernel_loaded
));
1787 task_t
current_task()
1789 return (current_task_fast());