]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/task.c
xnu-1504.9.26.tar.gz
[apple/xnu.git] / osfmk / kern / task.c
1 /*
2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_FREE_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 * File: kern/task.c
58 * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub,
59 * David Black
60 *
61 * Task management primitives implementation.
62 */
63 /*
64 * Copyright (c) 1993 The University of Utah and
65 * the Computer Systems Laboratory (CSL). All rights reserved.
66 *
67 * Permission to use, copy, modify and distribute this software and its
68 * documentation is hereby granted, provided that both the copyright
69 * notice and this permission notice appear in all copies of the
70 * software, derivative works or modified versions, and any portions
71 * thereof, and that both notices appear in supporting documentation.
72 *
73 * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
74 * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
75 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
76 *
77 * CSL requests users of this software to return to csl-dist@cs.utah.edu any
78 * improvements that they make and grant CSL redistribution rights.
79 *
80 */
81 /*
82 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
83 * support for mandatory and extensible security protections. This notice
84 * is included in support of clause 2.2 (b) of the Apple Public License,
85 * Version 2.0.
86 * Copyright (c) 2005 SPARTA, Inc.
87 */
88
89 #include <mach_kdb.h>
90 #include <fast_tas.h>
91 #include <platforms.h>
92
93 #include <mach/mach_types.h>
94 #include <mach/boolean.h>
95 #include <mach/host_priv.h>
96 #include <mach/machine/vm_types.h>
97 #include <mach/vm_param.h>
98 #include <mach/semaphore.h>
99 #include <mach/task_info.h>
100 #include <mach/task_special_ports.h>
101
102 #include <ipc/ipc_types.h>
103 #include <ipc/ipc_space.h>
104 #include <ipc/ipc_entry.h>
105
106 #include <kern/kern_types.h>
107 #include <kern/mach_param.h>
108 #include <kern/misc_protos.h>
109 #include <kern/task.h>
110 #include <kern/thread.h>
111 #include <kern/zalloc.h>
112 #include <kern/kalloc.h>
113 #include <kern/processor.h>
114 #include <kern/sched_prim.h> /* for thread_wakeup */
115 #include <kern/ipc_tt.h>
116 #include <kern/ledger.h>
117 #include <kern/host.h>
118 #include <kern/clock.h>
119 #include <kern/timer.h>
120 #include <kern/assert.h>
121 #include <kern/sync_lock.h>
122 #include <kern/affinity.h>
123
124 #include <vm/pmap.h>
125 #include <vm/vm_map.h>
126 #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */
127 #include <vm/vm_pageout.h>
128 #include <vm/vm_protos.h>
129
130 #if MACH_KDB
131 #include <ddb/db_sym.h>
132 #endif /* MACH_KDB */
133
134 #ifdef __ppc__
135 #include <ppc/exception.h>
136 #include <ppc/hw_perfmon.h>
137 #endif
138
139
140 /*
141 * Exported interfaces
142 */
143
144 #include <mach/task_server.h>
145 #include <mach/mach_host_server.h>
146 #include <mach/host_security_server.h>
147 #include <mach/mach_port_server.h>
148 #include <mach/security_server.h>
149
150 #include <vm/vm_shared_region.h>
151
152 #if CONFIG_MACF_MACH
153 #include <security/mac_mach_internal.h>
154 #endif
155
156 #if CONFIG_COUNTERS
157 #include <pmc/pmc.h>
158 #endif /* CONFIG_COUNTERS */
159
160 task_t kernel_task;
161 zone_t task_zone;
162 lck_attr_t task_lck_attr;
163 lck_grp_t task_lck_grp;
164 lck_grp_attr_t task_lck_grp_attr;
165
166 int task_max = CONFIG_TASK_MAX; /* Max number of tasks */
167
168 /* Forwards */
169
170 void task_hold_locked(
171 task_t task);
172 void task_wait_locked(
173 task_t task);
174 void task_release_locked(
175 task_t task);
176 void task_free(
177 task_t task );
178 void task_synchronizer_destroy_all(
179 task_t task);
180
181 kern_return_t task_set_ledger(
182 task_t task,
183 ledger_t wired,
184 ledger_t paged);
185
186 int check_for_tasksuspend(
187 task_t task);
188
189 void
190 task_backing_store_privileged(
191 task_t task)
192 {
193 task_lock(task);
194 task->priv_flags |= VM_BACKING_STORE_PRIV;
195 task_unlock(task);
196 return;
197 }
198
199
200 void
201 task_set_64bit(
202 task_t task,
203 boolean_t is64bit)
204 {
205 #if defined(__i386__) || defined(__x86_64__)
206 thread_t thread;
207 #endif /* __i386__ */
208 int vm_flags = 0;
209
210 if (is64bit) {
211 if (task_has_64BitAddr(task))
212 return;
213
214 task_set_64BitAddr(task);
215 } else {
216 if ( !task_has_64BitAddr(task))
217 return;
218
219 /*
220 * Deallocate all memory previously allocated
221 * above the 32-bit address space, since it won't
222 * be accessible anymore.
223 */
224 /* remove regular VM map entries & pmap mappings */
225 (void) vm_map_remove(task->map,
226 (vm_map_offset_t) VM_MAX_ADDRESS,
227 MACH_VM_MAX_ADDRESS,
228 0);
229 #ifdef __ppc__
230 /*
231 * PPC51: ppc64 is limited to 51-bit addresses.
232 * Memory mapped above that limit is handled specially
233 * at the pmap level, so let pmap clean the commpage mapping
234 * explicitly...
235 */
236 pmap_unmap_sharedpage(task->map->pmap); /* Unmap commpage */
237 /* ... and avoid regular pmap cleanup */
238 vm_flags |= VM_MAP_REMOVE_NO_PMAP_CLEANUP;
239 #endif /* __ppc__ */
240 /* remove the higher VM mappings */
241 (void) vm_map_remove(task->map,
242 MACH_VM_MAX_ADDRESS,
243 0xFFFFFFFFFFFFF000ULL,
244 vm_flags);
245 task_clear_64BitAddr(task);
246 }
247 /* FIXME: On x86, the thread save state flavor can diverge from the
248 * task's 64-bit feature flag due to the 32-bit/64-bit register save
249 * state dichotomy. Since we can be pre-empted in this interval,
250 * certain routines may observe the thread as being in an inconsistent
251 * state with respect to its task's 64-bitness.
252 */
253 #if defined(__i386__) || defined(__x86_64__)
254 task_lock(task);
255 queue_iterate(&task->threads, thread, thread_t, task_threads) {
256 thread_mtx_lock(thread);
257 machine_thread_switch_addrmode(thread);
258 thread_mtx_unlock(thread);
259 }
260 task_unlock(task);
261 #endif /* __i386__ */
262 }
263
264
265 void
266 task_set_dyld_info(task_t task, mach_vm_address_t addr, mach_vm_size_t size)
267 {
268 task_lock(task);
269 task->all_image_info_addr = addr;
270 task->all_image_info_size = size;
271 task_unlock(task);
272 }
273
274 void
275 task_init(void)
276 {
277
278 lck_grp_attr_setdefault(&task_lck_grp_attr);
279 lck_grp_init(&task_lck_grp, "task", &task_lck_grp_attr);
280 lck_attr_setdefault(&task_lck_attr);
281 lck_mtx_init(&tasks_threads_lock, &task_lck_grp, &task_lck_attr);
282
283 task_zone = zinit(
284 sizeof(struct task),
285 task_max * sizeof(struct task),
286 TASK_CHUNK * sizeof(struct task),
287 "tasks");
288 zone_change(task_zone, Z_NOENCRYPT, TRUE);
289
290 /*
291 * Create the kernel task as the first task.
292 */
293 #ifdef __LP64__
294 if (task_create_internal(TASK_NULL, FALSE, TRUE, &kernel_task) != KERN_SUCCESS)
295 #else
296 if (task_create_internal(TASK_NULL, FALSE, FALSE, &kernel_task) != KERN_SUCCESS)
297 #endif
298 panic("task_init\n");
299
300 vm_map_deallocate(kernel_task->map);
301 kernel_task->map = kernel_map;
302 }
303
304 /*
305 * Create a task running in the kernel address space. It may
306 * have its own map of size mem_size and may have ipc privileges.
307 */
308 kern_return_t
309 kernel_task_create(
310 __unused task_t parent_task,
311 __unused vm_offset_t map_base,
312 __unused vm_size_t map_size,
313 __unused task_t *child_task)
314 {
315 return (KERN_INVALID_ARGUMENT);
316 }
317
318 kern_return_t
319 task_create(
320 task_t parent_task,
321 __unused ledger_port_array_t ledger_ports,
322 __unused mach_msg_type_number_t num_ledger_ports,
323 __unused boolean_t inherit_memory,
324 __unused task_t *child_task) /* OUT */
325 {
326 if (parent_task == TASK_NULL)
327 return(KERN_INVALID_ARGUMENT);
328
329 /*
330 * No longer supported: too many calls assume that a task has a valid
331 * process attached.
332 */
333 return(KERN_FAILURE);
334 }
335
336 kern_return_t
337 host_security_create_task_token(
338 host_security_t host_security,
339 task_t parent_task,
340 __unused security_token_t sec_token,
341 __unused audit_token_t audit_token,
342 __unused host_priv_t host_priv,
343 __unused ledger_port_array_t ledger_ports,
344 __unused mach_msg_type_number_t num_ledger_ports,
345 __unused boolean_t inherit_memory,
346 __unused task_t *child_task) /* OUT */
347 {
348 if (parent_task == TASK_NULL)
349 return(KERN_INVALID_ARGUMENT);
350
351 if (host_security == HOST_NULL)
352 return(KERN_INVALID_SECURITY);
353
354 /*
355 * No longer supported.
356 */
357 return(KERN_FAILURE);
358 }
359
360 kern_return_t
361 task_create_internal(
362 task_t parent_task,
363 boolean_t inherit_memory,
364 boolean_t is_64bit,
365 task_t *child_task) /* OUT */
366 {
367 task_t new_task;
368 vm_shared_region_t shared_region;
369
370 new_task = (task_t) zalloc(task_zone);
371
372 if (new_task == TASK_NULL)
373 return(KERN_RESOURCE_SHORTAGE);
374
375 /* one ref for just being alive; one for our caller */
376 new_task->ref_count = 2;
377
378 /* if inherit_memory is true, parent_task MUST not be NULL */
379 if (inherit_memory)
380 new_task->map = vm_map_fork(parent_task->map);
381 else
382 new_task->map = vm_map_create(pmap_create(0, is_64bit),
383 (vm_map_offset_t)(VM_MIN_ADDRESS),
384 (vm_map_offset_t)(VM_MAX_ADDRESS), TRUE);
385
386 /* Inherit memlock limit from parent */
387 if (parent_task)
388 vm_map_set_user_wire_limit(new_task->map, (vm_size_t)parent_task->map->user_wire_limit);
389
390 lck_mtx_init(&new_task->lock, &task_lck_grp, &task_lck_attr);
391 queue_init(&new_task->threads);
392 new_task->suspend_count = 0;
393 new_task->thread_count = 0;
394 new_task->active_thread_count = 0;
395 new_task->user_stop_count = 0;
396 new_task->role = TASK_UNSPECIFIED;
397 new_task->active = TRUE;
398 new_task->halting = FALSE;
399 new_task->user_data = NULL;
400 new_task->faults = 0;
401 new_task->cow_faults = 0;
402 new_task->pageins = 0;
403 new_task->messages_sent = 0;
404 new_task->messages_received = 0;
405 new_task->syscalls_mach = 0;
406 new_task->priv_flags = 0;
407 new_task->syscalls_unix=0;
408 new_task->c_switch = new_task->p_switch = new_task->ps_switch = 0;
409 new_task->taskFeatures[0] = 0; /* Init task features */
410 new_task->taskFeatures[1] = 0; /* Init task features */
411
412 #ifdef MACH_BSD
413 new_task->bsd_info = NULL;
414 #endif /* MACH_BSD */
415
416 #if defined(__i386__) || defined(__x86_64__)
417 new_task->i386_ldt = 0;
418 new_task->task_debug = NULL;
419
420 #endif
421
422 #ifdef __ppc__
423 if(BootProcInfo.pf.Available & pf64Bit) new_task->taskFeatures[0] |= tf64BitData; /* If 64-bit machine, show we have 64-bit registers at least */
424 #endif
425
426 queue_init(&new_task->semaphore_list);
427 queue_init(&new_task->lock_set_list);
428 new_task->semaphores_owned = 0;
429 new_task->lock_sets_owned = 0;
430
431 #if CONFIG_MACF_MACH
432 new_task->label = labelh_new(1);
433 mac_task_label_init (&new_task->maclabel);
434 #endif
435
436 ipc_task_init(new_task, parent_task);
437
438 new_task->total_user_time = 0;
439 new_task->total_system_time = 0;
440
441 new_task->vtimers = 0;
442
443 new_task->shared_region = NULL;
444
445 new_task->affinity_space = NULL;
446
447 #if CONFIG_COUNTERS
448 new_task->t_chud = 0U;
449 #endif
450
451 if (parent_task != TASK_NULL) {
452 new_task->sec_token = parent_task->sec_token;
453 new_task->audit_token = parent_task->audit_token;
454
455 /* inherit the parent's shared region */
456 shared_region = vm_shared_region_get(parent_task);
457 vm_shared_region_set(new_task, shared_region);
458
459 new_task->wired_ledger_port = ledger_copy(
460 convert_port_to_ledger(parent_task->wired_ledger_port));
461 new_task->paged_ledger_port = ledger_copy(
462 convert_port_to_ledger(parent_task->paged_ledger_port));
463 if(task_has_64BitAddr(parent_task))
464 task_set_64BitAddr(new_task);
465 new_task->all_image_info_addr = parent_task->all_image_info_addr;
466 new_task->all_image_info_size = parent_task->all_image_info_size;
467
468 #if defined(__i386__) || defined(__x86_64__)
469 if (inherit_memory && parent_task->i386_ldt)
470 new_task->i386_ldt = user_ldt_copy(parent_task->i386_ldt);
471 #endif
472 if (inherit_memory && parent_task->affinity_space)
473 task_affinity_create(parent_task, new_task);
474
475 new_task->pset_hint = parent_task->pset_hint = task_choose_pset(parent_task);
476 }
477 else {
478 new_task->sec_token = KERNEL_SECURITY_TOKEN;
479 new_task->audit_token = KERNEL_AUDIT_TOKEN;
480 new_task->wired_ledger_port = ledger_copy(root_wired_ledger);
481 new_task->paged_ledger_port = ledger_copy(root_paged_ledger);
482 #ifdef __LP64__
483 if(is_64bit)
484 task_set_64BitAddr(new_task);
485 #endif
486
487 new_task->pset_hint = PROCESSOR_SET_NULL;
488 }
489
490 if (kernel_task == TASK_NULL) {
491 new_task->priority = BASEPRI_KERNEL;
492 new_task->max_priority = MAXPRI_KERNEL;
493 }
494 else {
495 new_task->priority = BASEPRI_DEFAULT;
496 new_task->max_priority = MAXPRI_USER;
497 }
498
499 lck_mtx_lock(&tasks_threads_lock);
500 queue_enter(&tasks, new_task, task_t, tasks);
501 tasks_count++;
502 lck_mtx_unlock(&tasks_threads_lock);
503
504 if (vm_backing_store_low && parent_task != NULL)
505 new_task->priv_flags |= (parent_task->priv_flags&VM_BACKING_STORE_PRIV);
506
507 ipc_task_enable(new_task);
508
509 *child_task = new_task;
510 return(KERN_SUCCESS);
511 }
512
513 /*
514 * task_deallocate:
515 *
516 * Drop a reference on a task.
517 */
518 void
519 task_deallocate(
520 task_t task)
521 {
522 if (task == TASK_NULL)
523 return;
524
525 if (task_deallocate_internal(task) > 0)
526 return;
527
528 ipc_task_terminate(task);
529
530 if (task->affinity_space)
531 task_affinity_deallocate(task);
532
533 vm_map_deallocate(task->map);
534 is_release(task->itk_space);
535
536 lck_mtx_destroy(&task->lock, &task_lck_grp);
537
538 #if CONFIG_MACF_MACH
539 labelh_release(task->label);
540 #endif
541 zfree(task_zone, task);
542 }
543
544 /*
545 * task_name_deallocate:
546 *
547 * Drop a reference on a task name.
548 */
549 void
550 task_name_deallocate(
551 task_name_t task_name)
552 {
553 return(task_deallocate((task_t)task_name));
554 }
555
556
557 /*
558 * task_terminate:
559 *
560 * Terminate the specified task. See comments on thread_terminate
561 * (kern/thread.c) about problems with terminating the "current task."
562 */
563
564 kern_return_t
565 task_terminate(
566 task_t task)
567 {
568 if (task == TASK_NULL)
569 return (KERN_INVALID_ARGUMENT);
570
571 if (task->bsd_info)
572 return (KERN_FAILURE);
573
574 return (task_terminate_internal(task));
575 }
576
577 kern_return_t
578 task_terminate_internal(
579 task_t task)
580 {
581 thread_t thread, self;
582 task_t self_task;
583 boolean_t interrupt_save;
584
585 assert(task != kernel_task);
586
587 self = current_thread();
588 self_task = self->task;
589
590 /*
591 * Get the task locked and make sure that we are not racing
592 * with someone else trying to terminate us.
593 */
594 if (task == self_task)
595 task_lock(task);
596 else
597 if (task < self_task) {
598 task_lock(task);
599 task_lock(self_task);
600 }
601 else {
602 task_lock(self_task);
603 task_lock(task);
604 }
605
606 if (!task->active || !self->active) {
607 /*
608 * Task or current act is already being terminated.
609 * Just return an error. If we are dying, this will
610 * just get us to our AST special handler and that
611 * will get us to finalize the termination of ourselves.
612 */
613 task_unlock(task);
614 if (self_task != task)
615 task_unlock(self_task);
616
617 return (KERN_FAILURE);
618 }
619
620 if (self_task != task)
621 task_unlock(self_task);
622
623 /*
624 * Make sure the current thread does not get aborted out of
625 * the waits inside these operations.
626 */
627 interrupt_save = thread_interrupt_level(THREAD_UNINT);
628
629 /*
630 * Indicate that we want all the threads to stop executing
631 * at user space by holding the task (we would have held
632 * each thread independently in thread_terminate_internal -
633 * but this way we may be more likely to already find it
634 * held there). Mark the task inactive, and prevent
635 * further task operations via the task port.
636 */
637 task_hold_locked(task);
638 task->active = FALSE;
639 ipc_task_disable(task);
640
641 /*
642 * Terminate each thread in the task.
643 */
644 queue_iterate(&task->threads, thread, thread_t, task_threads) {
645 thread_terminate_internal(thread);
646 }
647
648 /*
649 * Give the machine dependent code a chance
650 * to perform cleanup before ripping apart
651 * the task.
652 */
653 if (self_task == task)
654 machine_thread_terminate_self();
655
656 task_unlock(task);
657
658 /*
659 * Destroy all synchronizers owned by the task.
660 */
661 task_synchronizer_destroy_all(task);
662
663 /*
664 * Destroy the IPC space, leaving just a reference for it.
665 */
666 ipc_space_destroy(task->itk_space);
667
668 #ifdef __ppc__
669 /*
670 * PPC51: ppc64 is limited to 51-bit addresses.
671 */
672 pmap_unmap_sharedpage(task->map->pmap); /* Unmap commpage */
673 #endif /* __ppc__ */
674
675 if (vm_map_has_4GB_pagezero(task->map))
676 vm_map_clear_4GB_pagezero(task->map);
677
678 /*
679 * If the current thread is a member of the task
680 * being terminated, then the last reference to
681 * the task will not be dropped until the thread
682 * is finally reaped. To avoid incurring the
683 * expense of removing the address space regions
684 * at reap time, we do it explictly here.
685 */
686 vm_map_remove(task->map,
687 task->map->min_offset,
688 task->map->max_offset,
689 VM_MAP_NO_FLAGS);
690
691 /* release our shared region */
692 vm_shared_region_set(task, NULL);
693
694 lck_mtx_lock(&tasks_threads_lock);
695 queue_remove(&tasks, task, task_t, tasks);
696 tasks_count--;
697 lck_mtx_unlock(&tasks_threads_lock);
698
699 /*
700 * We no longer need to guard against being aborted, so restore
701 * the previous interruptible state.
702 */
703 thread_interrupt_level(interrupt_save);
704
705 #if __ppc__
706 perfmon_release_facility(task); // notify the perfmon facility
707 #endif
708
709 /*
710 * Get rid of the task active reference on itself.
711 */
712 task_deallocate(task);
713
714 return (KERN_SUCCESS);
715 }
716
717 /*
718 * task_start_halt:
719 *
720 * Shut the current task down (except for the current thread) in
721 * preparation for dramatic changes to the task (probably exec).
722 * We hold the task and mark all other threads in the task for
723 * termination.
724 */
725 kern_return_t
726 task_start_halt(
727 task_t task)
728 {
729 thread_t thread, self;
730
731 assert(task != kernel_task);
732
733 self = current_thread();
734
735 if (task != self->task)
736 return (KERN_INVALID_ARGUMENT);
737
738 task_lock(task);
739
740 if (task->halting || !task->active || !self->active) {
741 /*
742 * Task or current thread is already being terminated.
743 * Hurry up and return out of the current kernel context
744 * so that we run our AST special handler to terminate
745 * ourselves.
746 */
747 task_unlock(task);
748
749 return (KERN_FAILURE);
750 }
751
752 task->halting = TRUE;
753
754 if (task->thread_count > 1) {
755
756 /*
757 * Mark all the threads to keep them from starting any more
758 * user-level execution. The thread_terminate_internal code
759 * would do this on a thread by thread basis anyway, but this
760 * gives us a better chance of not having to wait there.
761 */
762 task_hold_locked(task);
763
764 /*
765 * Terminate all the other threads in the task.
766 */
767 queue_iterate(&task->threads, thread, thread_t, task_threads) {
768 if (thread != self)
769 thread_terminate_internal(thread);
770 }
771
772 task_release_locked(task);
773 }
774 task_unlock(task);
775 return KERN_SUCCESS;
776 }
777
778
779 /*
780 * task_complete_halt:
781 *
782 * Complete task halt by waiting for threads to terminate, then clean
783 * up task resources (VM, port namespace, etc...) and then let the
784 * current thread go in the (practically empty) task context.
785 */
786 void
787 task_complete_halt(task_t task)
788 {
789 task_lock(task);
790 assert(task->halting);
791 assert(task == current_task());
792
793 /*
794 * Give the machine dependent code a chance
795 * to perform cleanup of task-level resources
796 * associated with the current thread before
797 * ripping apart the task.
798 *
799 * This must be done with the task locked.
800 */
801 machine_thread_terminate_self();
802
803 /*
804 * Wait for the other threads to get shut down.
805 * When the last other thread is reaped, we'll be
806 * worken up.
807 */
808 if (task->thread_count > 1) {
809 assert_wait((event_t)&task->halting, THREAD_UNINT);
810 task_unlock(task);
811 thread_block(THREAD_CONTINUE_NULL);
812 } else {
813 task_unlock(task);
814 }
815
816 /*
817 * Destroy all synchronizers owned by the task.
818 */
819 task_synchronizer_destroy_all(task);
820
821 /*
822 * Destroy the contents of the IPC space, leaving just
823 * a reference for it.
824 */
825 ipc_space_clean(task->itk_space);
826
827 /*
828 * Clean out the address space, as we are going to be
829 * getting a new one.
830 */
831 vm_map_remove(task->map, task->map->min_offset,
832 task->map->max_offset, VM_MAP_NO_FLAGS);
833
834 task->halting = FALSE;
835 }
836
837 /*
838 * task_hold_locked:
839 *
840 * Suspend execution of the specified task.
841 * This is a recursive-style suspension of the task, a count of
842 * suspends is maintained.
843 *
844 * CONDITIONS: the task is locked and active.
845 */
846 void
847 task_hold_locked(
848 register task_t task)
849 {
850 register thread_t thread;
851
852 assert(task->active);
853
854 if (task->suspend_count++ > 0)
855 return;
856
857 /*
858 * Iterate through all the threads and hold them.
859 */
860 queue_iterate(&task->threads, thread, thread_t, task_threads) {
861 thread_mtx_lock(thread);
862 thread_hold(thread);
863 thread_mtx_unlock(thread);
864 }
865 }
866
867 /*
868 * task_hold:
869 *
870 * Same as the internal routine above, except that is must lock
871 * and verify that the task is active. This differs from task_suspend
872 * in that it places a kernel hold on the task rather than just a
873 * user-level hold. This keeps users from over resuming and setting
874 * it running out from under the kernel.
875 *
876 * CONDITIONS: the caller holds a reference on the task
877 */
878 kern_return_t
879 task_hold(
880 register task_t task)
881 {
882 if (task == TASK_NULL)
883 return (KERN_INVALID_ARGUMENT);
884
885 task_lock(task);
886
887 if (!task->active) {
888 task_unlock(task);
889
890 return (KERN_FAILURE);
891 }
892
893 task_hold_locked(task);
894 task_unlock(task);
895
896 return (KERN_SUCCESS);
897 }
898
899 /*
900 * task_wait_locked:
901 *
902 * Wait for all threads in task to stop.
903 *
904 * Conditions:
905 * Called with task locked, active, and held.
906 */
907 void
908 task_wait_locked(
909 register task_t task)
910 {
911 register thread_t thread, self;
912
913 assert(task->active);
914 assert(task->suspend_count > 0);
915
916 self = current_thread();
917
918 /*
919 * Iterate through all the threads and wait for them to
920 * stop. Do not wait for the current thread if it is within
921 * the task.
922 */
923 queue_iterate(&task->threads, thread, thread_t, task_threads) {
924 if (thread != self)
925 thread_wait(thread);
926 }
927 }
928
929 /*
930 * task_release_locked:
931 *
932 * Release a kernel hold on a task.
933 *
934 * CONDITIONS: the task is locked and active
935 */
936 void
937 task_release_locked(
938 register task_t task)
939 {
940 register thread_t thread;
941
942 assert(task->active);
943 assert(task->suspend_count > 0);
944
945 if (--task->suspend_count > 0)
946 return;
947
948 queue_iterate(&task->threads, thread, thread_t, task_threads) {
949 thread_mtx_lock(thread);
950 thread_release(thread);
951 thread_mtx_unlock(thread);
952 }
953 }
954
955 /*
956 * task_release:
957 *
958 * Same as the internal routine above, except that it must lock
959 * and verify that the task is active.
960 *
961 * CONDITIONS: The caller holds a reference to the task
962 */
963 kern_return_t
964 task_release(
965 task_t task)
966 {
967 if (task == TASK_NULL)
968 return (KERN_INVALID_ARGUMENT);
969
970 task_lock(task);
971
972 if (!task->active) {
973 task_unlock(task);
974
975 return (KERN_FAILURE);
976 }
977
978 task_release_locked(task);
979 task_unlock(task);
980
981 return (KERN_SUCCESS);
982 }
983
984 kern_return_t
985 task_threads(
986 task_t task,
987 thread_act_array_t *threads_out,
988 mach_msg_type_number_t *count)
989 {
990 mach_msg_type_number_t actual;
991 thread_t *thread_list;
992 thread_t thread;
993 vm_size_t size, size_needed;
994 void *addr;
995 unsigned int i, j;
996
997 if (task == TASK_NULL)
998 return (KERN_INVALID_ARGUMENT);
999
1000 size = 0; addr = NULL;
1001
1002 for (;;) {
1003 task_lock(task);
1004 if (!task->active) {
1005 task_unlock(task);
1006
1007 if (size != 0)
1008 kfree(addr, size);
1009
1010 return (KERN_FAILURE);
1011 }
1012
1013 actual = task->thread_count;
1014
1015 /* do we have the memory we need? */
1016 size_needed = actual * sizeof (mach_port_t);
1017 if (size_needed <= size)
1018 break;
1019
1020 /* unlock the task and allocate more memory */
1021 task_unlock(task);
1022
1023 if (size != 0)
1024 kfree(addr, size);
1025
1026 assert(size_needed > 0);
1027 size = size_needed;
1028
1029 addr = kalloc(size);
1030 if (addr == 0)
1031 return (KERN_RESOURCE_SHORTAGE);
1032 }
1033
1034 /* OK, have memory and the task is locked & active */
1035 thread_list = (thread_t *)addr;
1036
1037 i = j = 0;
1038
1039 for (thread = (thread_t)queue_first(&task->threads); i < actual;
1040 ++i, thread = (thread_t)queue_next(&thread->task_threads)) {
1041 thread_reference_internal(thread);
1042 thread_list[j++] = thread;
1043 }
1044
1045 assert(queue_end(&task->threads, (queue_entry_t)thread));
1046
1047 actual = j;
1048 size_needed = actual * sizeof (mach_port_t);
1049
1050 /* can unlock task now that we've got the thread refs */
1051 task_unlock(task);
1052
1053 if (actual == 0) {
1054 /* no threads, so return null pointer and deallocate memory */
1055
1056 *threads_out = NULL;
1057 *count = 0;
1058
1059 if (size != 0)
1060 kfree(addr, size);
1061 }
1062 else {
1063 /* if we allocated too much, must copy */
1064
1065 if (size_needed < size) {
1066 void *newaddr;
1067
1068 newaddr = kalloc(size_needed);
1069 if (newaddr == 0) {
1070 for (i = 0; i < actual; ++i)
1071 thread_deallocate(thread_list[i]);
1072 kfree(addr, size);
1073 return (KERN_RESOURCE_SHORTAGE);
1074 }
1075
1076 bcopy(addr, newaddr, size_needed);
1077 kfree(addr, size);
1078 thread_list = (thread_t *)newaddr;
1079 }
1080
1081 *threads_out = thread_list;
1082 *count = actual;
1083
1084 /* do the conversion that Mig should handle */
1085
1086 for (i = 0; i < actual; ++i)
1087 ((ipc_port_t *) thread_list)[i] = convert_thread_to_port(thread_list[i]);
1088 }
1089
1090 return (KERN_SUCCESS);
1091 }
1092
1093 /*
1094 * task_suspend:
1095 *
1096 * Implement a user-level suspension on a task.
1097 *
1098 * Conditions:
1099 * The caller holds a reference to the task
1100 */
1101 kern_return_t
1102 task_suspend(
1103 register task_t task)
1104 {
1105 if (task == TASK_NULL || task == kernel_task)
1106 return (KERN_INVALID_ARGUMENT);
1107
1108 task_lock(task);
1109
1110 if (!task->active) {
1111 task_unlock(task);
1112
1113 return (KERN_FAILURE);
1114 }
1115
1116 if (task->user_stop_count++ > 0) {
1117 /*
1118 * If the stop count was positive, the task is
1119 * already stopped and we can exit.
1120 */
1121 task_unlock(task);
1122
1123 return (KERN_SUCCESS);
1124 }
1125
1126 /*
1127 * Put a kernel-level hold on the threads in the task (all
1128 * user-level task suspensions added together represent a
1129 * single kernel-level hold). We then wait for the threads
1130 * to stop executing user code.
1131 */
1132 task_hold_locked(task);
1133 task_wait_locked(task);
1134
1135 task_unlock(task);
1136
1137 return (KERN_SUCCESS);
1138 }
1139
1140 /*
1141 * task_resume:
1142 * Release a kernel hold on a task.
1143 *
1144 * Conditions:
1145 * The caller holds a reference to the task
1146 */
1147 kern_return_t
1148 task_resume(
1149 register task_t task)
1150 {
1151 register boolean_t release = FALSE;
1152
1153 if (task == TASK_NULL || task == kernel_task)
1154 return (KERN_INVALID_ARGUMENT);
1155
1156 task_lock(task);
1157
1158 if (!task->active) {
1159 task_unlock(task);
1160
1161 return (KERN_FAILURE);
1162 }
1163
1164 if (task->user_stop_count > 0) {
1165 if (--task->user_stop_count == 0)
1166 release = TRUE;
1167 }
1168 else {
1169 task_unlock(task);
1170
1171 return (KERN_FAILURE);
1172 }
1173
1174 /*
1175 * Release the task if necessary.
1176 */
1177 if (release)
1178 task_release_locked(task);
1179
1180 task_unlock(task);
1181
1182 return (KERN_SUCCESS);
1183 }
1184
1185 kern_return_t
1186 host_security_set_task_token(
1187 host_security_t host_security,
1188 task_t task,
1189 security_token_t sec_token,
1190 audit_token_t audit_token,
1191 host_priv_t host_priv)
1192 {
1193 ipc_port_t host_port;
1194 kern_return_t kr;
1195
1196 if (task == TASK_NULL)
1197 return(KERN_INVALID_ARGUMENT);
1198
1199 if (host_security == HOST_NULL)
1200 return(KERN_INVALID_SECURITY);
1201
1202 task_lock(task);
1203 task->sec_token = sec_token;
1204 task->audit_token = audit_token;
1205 task_unlock(task);
1206
1207 if (host_priv != HOST_PRIV_NULL) {
1208 kr = host_get_host_priv_port(host_priv, &host_port);
1209 } else {
1210 kr = host_get_host_port(host_priv_self(), &host_port);
1211 }
1212 assert(kr == KERN_SUCCESS);
1213 kr = task_set_special_port(task, TASK_HOST_PORT, host_port);
1214 return(kr);
1215 }
1216
1217 /*
1218 * Utility routine to set a ledger
1219 */
1220 kern_return_t
1221 task_set_ledger(
1222 task_t task,
1223 ledger_t wired,
1224 ledger_t paged)
1225 {
1226 if (task == TASK_NULL)
1227 return(KERN_INVALID_ARGUMENT);
1228
1229 task_lock(task);
1230 if (wired) {
1231 ipc_port_release_send(task->wired_ledger_port);
1232 task->wired_ledger_port = ledger_copy(wired);
1233 }
1234 if (paged) {
1235 ipc_port_release_send(task->paged_ledger_port);
1236 task->paged_ledger_port = ledger_copy(paged);
1237 }
1238 task_unlock(task);
1239
1240 return(KERN_SUCCESS);
1241 }
1242
1243 /*
1244 * This routine was added, pretty much exclusively, for registering the
1245 * RPC glue vector for in-kernel short circuited tasks. Rather than
1246 * removing it completely, I have only disabled that feature (which was
1247 * the only feature at the time). It just appears that we are going to
1248 * want to add some user data to tasks in the future (i.e. bsd info,
1249 * task names, etc...), so I left it in the formal task interface.
1250 */
1251 kern_return_t
1252 task_set_info(
1253 task_t task,
1254 task_flavor_t flavor,
1255 __unused task_info_t task_info_in, /* pointer to IN array */
1256 __unused mach_msg_type_number_t task_info_count)
1257 {
1258 if (task == TASK_NULL)
1259 return(KERN_INVALID_ARGUMENT);
1260
1261 switch (flavor) {
1262 default:
1263 return (KERN_INVALID_ARGUMENT);
1264 }
1265 return (KERN_SUCCESS);
1266 }
1267
1268 kern_return_t
1269 task_info(
1270 task_t task,
1271 task_flavor_t flavor,
1272 task_info_t task_info_out,
1273 mach_msg_type_number_t *task_info_count)
1274 {
1275 kern_return_t error = KERN_SUCCESS;
1276
1277 if (task == TASK_NULL)
1278 return (KERN_INVALID_ARGUMENT);
1279
1280 task_lock(task);
1281
1282 if ((task != current_task()) && (!task->active)) {
1283 task_unlock(task);
1284 return (KERN_INVALID_ARGUMENT);
1285 }
1286
1287 switch (flavor) {
1288
1289 case TASK_BASIC_INFO_32:
1290 case TASK_BASIC2_INFO_32:
1291 {
1292 task_basic_info_32_t basic_info;
1293 vm_map_t map;
1294 clock_sec_t secs;
1295 clock_usec_t usecs;
1296
1297 if (*task_info_count < TASK_BASIC_INFO_32_COUNT) {
1298 error = KERN_INVALID_ARGUMENT;
1299 break;
1300 }
1301
1302 basic_info = (task_basic_info_32_t)task_info_out;
1303
1304 map = (task == kernel_task)? kernel_map: task->map;
1305 basic_info->virtual_size = (typeof(basic_info->virtual_size))map->size;
1306 if (flavor == TASK_BASIC2_INFO_32) {
1307 /*
1308 * The "BASIC2" flavor gets the maximum resident
1309 * size instead of the current resident size...
1310 */
1311 basic_info->resident_size = pmap_resident_max(map->pmap);
1312 } else {
1313 basic_info->resident_size = pmap_resident_count(map->pmap);
1314 }
1315 basic_info->resident_size *= PAGE_SIZE;
1316
1317 basic_info->policy = ((task != kernel_task)?
1318 POLICY_TIMESHARE: POLICY_RR);
1319 basic_info->suspend_count = task->user_stop_count;
1320
1321 absolutetime_to_microtime(task->total_user_time, &secs, &usecs);
1322 basic_info->user_time.seconds =
1323 (typeof(basic_info->user_time.seconds))secs;
1324 basic_info->user_time.microseconds = usecs;
1325
1326 absolutetime_to_microtime(task->total_system_time, &secs, &usecs);
1327 basic_info->system_time.seconds =
1328 (typeof(basic_info->system_time.seconds))secs;
1329 basic_info->system_time.microseconds = usecs;
1330
1331 *task_info_count = TASK_BASIC_INFO_32_COUNT;
1332 break;
1333 }
1334
1335 case TASK_BASIC_INFO_64:
1336 {
1337 task_basic_info_64_t basic_info;
1338 vm_map_t map;
1339 clock_sec_t secs;
1340 clock_usec_t usecs;
1341
1342 if (*task_info_count < TASK_BASIC_INFO_64_COUNT) {
1343 error = KERN_INVALID_ARGUMENT;
1344 break;
1345 }
1346
1347 basic_info = (task_basic_info_64_t)task_info_out;
1348
1349 map = (task == kernel_task)? kernel_map: task->map;
1350 basic_info->virtual_size = map->size;
1351 basic_info->resident_size =
1352 (mach_vm_size_t)(pmap_resident_count(map->pmap))
1353 * PAGE_SIZE_64;
1354
1355 basic_info->policy = ((task != kernel_task)?
1356 POLICY_TIMESHARE: POLICY_RR);
1357 basic_info->suspend_count = task->user_stop_count;
1358
1359 absolutetime_to_microtime(task->total_user_time, &secs, &usecs);
1360 basic_info->user_time.seconds =
1361 (typeof(basic_info->user_time.seconds))secs;
1362 basic_info->user_time.microseconds = usecs;
1363
1364 absolutetime_to_microtime(task->total_system_time, &secs, &usecs);
1365 basic_info->system_time.seconds =
1366 (typeof(basic_info->system_time.seconds))secs;
1367 basic_info->system_time.microseconds = usecs;
1368
1369 *task_info_count = TASK_BASIC_INFO_64_COUNT;
1370 break;
1371 }
1372
1373 case TASK_THREAD_TIMES_INFO:
1374 {
1375 register task_thread_times_info_t times_info;
1376 register thread_t thread;
1377
1378 if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
1379 error = KERN_INVALID_ARGUMENT;
1380 break;
1381 }
1382
1383 times_info = (task_thread_times_info_t) task_info_out;
1384 times_info->user_time.seconds = 0;
1385 times_info->user_time.microseconds = 0;
1386 times_info->system_time.seconds = 0;
1387 times_info->system_time.microseconds = 0;
1388
1389
1390 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1391 time_value_t user_time, system_time;
1392
1393 thread_read_times(thread, &user_time, &system_time);
1394
1395 time_value_add(&times_info->user_time, &user_time);
1396 time_value_add(&times_info->system_time, &system_time);
1397 }
1398
1399
1400 *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
1401 break;
1402 }
1403
1404 case TASK_ABSOLUTETIME_INFO:
1405 {
1406 task_absolutetime_info_t info;
1407 register thread_t thread;
1408
1409 if (*task_info_count < TASK_ABSOLUTETIME_INFO_COUNT) {
1410 error = KERN_INVALID_ARGUMENT;
1411 break;
1412 }
1413
1414 info = (task_absolutetime_info_t)task_info_out;
1415 info->threads_user = info->threads_system = 0;
1416
1417
1418 info->total_user = task->total_user_time;
1419 info->total_system = task->total_system_time;
1420
1421 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1422 uint64_t tval;
1423
1424 tval = timer_grab(&thread->user_timer);
1425 info->threads_user += tval;
1426 info->total_user += tval;
1427
1428 tval = timer_grab(&thread->system_timer);
1429 info->threads_system += tval;
1430 info->total_system += tval;
1431 }
1432
1433
1434 *task_info_count = TASK_ABSOLUTETIME_INFO_COUNT;
1435 break;
1436 }
1437
1438 case TASK_DYLD_INFO:
1439 {
1440 task_dyld_info_t info;
1441
1442 if (*task_info_count < TASK_DYLD_INFO_COUNT) {
1443 error = KERN_INVALID_ARGUMENT;
1444 break;
1445 }
1446 info = (task_dyld_info_t)task_info_out;
1447 info->all_image_info_addr = task->all_image_info_addr;
1448 info->all_image_info_size = task->all_image_info_size;
1449 *task_info_count = TASK_DYLD_INFO_COUNT;
1450 break;
1451 }
1452
1453 /* OBSOLETE */
1454 case TASK_SCHED_FIFO_INFO:
1455 {
1456
1457 if (*task_info_count < POLICY_FIFO_BASE_COUNT) {
1458 error = KERN_INVALID_ARGUMENT;
1459 break;
1460 }
1461
1462 error = KERN_INVALID_POLICY;
1463 }
1464
1465 /* OBSOLETE */
1466 case TASK_SCHED_RR_INFO:
1467 {
1468 register policy_rr_base_t rr_base;
1469
1470 if (*task_info_count < POLICY_RR_BASE_COUNT) {
1471 error = KERN_INVALID_ARGUMENT;
1472 break;
1473 }
1474
1475 rr_base = (policy_rr_base_t) task_info_out;
1476
1477 if (task != kernel_task) {
1478 error = KERN_INVALID_POLICY;
1479 break;
1480 }
1481
1482 rr_base->base_priority = task->priority;
1483
1484 rr_base->quantum = std_quantum_us / 1000;
1485
1486 *task_info_count = POLICY_RR_BASE_COUNT;
1487 break;
1488 }
1489
1490 /* OBSOLETE */
1491 case TASK_SCHED_TIMESHARE_INFO:
1492 {
1493 register policy_timeshare_base_t ts_base;
1494
1495 if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT) {
1496 error = KERN_INVALID_ARGUMENT;
1497 break;
1498 }
1499
1500 ts_base = (policy_timeshare_base_t) task_info_out;
1501
1502 if (task == kernel_task) {
1503 error = KERN_INVALID_POLICY;
1504 break;
1505 }
1506
1507 ts_base->base_priority = task->priority;
1508
1509 *task_info_count = POLICY_TIMESHARE_BASE_COUNT;
1510 break;
1511 }
1512
1513 case TASK_SECURITY_TOKEN:
1514 {
1515 register security_token_t *sec_token_p;
1516
1517 if (*task_info_count < TASK_SECURITY_TOKEN_COUNT) {
1518 error = KERN_INVALID_ARGUMENT;
1519 break;
1520 }
1521
1522 sec_token_p = (security_token_t *) task_info_out;
1523
1524 *sec_token_p = task->sec_token;
1525
1526 *task_info_count = TASK_SECURITY_TOKEN_COUNT;
1527 break;
1528 }
1529
1530 case TASK_AUDIT_TOKEN:
1531 {
1532 register audit_token_t *audit_token_p;
1533
1534 if (*task_info_count < TASK_AUDIT_TOKEN_COUNT) {
1535 error = KERN_INVALID_ARGUMENT;
1536 break;
1537 }
1538
1539 audit_token_p = (audit_token_t *) task_info_out;
1540
1541 *audit_token_p = task->audit_token;
1542
1543 *task_info_count = TASK_AUDIT_TOKEN_COUNT;
1544 break;
1545 }
1546
1547 case TASK_SCHED_INFO:
1548 error = KERN_INVALID_ARGUMENT;
1549
1550 case TASK_EVENTS_INFO:
1551 {
1552 register task_events_info_t events_info;
1553 register thread_t thread;
1554
1555 if (*task_info_count < TASK_EVENTS_INFO_COUNT) {
1556 error = KERN_INVALID_ARGUMENT;
1557 break;
1558 }
1559
1560 events_info = (task_events_info_t) task_info_out;
1561
1562
1563 events_info->faults = task->faults;
1564 events_info->pageins = task->pageins;
1565 events_info->cow_faults = task->cow_faults;
1566 events_info->messages_sent = task->messages_sent;
1567 events_info->messages_received = task->messages_received;
1568 events_info->syscalls_mach = task->syscalls_mach;
1569 events_info->syscalls_unix = task->syscalls_unix;
1570
1571 events_info->csw = task->c_switch;
1572
1573 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1574 events_info->csw += thread->c_switch;
1575 }
1576
1577
1578 *task_info_count = TASK_EVENTS_INFO_COUNT;
1579 break;
1580 }
1581 case TASK_AFFINITY_TAG_INFO:
1582 {
1583 if (*task_info_count < TASK_AFFINITY_TAG_INFO_COUNT) {
1584 error = KERN_INVALID_ARGUMENT;
1585 break;
1586 }
1587
1588 error = task_affinity_info(task, task_info_out, task_info_count);
1589 }
1590
1591 default:
1592 error = KERN_INVALID_ARGUMENT;
1593 }
1594
1595 task_unlock(task);
1596 return (error);
1597 }
1598
1599 void
1600 task_vtimer_set(
1601 task_t task,
1602 integer_t which)
1603 {
1604 thread_t thread;
1605
1606 /* assert(task == current_task()); */ /* bogus assert 4803227 4807483 */
1607
1608 task_lock(task);
1609
1610 task->vtimers |= which;
1611
1612 switch (which) {
1613
1614 case TASK_VTIMER_USER:
1615 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1616 thread->vtimer_user_save = timer_grab(&thread->user_timer);
1617 }
1618 break;
1619
1620 case TASK_VTIMER_PROF:
1621 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1622 thread->vtimer_prof_save = timer_grab(&thread->user_timer);
1623 thread->vtimer_prof_save += timer_grab(&thread->system_timer);
1624 }
1625 break;
1626
1627 case TASK_VTIMER_RLIM:
1628 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1629 thread->vtimer_rlim_save = timer_grab(&thread->user_timer);
1630 thread->vtimer_rlim_save += timer_grab(&thread->system_timer);
1631 }
1632 break;
1633 }
1634
1635 task_unlock(task);
1636 }
1637
1638 void
1639 task_vtimer_clear(
1640 task_t task,
1641 integer_t which)
1642 {
1643 assert(task == current_task());
1644
1645 task_lock(task);
1646
1647 task->vtimers &= ~which;
1648
1649 task_unlock(task);
1650 }
1651
1652 void
1653 task_vtimer_update(
1654 __unused
1655 task_t task,
1656 integer_t which,
1657 uint32_t *microsecs)
1658 {
1659 thread_t thread = current_thread();
1660 uint32_t tdelt;
1661 clock_sec_t secs;
1662 uint64_t tsum;
1663
1664 assert(task == current_task());
1665
1666 assert(task->vtimers & which);
1667
1668 secs = tdelt = 0;
1669
1670 switch (which) {
1671
1672 case TASK_VTIMER_USER:
1673 tdelt = (uint32_t)timer_delta(&thread->user_timer,
1674 &thread->vtimer_user_save);
1675 absolutetime_to_microtime(tdelt, &secs, microsecs);
1676 break;
1677
1678 case TASK_VTIMER_PROF:
1679 tsum = timer_grab(&thread->user_timer);
1680 tsum += timer_grab(&thread->system_timer);
1681 tdelt = (uint32_t)(tsum - thread->vtimer_prof_save);
1682 absolutetime_to_microtime(tdelt, &secs, microsecs);
1683 /* if the time delta is smaller than a usec, ignore */
1684 if (*microsecs != 0)
1685 thread->vtimer_prof_save = tsum;
1686 break;
1687
1688 case TASK_VTIMER_RLIM:
1689 tsum = timer_grab(&thread->user_timer);
1690 tsum += timer_grab(&thread->system_timer);
1691 tdelt = (uint32_t)(tsum - thread->vtimer_rlim_save);
1692 thread->vtimer_rlim_save = tsum;
1693 absolutetime_to_microtime(tdelt, &secs, microsecs);
1694 break;
1695 }
1696
1697 }
1698
1699 /*
1700 * task_assign:
1701 *
1702 * Change the assigned processor set for the task
1703 */
1704 kern_return_t
1705 task_assign(
1706 __unused task_t task,
1707 __unused processor_set_t new_pset,
1708 __unused boolean_t assign_threads)
1709 {
1710 return(KERN_FAILURE);
1711 }
1712
1713 /*
1714 * task_assign_default:
1715 *
1716 * Version of task_assign to assign to default processor set.
1717 */
1718 kern_return_t
1719 task_assign_default(
1720 task_t task,
1721 boolean_t assign_threads)
1722 {
1723 return (task_assign(task, &pset0, assign_threads));
1724 }
1725
1726 /*
1727 * task_get_assignment
1728 *
1729 * Return name of processor set that task is assigned to.
1730 */
1731 kern_return_t
1732 task_get_assignment(
1733 task_t task,
1734 processor_set_t *pset)
1735 {
1736 if (!task->active)
1737 return(KERN_FAILURE);
1738
1739 *pset = &pset0;
1740
1741 return (KERN_SUCCESS);
1742 }
1743
1744
1745 /*
1746 * task_policy
1747 *
1748 * Set scheduling policy and parameters, both base and limit, for
1749 * the given task. Policy must be a policy which is enabled for the
1750 * processor set. Change contained threads if requested.
1751 */
1752 kern_return_t
1753 task_policy(
1754 __unused task_t task,
1755 __unused policy_t policy_id,
1756 __unused policy_base_t base,
1757 __unused mach_msg_type_number_t count,
1758 __unused boolean_t set_limit,
1759 __unused boolean_t change)
1760 {
1761 return(KERN_FAILURE);
1762 }
1763
1764 /*
1765 * task_set_policy
1766 *
1767 * Set scheduling policy and parameters, both base and limit, for
1768 * the given task. Policy can be any policy implemented by the
1769 * processor set, whether enabled or not. Change contained threads
1770 * if requested.
1771 */
1772 kern_return_t
1773 task_set_policy(
1774 __unused task_t task,
1775 __unused processor_set_t pset,
1776 __unused policy_t policy_id,
1777 __unused policy_base_t base,
1778 __unused mach_msg_type_number_t base_count,
1779 __unused policy_limit_t limit,
1780 __unused mach_msg_type_number_t limit_count,
1781 __unused boolean_t change)
1782 {
1783 return(KERN_FAILURE);
1784 }
1785
1786 #if FAST_TAS
1787 kern_return_t
1788 task_set_ras_pc(
1789 task_t task,
1790 vm_offset_t pc,
1791 vm_offset_t endpc)
1792 {
1793 extern int fast_tas_debug;
1794
1795 if (fast_tas_debug) {
1796 printf("task 0x%x: setting fast_tas to [0x%x, 0x%x]\n",
1797 task, pc, endpc);
1798 }
1799 task_lock(task);
1800 task->fast_tas_base = pc;
1801 task->fast_tas_end = endpc;
1802 task_unlock(task);
1803 return KERN_SUCCESS;
1804 }
1805 #else /* FAST_TAS */
1806 kern_return_t
1807 task_set_ras_pc(
1808 __unused task_t task,
1809 __unused vm_offset_t pc,
1810 __unused vm_offset_t endpc)
1811 {
1812 return KERN_FAILURE;
1813 }
1814 #endif /* FAST_TAS */
1815
1816 void
1817 task_synchronizer_destroy_all(task_t task)
1818 {
1819 semaphore_t semaphore;
1820 lock_set_t lock_set;
1821
1822 /*
1823 * Destroy owned semaphores
1824 */
1825
1826 while (!queue_empty(&task->semaphore_list)) {
1827 semaphore = (semaphore_t) queue_first(&task->semaphore_list);
1828 (void) semaphore_destroy(task, semaphore);
1829 }
1830
1831 /*
1832 * Destroy owned lock sets
1833 */
1834
1835 while (!queue_empty(&task->lock_set_list)) {
1836 lock_set = (lock_set_t) queue_first(&task->lock_set_list);
1837 (void) lock_set_destroy(task, lock_set);
1838 }
1839 }
1840
1841 /*
1842 * Install default (machine-dependent) initial thread state
1843 * on the task. Subsequent thread creation will have this initial
1844 * state set on the thread by machine_thread_inherit_taskwide().
1845 * Flavors and structures are exactly the same as those to thread_set_state()
1846 */
1847 kern_return_t
1848 task_set_state(
1849 task_t task,
1850 int flavor,
1851 thread_state_t state,
1852 mach_msg_type_number_t state_count)
1853 {
1854 kern_return_t ret;
1855
1856 if (task == TASK_NULL) {
1857 return (KERN_INVALID_ARGUMENT);
1858 }
1859
1860 task_lock(task);
1861
1862 if (!task->active) {
1863 task_unlock(task);
1864 return (KERN_FAILURE);
1865 }
1866
1867 ret = machine_task_set_state(task, flavor, state, state_count);
1868
1869 task_unlock(task);
1870 return ret;
1871 }
1872
1873 /*
1874 * Examine the default (machine-dependent) initial thread state
1875 * on the task, as set by task_set_state(). Flavors and structures
1876 * are exactly the same as those passed to thread_get_state().
1877 */
1878 kern_return_t
1879 task_get_state(
1880 task_t task,
1881 int flavor,
1882 thread_state_t state,
1883 mach_msg_type_number_t *state_count)
1884 {
1885 kern_return_t ret;
1886
1887 if (task == TASK_NULL) {
1888 return (KERN_INVALID_ARGUMENT);
1889 }
1890
1891 task_lock(task);
1892
1893 if (!task->active) {
1894 task_unlock(task);
1895 return (KERN_FAILURE);
1896 }
1897
1898 ret = machine_task_get_state(task, flavor, state, state_count);
1899
1900 task_unlock(task);
1901 return ret;
1902 }
1903
1904
1905 /*
1906 * We need to export some functions to other components that
1907 * are currently implemented in macros within the osfmk
1908 * component. Just export them as functions of the same name.
1909 */
1910 boolean_t is_kerneltask(task_t t)
1911 {
1912 if (t == kernel_task)
1913 return (TRUE);
1914
1915 return (FALSE);
1916 }
1917
1918 int
1919 check_for_tasksuspend(task_t task)
1920 {
1921
1922 if (task == TASK_NULL)
1923 return (0);
1924
1925 return (task->suspend_count > 0);
1926 }
1927
1928 #undef current_task
1929 task_t current_task(void);
1930 task_t current_task(void)
1931 {
1932 return (current_task_fast());
1933 }
1934
1935 #undef task_reference
1936 void task_reference(task_t task);
1937 void
1938 task_reference(
1939 task_t task)
1940 {
1941 if (task != TASK_NULL)
1942 task_reference_internal(task);
1943 }
1944
1945 #if CONFIG_MACF_MACH
1946 /*
1947 * Protect 2 task labels against modification by adding a reference on
1948 * both label handles. The locks do not actually have to be held while
1949 * using the labels as only labels with one reference can be modified
1950 * in place.
1951 */
1952
1953 void
1954 tasklabel_lock2(
1955 task_t a,
1956 task_t b)
1957 {
1958 labelh_reference(a->label);
1959 labelh_reference(b->label);
1960 }
1961
1962 void
1963 tasklabel_unlock2(
1964 task_t a,
1965 task_t b)
1966 {
1967 labelh_release(a->label);
1968 labelh_release(b->label);
1969 }
1970
1971 void
1972 mac_task_label_update_internal(
1973 struct label *pl,
1974 struct task *task)
1975 {
1976
1977 tasklabel_lock(task);
1978 task->label = labelh_modify(task->label);
1979 mac_task_label_update(pl, &task->maclabel);
1980 tasklabel_unlock(task);
1981 ip_lock(task->itk_self);
1982 mac_port_label_update_cred(pl, &task->itk_self->ip_label);
1983 ip_unlock(task->itk_self);
1984 }
1985
1986 void
1987 mac_task_label_modify(
1988 struct task *task,
1989 void *arg,
1990 void (*f) (struct label *l, void *arg))
1991 {
1992
1993 tasklabel_lock(task);
1994 task->label = labelh_modify(task->label);
1995 (*f)(&task->maclabel, arg);
1996 tasklabel_unlock(task);
1997 }
1998
1999 struct label *
2000 mac_task_get_label(struct task *task)
2001 {
2002 return (&task->maclabel);
2003 }
2004 #endif