]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/task.c
xnu-201.tar.gz
[apple/xnu.git] / osfmk / kern / task.c
CommitLineData
1c79356b
A
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 Software.Distribution@CS.CMU.EDU
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 csl-dist@cs.utah.edu 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/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 */
1c79356b
A
101#include <kern/ipc_tt.h>
102#include <kern/ledger.h>
103#include <kern/host.h>
104#include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */
105#include <kern/profile.h>
106#include <kern/assert.h>
107#include <kern/sync_lock.h>
108#if MACH_KDB
109#include <ddb/db_sym.h>
110#endif /* MACH_KDB */
111
112#if TASK_SWAPPER
113#include <kern/task_swap.h>
114#endif /* TASK_SWAPPER */
115
116/*
117 * Exported interfaces
118 */
119
120#include <mach/task_server.h>
121#include <mach/mach_host_server.h>
122#include <mach/host_security_server.h>
0b4e3aa0 123#include <vm/task_working_set.h>
1c79356b
A
124
125task_t kernel_task;
126zone_t task_zone;
127
128/* Forwards */
129
130void task_hold_locked(
131 task_t task);
132void task_wait_locked(
133 task_t task);
134void task_release_locked(
135 task_t task);
136void task_collect_scan(void);
137void task_free(
138 task_t task );
139void task_synchronizer_destroy_all(
140 task_t task);
141void task_subsystem_destroy_all(
142 task_t task);
143
144kern_return_t task_set_ledger(
145 task_t task,
146 ledger_t wired,
147 ledger_t paged);
148
149void
150task_init(void)
151{
152 task_zone = zinit(
153 sizeof(struct task),
154 TASK_MAX * sizeof(struct task),
155 TASK_CHUNK * sizeof(struct task),
156 "tasks");
157
158 eml_init();
159
160 /*
161 * Create the kernel task as the first task.
162 * Task_create_local must assign to kernel_task as a side effect,
163 * for other initialization. (:-()
164 */
165 if (task_create_local(
166 TASK_NULL, FALSE, FALSE, &kernel_task) != KERN_SUCCESS)
167 panic("task_init\n");
168 vm_map_deallocate(kernel_task->map);
169 kernel_task->map = kernel_map;
170
171#if MACH_ASSERT
172 if (watchacts & WA_TASK)
173 printf("task_init: kernel_task = %x map=%x\n",
174 kernel_task, kernel_map);
175#endif /* MACH_ASSERT */
176}
177
178#if MACH_HOST
179void
180task_freeze(
181 task_t task)
182{
183 task_lock(task);
184 /*
185 * If may_assign is false, task is already being assigned,
186 * wait for that to finish.
187 */
188 while (task->may_assign == FALSE) {
189 task->assign_active = TRUE;
190 thread_sleep_mutex((event_t) &task->assign_active,
191 &task->lock, THREAD_INTERRUPTIBLE);
192 task_lock(task);
193 }
194 task->may_assign = FALSE;
195 task_unlock(task);
196
197 return;
198}
199
200void
201task_unfreeze(
202 task_t task)
203{
204 task_lock(task);
205 assert(task->may_assign == FALSE);
206 task->may_assign = TRUE;
207 if (task->assign_active == TRUE) {
208 task->assign_active = FALSE;
209 thread_wakeup((event_t)&task->assign_active);
210 }
211 task_unlock(task);
212
213 return;
214}
215#endif /* MACH_HOST */
216
217/*
218 * Create a task running in the kernel address space. It may
219 * have its own map of size mem_size and may have ipc privileges.
220 */
221kern_return_t
222kernel_task_create(
223 task_t parent_task,
224 vm_offset_t map_base,
225 vm_size_t map_size,
226 task_t *child_task)
227{
228 kern_return_t result;
229 task_t new_task;
230 vm_map_t old_map;
231
232 /*
233 * Create the task.
234 */
235 result = task_create_local(parent_task, FALSE, TRUE, &new_task);
236 if (result != KERN_SUCCESS)
237 return (result);
238
239 /*
240 * Task_create_local creates the task with a user-space map.
241 * We attempt to replace the map and free it afterwards; else
242 * task_deallocate will free it (can NOT set map to null before
243 * task_deallocate, this impersonates a norma placeholder task).
244 * _Mark the memory as pageable_ -- this is what we
245 * want for images (like servers) loaded into the kernel.
246 */
247 if (map_size == 0) {
248 vm_map_deallocate(new_task->map);
249 new_task->map = kernel_map;
250 *child_task = new_task;
251 } else {
252 old_map = new_task->map;
253 if ((result = kmem_suballoc(kernel_map, &map_base,
254 map_size, TRUE, FALSE,
255 &new_task->map)) != KERN_SUCCESS) {
256 /*
257 * New task created with ref count of 2 -- decrement by
258 * one to force task deletion.
259 */
260 printf("kmem_suballoc(%x,%x,%x,1,0,&new) Fails\n",
261 kernel_map, map_base, map_size);
262 --new_task->ref_count;
263 task_deallocate(new_task);
264 return (result);
265 }
266 vm_map_deallocate(old_map);
267 *child_task = new_task;
268 }
269 return (KERN_SUCCESS);
270}
271
272kern_return_t
273task_create(
274 task_t parent_task,
275 ledger_port_array_t ledger_ports,
276 mach_msg_type_number_t num_ledger_ports,
277 boolean_t inherit_memory,
278 task_t *child_task) /* OUT */
279{
280 if (parent_task == TASK_NULL)
281 return(KERN_INVALID_ARGUMENT);
282
283 return task_create_local(
284 parent_task, inherit_memory, FALSE, child_task);
285}
286
287kern_return_t
288host_security_create_task_token(
289 host_security_t host_security,
290 task_t parent_task,
291 security_token_t sec_token,
292 host_priv_t host_priv,
293 ledger_port_array_t ledger_ports,
294 mach_msg_type_number_t num_ledger_ports,
295 boolean_t inherit_memory,
296 task_t *child_task) /* OUT */
297{
298 kern_return_t result;
299
300 if (parent_task == TASK_NULL)
301 return(KERN_INVALID_ARGUMENT);
302
303 if (host_security == HOST_NULL)
304 return(KERN_INVALID_SECURITY);
305
306 result = task_create_local(
307 parent_task, inherit_memory, FALSE, child_task);
308
309 if (result != KERN_SUCCESS)
310 return(result);
311
312 result = host_security_set_task_token(host_security,
313 *child_task,
314 sec_token,
315 host_priv);
316
317 if (result != KERN_SUCCESS)
318 return(result);
319
320 return(result);
321}
322
323kern_return_t
324task_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 new_task->suspend_count = 0;
352 new_task->thr_act_count = 0;
353 new_task->res_act_count = 0;
354 new_task->active_act_count = 0;
355 new_task->user_stop_count = 0;
0b4e3aa0 356 new_task->role = TASK_UNSPECIFIED;
1c79356b
A
357 new_task->active = TRUE;
358 new_task->kernel_loaded = kernel_loaded;
359 new_task->user_data = 0;
360 new_task->faults = 0;
361 new_task->cow_faults = 0;
362 new_task->pageins = 0;
363 new_task->messages_sent = 0;
364 new_task->messages_received = 0;
365 new_task->syscalls_mach = 0;
366 new_task->syscalls_unix=0;
367 new_task->csw=0;
0b4e3aa0
A
368 new_task->dynamic_working_set = 0;
369
370 task_working_set_create(new_task, TWS_SMALL_HASH_LINE_COUNT,
371 0, TWS_HASH_STYLE_DEFAULT);
1c79356b
A
372
373#ifdef MACH_BSD
374 new_task->bsd_info = 0;
375#endif /* MACH_BSD */
376
377#if TASK_SWAPPER
378 new_task->swap_state = TASK_SW_IN;
379 new_task->swap_flags = 0;
380 new_task->swap_ast_waiting = 0;
381 new_task->swap_stamp = sched_tick;
382 new_task->swap_rss = 0;
383 new_task->swap_nswap = 0;
384#endif /* TASK_SWAPPER */
385
386 queue_init(&new_task->semaphore_list);
387 queue_init(&new_task->lock_set_list);
388 new_task->semaphores_owned = 0;
389 new_task->lock_sets_owned = 0;
390
391#if MACH_HOST
392 new_task->may_assign = TRUE;
393 new_task->assign_active = FALSE;
394#endif /* MACH_HOST */
395 eml_task_reference(new_task, parent_task);
396
397 ipc_task_init(new_task, parent_task);
398
399 new_task->total_user_time.seconds = 0;
400 new_task->total_user_time.microseconds = 0;
401 new_task->total_system_time.seconds = 0;
402 new_task->total_system_time.microseconds = 0;
403
404 task_prof_init(new_task);
405
406 if (parent_task != TASK_NULL) {
407#if MACH_HOST
408 /*
409 * Freeze the parent, so that parent_task->processor_set
410 * cannot change.
411 */
412 task_freeze(parent_task);
413#endif /* MACH_HOST */
414 pset = parent_task->processor_set;
415 if (!pset->active)
416 pset = &default_pset;
417
1c79356b
A
418 new_task->sec_token = parent_task->sec_token;
419
420 shared_region_mapping_ref(parent_task->system_shared_region);
421 new_task->system_shared_region = parent_task->system_shared_region;
422
423 new_task->wired_ledger_port = ledger_copy(
424 convert_port_to_ledger(parent_task->wired_ledger_port));
425 new_task->paged_ledger_port = ledger_copy(
426 convert_port_to_ledger(parent_task->paged_ledger_port));
427 }
428 else {
429 pset = &default_pset;
430
1c79356b
A
431 new_task->sec_token = KERNEL_SECURITY_TOKEN;
432 new_task->wired_ledger_port = ledger_copy(root_wired_ledger);
433 new_task->paged_ledger_port = ledger_copy(root_paged_ledger);
434 }
435
0b4e3aa0
A
436 if (kernel_task == TASK_NULL) {
437 new_task->priority = MINPRI_KERNEL;
438 new_task->max_priority = MAXPRI_KERNEL;
439 }
440 else {
441 new_task->priority = BASEPRI_DEFAULT;
442 new_task->max_priority = MAXPRI_USER;
443 }
444
1c79356b
A
445 pset_lock(pset);
446 pset_add_task(pset, new_task);
447 pset_unlock(pset);
448#if MACH_HOST
449 if (parent_task != TASK_NULL)
450 task_unfreeze(parent_task);
451#endif /* MACH_HOST */
452
453#if FAST_TAS
454 if (inherit_memory) {
455 new_task->fast_tas_base = parent_task->fast_tas_base;
456 new_task->fast_tas_end = parent_task->fast_tas_end;
457 } else {
458 new_task->fast_tas_base = (vm_offset_t)0;
459 new_task->fast_tas_end = (vm_offset_t)0;
460 }
461#endif /* FAST_TAS */
462
463 ipc_task_enable(new_task);
464
465#if TASK_SWAPPER
466 task_swapout_eligible(new_task);
467#endif /* TASK_SWAPPER */
468
469#if MACH_ASSERT
470 if (watchacts & WA_TASK)
471 printf("*** task_create_local(par=%x inh=%x) == 0x%x\n",
472 parent_task, inherit_memory, new_task);
473#endif /* MACH_ASSERT */
474
475 *child_task = new_task;
476 return(KERN_SUCCESS);
477}
478
479/*
480 * task_free:
481 *
482 * Called by task_deallocate when the task's reference count drops to zero.
483 * Task is locked.
484 */
485void
486task_free(
487 task_t task)
488{
489 processor_set_t pset;
490
491#if MACH_ASSERT
492 assert(task != 0);
493 if (watchacts & (WA_EXIT|WA_TASK))
494 printf("task_free(%x(%d)) map ref %d\n", task, task->ref_count,
495 task->map->ref_count);
496#endif /* MACH_ASSERT */
497
498#if TASK_SWAPPER
499 /* task_terminate guarantees that this task is off the list */
500 assert((task->swap_state & TASK_SW_ELIGIBLE) == 0);
501#endif /* TASK_SWAPPER */
502
503 eml_task_deallocate(task);
504
505 /*
506 * Temporarily restore the reference we dropped above, then
507 * freeze the task so that the task->processor_set field
508 * cannot change. In the !MACH_HOST case, the logic can be
509 * simplified, since the default_pset is the only pset.
510 */
511 ++task->ref_count;
512 task_unlock(task);
513#if MACH_HOST
514 task_freeze(task);
515#endif /* MACH_HOST */
516
517 pset = task->processor_set;
518 pset_lock(pset);
519 task_lock(task);
520 if (--task->ref_count > 0) {
521 /*
522 * A new reference appeared (probably from the pset).
523 * Back out. Must unfreeze inline since we'already
524 * dropped our reference.
525 */
526#if MACH_HOST
527 assert(task->may_assign == FALSE);
528 task->may_assign = TRUE;
529 if (task->assign_active == TRUE) {
530 task->assign_active = FALSE;
531 thread_wakeup((event_t)&task->assign_active);
532 }
533#endif /* MACH_HOST */
534 task_unlock(task);
535 pset_unlock(pset);
536 return;
537 }
538 pset_remove_task(pset,task);
539 task_unlock(task);
540 pset_unlock(pset);
541 pset_deallocate(pset);
542
543 ipc_task_terminate(task);
544 shared_region_mapping_dealloc(task->system_shared_region);
545
546 if (task->kernel_loaded)
547 vm_map_remove(kernel_map, task->map->min_offset,
548 task->map->max_offset, VM_MAP_NO_FLAGS);
549 vm_map_deallocate(task->map);
550 is_release(task->itk_space);
551 task_prof_deallocate(task);
0b4e3aa0
A
552 if(task->dynamic_working_set)
553 tws_hash_destroy((tws_hash_t)
554 task->dynamic_working_set);
1c79356b
A
555 zfree(task_zone, (vm_offset_t) task);
556}
557
558void
559task_deallocate(
560 task_t task)
561{
562 if (task != TASK_NULL) {
563 int c;
564
565 task_lock(task);
566 c = --task->ref_count;
567 if (c == 0)
568 task_free(task); /* unlocks task */
569 else
570 task_unlock(task);
571 }
572}
573
574void
575task_reference(
576 task_t task)
577{
578 if (task != TASK_NULL) {
579 task_lock(task);
580 task->ref_count++;
581 task_unlock(task);
582 }
583}
584
585boolean_t
586task_reference_try(
587 task_t task)
588{
589 if (task != TASK_NULL) {
590 if (task_lock_try(task)) {
591 task->ref_count++;
592 task_unlock(task);
593 return TRUE;
594 }
595 }
596 return FALSE;
597}
598
599/*
600 * task_terminate:
601 *
602 * Terminate the specified task. See comments on thread_terminate
603 * (kern/thread.c) about problems with terminating the "current task."
604 */
605
606kern_return_t
607task_terminate(
608 task_t task)
609{
610 if (task == TASK_NULL)
611 return(KERN_INVALID_ARGUMENT);
612 if (task->bsd_info)
613 return(KERN_FAILURE);
614 return (task_terminate_internal(task));
615}
616
617kern_return_t
618task_terminate_internal(
619 task_t task)
620{
621 thread_act_t thr_act, cur_thr_act;
622 task_t cur_task;
e7c99d92
A
623 thread_t cur_thread;
624 boolean_t interrupt_save;
1c79356b
A
625
626 assert(task != kernel_task);
627
628 cur_thr_act = current_act();
629 cur_task = cur_thr_act->task;
630
631#if TASK_SWAPPER
632 /*
633 * If task is not resident (swapped out, or being swapped
634 * out), we want to bring it back in (this can block).
635 * NOTE: The only way that this can happen in the current
636 * system is if the task is swapped while it has a thread
637 * in exit(), and the thread does not hit a clean point
638 * to swap itself before getting here.
639 * Terminating other tasks is another way to this code, but
640 * it is not yet fully supported.
641 * The task_swapin is unconditional. It used to be done
642 * only if the task is not resident. Swapping in a
643 * resident task will prevent it from being swapped out
644 * while it terminates.
645 */
646 task_swapin(task, TRUE); /* TRUE means make it unswappable */
647#endif /* TASK_SWAPPER */
648
649 /*
650 * Get the task locked and make sure that we are not racing
651 * with someone else trying to terminate us.
652 */
653 if (task == cur_task) {
654 task_lock(task);
655 } else if (task < cur_task) {
656 task_lock(task);
657 task_lock(cur_task);
658 } else {
659 task_lock(cur_task);
660 task_lock(task);
661 }
662
663 if (!task->active || !cur_thr_act->active) {
664 /*
665 * Task or current act is already being terminated.
666 * Just return an error. If we are dying, this will
667 * just get us to our AST special handler and that
668 * will get us to finalize the termination of ourselves.
669 */
670 task_unlock(task);
671 if (cur_task != task)
672 task_unlock(cur_task);
673 return(KERN_FAILURE);
674 }
675 if (cur_task != task)
676 task_unlock(cur_task);
677
e7c99d92
A
678 /*
679 * Make sure the current thread does not get aborted out of
680 * the waits inside these operations.
681 */
682 cur_thread = current_thread();
683 interrupt_save = cur_thread->interruptible;
684 cur_thread->interruptible = FALSE;
685
1c79356b
A
686 /*
687 * Indicate that we want all the threads to stop executing
688 * at user space by holding the task (we would have held
689 * each thread independently in thread_terminate_internal -
690 * but this way we may be more likely to already find it
691 * held there). Mark the task inactive, and prevent
692 * further task operations via the task port.
693 */
694 task_hold_locked(task);
695 task->active = FALSE;
696 ipc_task_disable(task);
697
698 /*
699 * Terminate each activation in the task.
700 *
701 * Each terminated activation will run it's special handler
702 * when its current kernel context is unwound. That will
703 * clean up most of the thread resources. Then it will be
704 * handed over to the reaper, who will finally remove the
705 * thread from the task list and free the structures.
1c79356b
A
706 */
707 queue_iterate(&task->thr_acts, thr_act, thread_act_t, thr_acts) {
1c79356b 708 thread_terminate_internal(thr_act);
1c79356b 709 }
e7c99d92
A
710
711 /*
712 * Clean up any virtual machine state/resources associated
713 * with the current activation because it may hold wiring
714 * and other references on resources we will be trying to
715 * release below.
716 */
717 if (cur_thr_act->task == task)
718 act_virtual_machine_destroy(cur_thr_act);
719
1c79356b
A
720 task_unlock(task);
721
722 /*
723 * Destroy all synchronizers owned by the task.
724 */
725 task_synchronizer_destroy_all(task);
726
727 /*
728 * Deallocate all subsystems owned by the task.
729 */
730 task_subsystem_destroy_all(task);
731
732 /*
733 * Destroy the IPC space, leaving just a reference for it.
734 */
735 if (!task->kernel_loaded)
736 ipc_space_destroy(task->itk_space);
737
738 /*
739 * If the current thread is a member of the task
740 * being terminated, then the last reference to
741 * the task will not be dropped until the thread
742 * is finally reaped. To avoid incurring the
743 * expense of removing the address space regions
744 * at reap time, we do it explictly here.
745 */
746 (void) vm_map_remove(task->map,
747 task->map->min_offset,
748 task->map->max_offset, VM_MAP_NO_FLAGS);
749
750 /*
e7c99d92
A
751 * We no longer need to guard against being aborted, so restore
752 * the previous interruptible state.
753 */
754 cur_thread->interruptible = interrupt_save;
755
756 /*
757 * Get rid of the task active reference on itself.
1c79356b 758 */
1c79356b
A
759 task_deallocate(task);
760
761 return(KERN_SUCCESS);
762}
763
764/*
765 * task_halt - Shut the current task down (except for the current thread) in
766 * preparation for dramatic changes to the task (probably exec).
767 * We hold the task, terminate all other threads in the task and
768 * wait for them to terminate, clean up the portspace, and when
769 * all done, let the current thread go.
770 */
771kern_return_t
772task_halt(
773 task_t task)
774{
775 thread_act_t thr_act, cur_thr_act;
776 task_t cur_task;
777
778 assert(task != kernel_task);
779
780 cur_thr_act = current_act();
781 cur_task = cur_thr_act->task;
782
783 if (task != cur_task) {
784 return(KERN_INVALID_ARGUMENT);
785 }
786
787#if TASK_SWAPPER
788 /*
789 * If task is not resident (swapped out, or being swapped
790 * out), we want to bring it back in and make it unswappable.
791 * This can block, so do it early.
792 */
793 task_swapin(task, TRUE); /* TRUE means make it unswappable */
794#endif /* TASK_SWAPPER */
795
796 task_lock(task);
797
798 if (!task->active || !cur_thr_act->active) {
799 /*
800 * Task or current thread is already being terminated.
801 * Hurry up and return out of the current kernel context
802 * so that we run our AST special handler to terminate
803 * ourselves.
804 */
805 task_unlock(task);
806 return(KERN_FAILURE);
807 }
808
809 if (task->thr_act_count > 1) {
810 /*
811 * Mark all the threads to keep them from starting any more
812 * user-level execution. The thread_terminate_internal code
813 * would do this on a thread by thread basis anyway, but this
814 * gives us a better chance of not having to wait there.
815 */
816 task_hold_locked(task);
817
818 /*
819 * Terminate all the other activations in the task.
820 *
821 * Each terminated activation will run it's special handler
822 * when its current kernel context is unwound. That will
823 * clean up most of the thread resources. Then it will be
824 * handed over to the reaper, who will finally remove the
825 * thread from the task list and free the structures.
1c79356b
A
826 */
827 queue_iterate(&task->thr_acts, thr_act, thread_act_t,thr_acts) {
828 if (thr_act != cur_thr_act)
829 thread_terminate_internal(thr_act);
1c79356b
A
830 }
831 task_release_locked(task);
832 }
e7c99d92
A
833
834 /*
835 * If the current thread has any virtual machine state
836 * associated with it, we need to explicitly clean that
837 * up now (because we did not terminate the current act)
838 * before we try to clean up the task VM and port spaces.
839 */
840 act_virtual_machine_destroy(cur_thr_act);
841
1c79356b
A
842 task_unlock(task);
843
844 /*
845 * Destroy all synchronizers owned by the task.
846 */
847 task_synchronizer_destroy_all(task);
848
849 /*
850 * Deallocate all subsystems owned by the task.
851 */
852 task_subsystem_destroy_all(task);
853
e7c99d92 854#if 0
1c79356b
A
855 /*
856 * Destroy the IPC space, leaving just a reference for it.
857 */
e7c99d92
A
858 /*
859 * Lookupd will break if we enable this cleaning, because it
860 * uses a slimey trick that depends upon the portspace not
861 * being cleaned up across exec (it passes the lookupd server
862 * port to the child after a restart using knowledge of this
863 * bug in past implementations). We need to fix lookupd to
864 * keep from leaking ports across exec.
865 */
1c79356b
A
866 if (!task->kernel_loaded)
867 ipc_space_clean(task->itk_space);
868#endif
869
870 /*
871 * Clean out the address space, as we are going to be
872 * getting a new one.
873 */
874 (void) vm_map_remove(task->map,
875 task->map->min_offset,
876 task->map->max_offset, VM_MAP_NO_FLAGS);
877
878 return KERN_SUCCESS;
879}
880
881/*
882 * task_hold_locked:
883 *
884 * Suspend execution of the specified task.
885 * This is a recursive-style suspension of the task, a count of
886 * suspends is maintained.
887 *
888 * CONDITIONS: the task is locked and active.
889 */
890void
891task_hold_locked(
892 register task_t task)
893{
894 register thread_act_t thr_act;
895
896 assert(task->active);
897
898 task->suspend_count++;
899
900 /*
901 * Iterate through all the thread_act's and hold them.
902 */
903 queue_iterate(&task->thr_acts, thr_act, thread_act_t, thr_acts) {
904 act_lock_thread(thr_act);
905 thread_hold(thr_act);
906 act_unlock_thread(thr_act);
907 }
908}
909
910/*
911 * task_hold:
912 *
913 * Same as the internal routine above, except that is must lock
914 * and verify that the task is active. This differs from task_suspend
915 * in that it places a kernel hold on the task rather than just a
916 * user-level hold. This keeps users from over resuming and setting
917 * it running out from under the kernel.
918 *
919 * CONDITIONS: the caller holds a reference on the task
920 */
921kern_return_t
922task_hold(task_t task)
923{
924 kern_return_t kret;
925
926 if (task == TASK_NULL)
927 return (KERN_INVALID_ARGUMENT);
928 task_lock(task);
929 if (!task->active) {
930 task_unlock(task);
931 return (KERN_FAILURE);
932 }
933 task_hold_locked(task);
934 task_unlock(task);
935
936 return(KERN_SUCCESS);
937}
938
939/*
940 * Routine: task_wait_locked
941 * Wait for all threads in task to stop.
942 *
943 * Conditions:
944 * Called with task locked, active, and held.
945 */
946void
947task_wait_locked(
948 register task_t task)
949{
950 register thread_act_t thr_act, cur_thr_act;
951
952 assert(task->active);
953 assert(task->suspend_count > 0);
954
955 cur_thr_act = current_act();
956 /*
957 * Iterate through all the thread's and wait for them to
958 * stop. Do not wait for the current thread if it is within
959 * the task.
960 */
961 queue_iterate(&task->thr_acts, thr_act, thread_act_t, thr_acts) {
962 if (thr_act != cur_thr_act) {
963 thread_shuttle_t thr_shuttle;
964
965 thr_shuttle = act_lock_thread(thr_act);
966 thread_wait(thr_shuttle);
967 act_unlock_thread(thr_act);
968 }
969 }
970}
971
972/*
973 * task_release_locked:
974 *
975 * Release a kernel hold on a task.
976 *
977 * CONDITIONS: the task is locked and active
978 */
979void
980task_release_locked(
981 register task_t task)
982{
983 register thread_act_t thr_act;
984
985 assert(task->active);
986
987 task->suspend_count--;
988 assert(task->suspend_count >= 0);
989
990 /*
991 * Iterate through all the thread_act's and hold them.
992 * Do not hold the current thread_act if it is within the
993 * task.
994 */
995 queue_iterate(&task->thr_acts, thr_act, thread_act_t, thr_acts) {
996 act_lock_thread(thr_act);
997 thread_release(thr_act);
998 act_unlock_thread(thr_act);
999 }
1000}
1001
1002/*
1003 * task_release:
1004 *
1005 * Same as the internal routine above, except that it must lock
1006 * and verify that the task is active.
1007 *
1008 * CONDITIONS: The caller holds a reference to the task
1009 */
1010kern_return_t
1011task_release(task_t task)
1012{
1013 kern_return_t kret;
1014
1015 if (task == TASK_NULL)
1016 return (KERN_INVALID_ARGUMENT);
1017 task_lock(task);
1018 if (!task->active) {
1019 task_unlock(task);
1020 return (KERN_FAILURE);
1021 }
1022 task_release_locked(task);
1023 task_unlock(task);
1024
1025 return(KERN_SUCCESS);
1026}
1027
1028kern_return_t
1029task_threads(
1030 task_t task,
1031 thread_act_array_t *thr_act_list,
1032 mach_msg_type_number_t *count)
1033{
1034 unsigned int actual; /* this many thr_acts */
1035 thread_act_t thr_act;
1036 thread_act_t *thr_acts;
1037 thread_t thread;
1038 int i, j;
1039
1040 vm_size_t size, size_needed;
1041 vm_offset_t addr;
1042
1043 if (task == TASK_NULL)
1044 return KERN_INVALID_ARGUMENT;
1045
1046 size = 0; addr = 0;
1047
1048 for (;;) {
1049 task_lock(task);
1050 if (!task->active) {
1051 task_unlock(task);
1052 if (size != 0)
1053 kfree(addr, size);
1054 return KERN_FAILURE;
1055 }
1056
1057 actual = task->thr_act_count;
1058
1059 /* do we have the memory we need? */
1060 size_needed = actual * sizeof(mach_port_t);
1061 if (size_needed <= size)
1062 break;
1063
1064 /* unlock the task and allocate more memory */
1065 task_unlock(task);
1066
1067 if (size != 0)
1068 kfree(addr, size);
1069
1070 assert(size_needed > 0);
1071 size = size_needed;
1072
1073 addr = kalloc(size);
1074 if (addr == 0)
1075 return KERN_RESOURCE_SHORTAGE;
1076 }
1077
1078 /* OK, have memory and the task is locked & active */
1079 thr_acts = (thread_act_t *) addr;
1080
1081 for (i = j = 0, thr_act = (thread_act_t) queue_first(&task->thr_acts);
1082 i < actual;
1083 i++, thr_act = (thread_act_t) queue_next(&thr_act->thr_acts)) {
1084 act_lock(thr_act);
1085 if (thr_act->ref_count > 0) {
1086 act_locked_act_reference(thr_act);
1087 thr_acts[j++] = thr_act;
1088 }
1089 act_unlock(thr_act);
1090 }
1091 assert(queue_end(&task->thr_acts, (queue_entry_t) thr_act));
1092
1093 actual = j;
1094 size_needed = actual * sizeof(mach_port_t);
1095
1096 /* can unlock task now that we've got the thr_act refs */
1097 task_unlock(task);
1098
1099 if (actual == 0) {
1100 /* no thr_acts, so return null pointer and deallocate memory */
1101
1102 *thr_act_list = 0;
1103 *count = 0;
1104
1105 if (size != 0)
1106 kfree(addr, size);
1107 } else {
1108 /* if we allocated too much, must copy */
1109
1110 if (size_needed < size) {
1111 vm_offset_t newaddr;
1112
1113 newaddr = kalloc(size_needed);
1114 if (newaddr == 0) {
1115 for (i = 0; i < actual; i++)
1116 act_deallocate(thr_acts[i]);
1117 kfree(addr, size);
1118 return KERN_RESOURCE_SHORTAGE;
1119 }
1120
1121 bcopy((char *) addr, (char *) newaddr, size_needed);
1122 kfree(addr, size);
1123 thr_acts = (thread_act_t *) newaddr;
1124 }
1125
1126 *thr_act_list = thr_acts;
1127 *count = actual;
1128
1129 /* do the conversion that Mig should handle */
1130
1131 for (i = 0; i < actual; i++)
1132 ((ipc_port_t *) thr_acts)[i] =
1133 convert_act_to_port(thr_acts[i]);
1134 }
1135
1136 return KERN_SUCCESS;
1137}
1138
1139/*
1140 * Routine: task_suspend
1141 * Implement a user-level suspension on a task.
1142 *
1143 * Conditions:
1144 * The caller holds a reference to the task
1145 */
1146kern_return_t
1147task_suspend(
1148 register task_t task)
1149{
1150 if (task == TASK_NULL)
1151 return (KERN_INVALID_ARGUMENT);
1152
1153 task_lock(task);
1154 if (!task->active) {
1155 task_unlock(task);
1156 return (KERN_FAILURE);
1157 }
1158 if ((task->user_stop_count)++ > 0) {
1159 /*
1160 * If the stop count was positive, the task is
1161 * already stopped and we can exit.
1162 */
1163 task_unlock(task);
1164 return (KERN_SUCCESS);
1165 }
1166
1167 /*
1168 * Put a kernel-level hold on the threads in the task (all
1169 * user-level task suspensions added together represent a
1170 * single kernel-level hold). We then wait for the threads
1171 * to stop executing user code.
1172 */
1173 task_hold_locked(task);
1174 task_wait_locked(task);
1175 task_unlock(task);
1176 return (KERN_SUCCESS);
1177}
1178
1179/*
1180 * Routine: task_resume
1181 * Release a kernel hold on a task.
1182 *
1183 * Conditions:
1184 * The caller holds a reference to the task
1185 */
1186kern_return_t
1187task_resume(register task_t task)
1188{
1189 register boolean_t release;
1190
1191 if (task == TASK_NULL)
1192 return(KERN_INVALID_ARGUMENT);
1193
1194 release = FALSE;
1195 task_lock(task);
1196 if (!task->active) {
1197 task_unlock(task);
1198 return(KERN_FAILURE);
1199 }
1200 if (task->user_stop_count > 0) {
1201 if (--(task->user_stop_count) == 0)
1202 release = TRUE;
1203 }
1204 else {
1205 task_unlock(task);
1206 return(KERN_FAILURE);
1207 }
1208
1209 /*
1210 * Release the task if necessary.
1211 */
1212 if (release)
1213 task_release_locked(task);
1214
1215 task_unlock(task);
1216 return(KERN_SUCCESS);
1217}
1218
1219kern_return_t
1220host_security_set_task_token(
1221 host_security_t host_security,
1222 task_t task,
1223 security_token_t sec_token,
1224 host_priv_t host_priv)
1225{
1226 kern_return_t kr;
1227
1228 if (task == TASK_NULL)
1229 return(KERN_INVALID_ARGUMENT);
1230
1231 if (host_security == HOST_NULL)
1232 return(KERN_INVALID_SECURITY);
1233
1234 task_lock(task);
1235 task->sec_token = sec_token;
1236 task_unlock(task);
1237
1238 if (host_priv != HOST_PRIV_NULL) {
1239 kr = task_set_special_port(task,
1240 TASK_HOST_PORT,
1241 ipc_port_make_send(realhost.host_priv_self));
1242 } else {
1243 kr = task_set_special_port(task,
1244 TASK_HOST_PORT,
1245 ipc_port_make_send(realhost.host_self));
1246 }
1247 return(kr);
1248}
1249
1250/*
1251 * Utility routine to set a ledger
1252 */
1253kern_return_t
1254task_set_ledger(
1255 task_t task,
1256 ledger_t wired,
1257 ledger_t paged)
1258{
1259 if (task == TASK_NULL)
1260 return(KERN_INVALID_ARGUMENT);
1261
1262 task_lock(task);
1263 if (wired) {
1264 ipc_port_release_send(task->wired_ledger_port);
1265 task->wired_ledger_port = ledger_copy(wired);
1266 }
1267 if (paged) {
1268 ipc_port_release_send(task->paged_ledger_port);
1269 task->paged_ledger_port = ledger_copy(paged);
1270 }
1271 task_unlock(task);
1272
1273 return(KERN_SUCCESS);
1274}
1275
1276/*
1277 * This routine was added, pretty much exclusively, for registering the
1278 * RPC glue vector for in-kernel short circuited tasks. Rather than
1279 * removing it completely, I have only disabled that feature (which was
1280 * the only feature at the time). It just appears that we are going to
1281 * want to add some user data to tasks in the future (i.e. bsd info,
1282 * task names, etc...), so I left it in the formal task interface.
1283 */
1284kern_return_t
1285task_set_info(
1286 task_t task,
1287 task_flavor_t flavor,
1288 task_info_t task_info_in, /* pointer to IN array */
1289 mach_msg_type_number_t task_info_count)
1290{
1291 vm_map_t map;
1292
1293 if (task == TASK_NULL)
1294 return(KERN_INVALID_ARGUMENT);
1295
1296 switch (flavor) {
1297 default:
1298 return (KERN_INVALID_ARGUMENT);
1299 }
1300 return (KERN_SUCCESS);
1301}
1302
1303kern_return_t
1304task_info(
1305 task_t task,
1306 task_flavor_t flavor,
1307 task_info_t task_info_out,
1308 mach_msg_type_number_t *task_info_count)
1309{
1310 thread_t thread;
1311 vm_map_t map;
1312
1313 if (task == TASK_NULL)
1314 return(KERN_INVALID_ARGUMENT);
1315
1316 switch (flavor) {
1317
1318 case TASK_BASIC_INFO:
1319 {
1320 register task_basic_info_t basic_info;
1321
1322 if (*task_info_count < TASK_BASIC_INFO_COUNT) {
1323 return(KERN_INVALID_ARGUMENT);
1324 }
1325
1326 basic_info = (task_basic_info_t) task_info_out;
1327
1328 map = (task == kernel_task) ? kernel_map : task->map;
1329
1330 basic_info->virtual_size = map->size;
1331 basic_info->resident_size = pmap_resident_count(map->pmap)
1332 * PAGE_SIZE;
1333
1334 task_lock(task);
0b4e3aa0
A
1335 basic_info->policy = ((task != kernel_task)?
1336 POLICY_TIMESHARE: POLICY_RR);
1c79356b
A
1337 basic_info->suspend_count = task->user_stop_count;
1338 basic_info->user_time.seconds
1339 = task->total_user_time.seconds;
1340 basic_info->user_time.microseconds
1341 = task->total_user_time.microseconds;
1342 basic_info->system_time.seconds
1343 = task->total_system_time.seconds;
1344 basic_info->system_time.microseconds
1345 = task->total_system_time.microseconds;
1346 task_unlock(task);
1347
1348 *task_info_count = TASK_BASIC_INFO_COUNT;
1349 break;
1350 }
1351
1352 case TASK_THREAD_TIMES_INFO:
1353 {
1354 register task_thread_times_info_t times_info;
1355 register thread_t thread;
1356 register thread_act_t thr_act;
1357
1358 if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
1359 return (KERN_INVALID_ARGUMENT);
1360 }
1361
1362 times_info = (task_thread_times_info_t) task_info_out;
1363 times_info->user_time.seconds = 0;
1364 times_info->user_time.microseconds = 0;
1365 times_info->system_time.seconds = 0;
1366 times_info->system_time.microseconds = 0;
1367
1368 task_lock(task);
1369 queue_iterate(&task->thr_acts, thr_act,
1370 thread_act_t, thr_acts)
1371 {
1372 time_value_t user_time, system_time;
1373 spl_t s;
1374
1375 thread = act_lock_thread(thr_act);
1376
1377 /* Skip empty threads and threads that have migrated
1378 * into this task:
1379 */
1380 if (!thread || thr_act->pool_port) {
1381 act_unlock_thread(thr_act);
1382 continue;
1383 }
1384 assert(thread); /* Must have thread, if no thread_pool*/
1385 s = splsched();
1386 thread_lock(thread);
1387
1388 thread_read_times(thread, &user_time, &system_time);
1389
1390 thread_unlock(thread);
1391 splx(s);
1392 act_unlock_thread(thr_act);
1393
1394 time_value_add(&times_info->user_time, &user_time);
1395 time_value_add(&times_info->system_time, &system_time);
1396 }
1397 task_unlock(task);
1398
1399 *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
1400 break;
1401 }
1402
1403 case TASK_SCHED_FIFO_INFO:
1404 {
1c79356b
A
1405
1406 if (*task_info_count < POLICY_FIFO_BASE_COUNT)
1407 return(KERN_INVALID_ARGUMENT);
1408
0b4e3aa0 1409 return(KERN_INVALID_POLICY);
1c79356b
A
1410 }
1411
1412 case TASK_SCHED_RR_INFO:
1413 {
1414 register policy_rr_base_t rr_base;
1415
1416 if (*task_info_count < POLICY_RR_BASE_COUNT)
1417 return(KERN_INVALID_ARGUMENT);
1418
1419 rr_base = (policy_rr_base_t) task_info_out;
1420
1421 task_lock(task);
0b4e3aa0 1422 if (task != kernel_task) {
1c79356b
A
1423 task_unlock(task);
1424 return(KERN_INVALID_POLICY);
1425 }
1426
1427 rr_base->base_priority = task->priority;
1428 task_unlock(task);
1429
0b4e3aa0 1430 rr_base->quantum = tick / 1000;
1c79356b
A
1431
1432 *task_info_count = POLICY_RR_BASE_COUNT;
1433 break;
1434 }
1435
1436 case TASK_SCHED_TIMESHARE_INFO:
1437 {
1438 register policy_timeshare_base_t ts_base;
1439
1440 if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT)
1441 return(KERN_INVALID_ARGUMENT);
1442
1443 ts_base = (policy_timeshare_base_t) task_info_out;
1444
1445 task_lock(task);
0b4e3aa0 1446 if (task == kernel_task) {
1c79356b
A
1447 task_unlock(task);
1448 return(KERN_INVALID_POLICY);
1449 }
1450
1451 ts_base->base_priority = task->priority;
1452 task_unlock(task);
1453
1454 *task_info_count = POLICY_TIMESHARE_BASE_COUNT;
1455 break;
1456 }
1457
1458 case TASK_SECURITY_TOKEN:
1459 {
1460 register security_token_t *sec_token_p;
1461
1462 if (*task_info_count < TASK_SECURITY_TOKEN_COUNT) {
1463 return(KERN_INVALID_ARGUMENT);
1464 }
1465
1466 sec_token_p = (security_token_t *) task_info_out;
1467
1468 task_lock(task);
1469 *sec_token_p = task->sec_token;
1470 task_unlock(task);
1471
1472 *task_info_count = TASK_SECURITY_TOKEN_COUNT;
1473 break;
1474 }
1475
1476 case TASK_SCHED_INFO:
1477 return(KERN_INVALID_ARGUMENT);
1478
1479 case TASK_EVENTS_INFO:
1480 {
1481 register task_events_info_t events_info;
1482
1483 if (*task_info_count < TASK_EVENTS_INFO_COUNT) {
1484 return(KERN_INVALID_ARGUMENT);
1485 }
1486
1487 events_info = (task_events_info_t) task_info_out;
1488
1489 task_lock(task);
1490 events_info->faults = task->faults;
1491 events_info->pageins = task->pageins;
1492 events_info->cow_faults = task->cow_faults;
1493 events_info->messages_sent = task->messages_sent;
1494 events_info->messages_received = task->messages_received;
1495 events_info->syscalls_mach = task->syscalls_mach;
1496 events_info->syscalls_unix = task->syscalls_unix;
1497 events_info->csw = task->csw;
1498 task_unlock(task);
1499
1500 *task_info_count = TASK_EVENTS_INFO_COUNT;
1501 break;
1502 }
1503
1504 default:
1505 return (KERN_INVALID_ARGUMENT);
1506 }
1507
1508 return(KERN_SUCCESS);
1509}
1510
1511/*
1512 * task_assign:
1513 *
1514 * Change the assigned processor set for the task
1515 */
1516kern_return_t
1517task_assign(
1518 task_t task,
1519 processor_set_t new_pset,
1520 boolean_t assign_threads)
1521{
1522#ifdef lint
1523 task++; new_pset++; assign_threads++;
1524#endif /* lint */
1525 return(KERN_FAILURE);
1526}
1527
1528/*
1529 * task_assign_default:
1530 *
1531 * Version of task_assign to assign to default processor set.
1532 */
1533kern_return_t
1534task_assign_default(
1535 task_t task,
1536 boolean_t assign_threads)
1537{
1538 return (task_assign(task, &default_pset, assign_threads));
1539}
1540
1541/*
1542 * task_get_assignment
1543 *
1544 * Return name of processor set that task is assigned to.
1545 */
1546kern_return_t
1547task_get_assignment(
1548 task_t task,
1549 processor_set_t *pset)
1550{
1551 if (!task->active)
1552 return(KERN_FAILURE);
1553
1554 *pset = task->processor_set;
1555 pset_reference(*pset);
1556 return(KERN_SUCCESS);
1557}
1558
1559
1560/*
1561 * task_policy
1562 *
1563 * Set scheduling policy and parameters, both base and limit, for
1564 * the given task. Policy must be a policy which is enabled for the
1565 * processor set. Change contained threads if requested.
1566 */
1567kern_return_t
1568task_policy(
1569 task_t task,
1570 policy_t policy_id,
1571 policy_base_t base,
1572 mach_msg_type_number_t count,
1573 boolean_t set_limit,
1574 boolean_t change)
1575{
1576 return(KERN_FAILURE);
1577}
1578
1579/*
1580 * task_set_policy
1581 *
1582 * Set scheduling policy and parameters, both base and limit, for
1583 * the given task. Policy can be any policy implemented by the
1584 * processor set, whether enabled or not. Change contained threads
1585 * if requested.
1586 */
1587kern_return_t
1588task_set_policy(
1589 task_t task,
1590 processor_set_t pset,
1591 policy_t policy_id,
1592 policy_base_t base,
1593 mach_msg_type_number_t base_count,
1594 policy_limit_t limit,
1595 mach_msg_type_number_t limit_count,
1596 boolean_t change)
1597{
1598 return(KERN_FAILURE);
1599}
1600
1601/*
1602 * task_collect_scan:
1603 *
1604 * Attempt to free resources owned by tasks.
1605 */
1606
1607void
1608task_collect_scan(void)
1609{
1610 register task_t task, prev_task;
1611 processor_set_t pset = &default_pset;
1612
1613 prev_task = TASK_NULL;
1614
1615 pset_lock(pset);
1616 pset->ref_count++;
1617 task = (task_t) queue_first(&pset->tasks);
1618 while (!queue_end(&pset->tasks, (queue_entry_t) task)) {
1619 task_reference(task);
1620 pset_unlock(pset);
1621
1622 pmap_collect(task->map->pmap);
1623
1624 if (prev_task != TASK_NULL)
1625 task_deallocate(prev_task);
1626 prev_task = task;
1627
1628 pset_lock(pset);
1629 task = (task_t) queue_next(&task->pset_tasks);
1630 }
1631 pset_unlock(pset);
1632
1633 pset_deallocate(pset);
1634
1635 if (prev_task != TASK_NULL)
1636 task_deallocate(prev_task);
1637}
1638
0b4e3aa0 1639/* Also disabled in vm/vm_pageout.c */
1c79356b
A
1640boolean_t task_collect_allowed = FALSE;
1641unsigned task_collect_last_tick = 0;
1642unsigned task_collect_max_rate = 0; /* in ticks */
1643
1644/*
1645 * consider_task_collect:
1646 *
1647 * Called by the pageout daemon when the system needs more free pages.
1648 */
1649
1650void
1651consider_task_collect(void)
1652{
1653 /*
1654 * By default, don't attempt task collection more frequently
1655 * than once per second.
1656 */
1657
1658 if (task_collect_max_rate == 0)
0b4e3aa0 1659 task_collect_max_rate = (1 << SCHED_TICK_SHIFT) + 1;
1c79356b
A
1660
1661 if (task_collect_allowed &&
1662 (sched_tick > (task_collect_last_tick + task_collect_max_rate))) {
1663 task_collect_last_tick = sched_tick;
1664 task_collect_scan();
1665 }
1666}
1667
1668kern_return_t
1669task_set_ras_pc(
1670 task_t task,
1671 vm_offset_t pc,
1672 vm_offset_t endpc)
1673{
1674#if FAST_TAS
1675 extern int fast_tas_debug;
1676
1677 if (fast_tas_debug) {
1678 printf("task 0x%x: setting fast_tas to [0x%x, 0x%x]\n",
1679 task, pc, endpc);
1680 }
1681 task_lock(task);
1682 task->fast_tas_base = pc;
1683 task->fast_tas_end = endpc;
1684 task_unlock(task);
1685 return KERN_SUCCESS;
1686
1687#else /* FAST_TAS */
1688#ifdef lint
1689 task++;
1690 pc++;
1691 endpc++;
1692#endif /* lint */
1693
1694 return KERN_FAILURE;
1695
1696#endif /* FAST_TAS */
1697}
1698
1699void
1700task_synchronizer_destroy_all(task_t task)
1701{
1702 semaphore_t semaphore;
1703 lock_set_t lock_set;
1704
1705 /*
1706 * Destroy owned semaphores
1707 */
1708
1709 while (!queue_empty(&task->semaphore_list)) {
1710 semaphore = (semaphore_t) queue_first(&task->semaphore_list);
1711 (void) semaphore_destroy(task, semaphore);
1712 }
1713
1714 /*
1715 * Destroy owned lock sets
1716 */
1717
1718 while (!queue_empty(&task->lock_set_list)) {
1719 lock_set = (lock_set_t) queue_first(&task->lock_set_list);
1720 (void) lock_set_destroy(task, lock_set);
1721 }
1722}
1723
1724void
1725task_subsystem_destroy_all(task_t task)
1726{
1727 subsystem_t subsystem;
1728
1729 /*
1730 * Destroy owned subsystems
1731 */
1732
1733 while (!queue_empty(&task->subsystem_list)) {
1734 subsystem = (subsystem_t) queue_first(&task->subsystem_list);
1735 subsystem_deallocate(subsystem);
1736 }
1737}
1738
1739/*
1740 * task_set_port_space:
1741 *
1742 * Set port name space of task to specified size.
1743 */
1744
1745kern_return_t
1746task_set_port_space(
1747 task_t task,
1748 int table_entries)
1749{
1750 kern_return_t kr;
1751
1752 is_write_lock(task->itk_space);
1753 kr = ipc_entry_grow_table(task->itk_space, table_entries);
1754 if (kr == KERN_SUCCESS)
1755 is_write_unlock(task->itk_space);
1756 return kr;
1757}
1758
1759/*
1760 * We need to export some functions to other components that
1761 * are currently implemented in macros within the osfmk
1762 * component. Just export them as functions of the same name.
1763 */
1764boolean_t is_kerneltask(task_t t)
1765{
1766 if (t == kernel_task)
1767 return(TRUE);
1768 else
1769 return((t->kernel_loaded));
1770}
1771
1772#undef current_task
1773task_t current_task()
1774{
1775 return (current_task_fast());
1776}