]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/task.c
b7dd9076504224de41cecc72cf4ebbaee6764f35
[apple/xnu.git] / osfmk / kern / task.c
1 /*
2 * Copyright (c) 2000-2008 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 * Exported interfaces
141 */
142
143 #include <mach/task_server.h>
144 #include <mach/mach_host_server.h>
145 #include <mach/host_security_server.h>
146 #include <mach/mach_port_server.h>
147 #include <mach/security_server.h>
148
149 #include <vm/vm_shared_region.h>
150
151 #if CONFIG_MACF_MACH
152 #include <security/mac_mach_internal.h>
153 #endif
154
155 task_t kernel_task;
156 zone_t task_zone;
157
158 /* Forwards */
159
160 void task_hold_locked(
161 task_t task);
162 void task_wait_locked(
163 task_t task);
164 void task_release_locked(
165 task_t task);
166 void task_free(
167 task_t task );
168 void task_synchronizer_destroy_all(
169 task_t task);
170
171 kern_return_t task_set_ledger(
172 task_t task,
173 ledger_t wired,
174 ledger_t paged);
175
176 void
177 task_backing_store_privileged(
178 task_t task)
179 {
180 task_lock(task);
181 task->priv_flags |= VM_BACKING_STORE_PRIV;
182 task_unlock(task);
183 return;
184 }
185
186
187 void
188 task_set_64bit(
189 task_t task,
190 boolean_t is64bit)
191 {
192 #ifdef __i386__
193 thread_t thread;
194 #endif /* __i386__ */
195 int vm_flags = 0;
196
197 if (is64bit) {
198 if (task_has_64BitAddr(task))
199 return;
200
201 task_set_64BitAddr(task);
202 } else {
203 if ( !task_has_64BitAddr(task))
204 return;
205
206 /*
207 * Deallocate all memory previously allocated
208 * above the 32-bit address space, since it won't
209 * be accessible anymore.
210 */
211 /* remove regular VM map entries & pmap mappings */
212 (void) vm_map_remove(task->map,
213 (vm_map_offset_t) VM_MAX_ADDRESS,
214 MACH_VM_MAX_ADDRESS,
215 0);
216 #ifdef __ppc__
217 /* LP64todo - make this clean */
218 /*
219 * PPC51: ppc64 is limited to 51-bit addresses.
220 * Memory mapped above that limit is handled specially
221 * at the pmap level, so let pmap clean the commpage mapping
222 * explicitly...
223 */
224 pmap_unmap_sharedpage(task->map->pmap); /* Unmap commpage */
225 /* ... and avoid regular pmap cleanup */
226 vm_flags |= VM_MAP_REMOVE_NO_PMAP_CLEANUP;
227 #endif /* __ppc__ */
228 /* remove the higher VM mappings */
229 (void) vm_map_remove(task->map,
230 MACH_VM_MAX_ADDRESS,
231 0xFFFFFFFFFFFFF000ULL,
232 vm_flags);
233 task_clear_64BitAddr(task);
234 }
235 /* FIXME: On x86, the thread save state flavor can diverge from the
236 * task's 64-bit feature flag due to the 32-bit/64-bit register save
237 * state dichotomy. Since we can be pre-empted in this interval,
238 * certain routines may observe the thread as being in an inconsistent
239 * state with respect to its task's 64-bitness.
240 */
241 #ifdef __i386__
242 queue_iterate(&task->threads, thread, thread_t, task_threads) {
243 machine_thread_switch_addrmode(thread);
244 }
245 #endif /* __i386__ */
246 }
247
248 void
249 task_init(void)
250 {
251 task_zone = zinit(
252 sizeof(struct task),
253 TASK_MAX * sizeof(struct task),
254 TASK_CHUNK * sizeof(struct task),
255 "tasks");
256
257 /*
258 * Create the kernel task as the first task.
259 */
260 if (task_create_internal(TASK_NULL, FALSE, FALSE, &kernel_task) != KERN_SUCCESS)
261 panic("task_init\n");
262
263 vm_map_deallocate(kernel_task->map);
264 kernel_task->map = kernel_map;
265 }
266
267 /*
268 * Create a task running in the kernel address space. It may
269 * have its own map of size mem_size and may have ipc privileges.
270 */
271 kern_return_t
272 kernel_task_create(
273 __unused task_t parent_task,
274 __unused vm_offset_t map_base,
275 __unused vm_size_t map_size,
276 __unused task_t *child_task)
277 {
278 return (KERN_INVALID_ARGUMENT);
279 }
280
281 kern_return_t
282 task_create(
283 task_t parent_task,
284 __unused ledger_port_array_t ledger_ports,
285 __unused mach_msg_type_number_t num_ledger_ports,
286 __unused boolean_t inherit_memory,
287 __unused task_t *child_task) /* OUT */
288 {
289 if (parent_task == TASK_NULL)
290 return(KERN_INVALID_ARGUMENT);
291
292 /*
293 * No longer supported: too many calls assume that a task has a valid
294 * process attached.
295 */
296 return(KERN_FAILURE);
297 }
298
299 kern_return_t
300 host_security_create_task_token(
301 host_security_t host_security,
302 task_t parent_task,
303 __unused security_token_t sec_token,
304 __unused audit_token_t audit_token,
305 __unused host_priv_t host_priv,
306 __unused ledger_port_array_t ledger_ports,
307 __unused mach_msg_type_number_t num_ledger_ports,
308 __unused boolean_t inherit_memory,
309 __unused task_t *child_task) /* OUT */
310 {
311 if (parent_task == TASK_NULL)
312 return(KERN_INVALID_ARGUMENT);
313
314 if (host_security == HOST_NULL)
315 return(KERN_INVALID_SECURITY);
316
317 /*
318 * No longer supported.
319 */
320 return(KERN_FAILURE);
321 }
322
323 kern_return_t
324 task_create_internal(
325 task_t parent_task,
326 boolean_t inherit_memory,
327 boolean_t is_64bit,
328 task_t *child_task) /* OUT */
329 {
330 task_t new_task;
331 vm_shared_region_t shared_region;
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, is_64bit),
345 (vm_map_offset_t)(VM_MIN_ADDRESS),
346 (vm_map_offset_t)(VM_MAX_ADDRESS), TRUE);
347
348 /* Inherit memlock limit from parent */
349 if (parent_task)
350 vm_map_set_user_wire_limit(new_task->map, parent_task->map->user_wire_limit);
351
352 mutex_init(&new_task->lock, 0);
353 queue_init(&new_task->threads);
354 new_task->suspend_count = 0;
355 new_task->thread_count = 0;
356 new_task->active_thread_count = 0;
357 new_task->user_stop_count = 0;
358 new_task->pset_hint = PROCESSOR_SET_NULL;
359 new_task->role = TASK_UNSPECIFIED;
360 new_task->active = TRUE;
361 new_task->user_data = NULL;
362 new_task->faults = 0;
363 new_task->cow_faults = 0;
364 new_task->pageins = 0;
365 new_task->messages_sent = 0;
366 new_task->messages_received = 0;
367 new_task->syscalls_mach = 0;
368 new_task->priv_flags = 0;
369 new_task->syscalls_unix=0;
370 new_task->c_switch = new_task->p_switch = new_task->ps_switch = 0;
371 new_task->taskFeatures[0] = 0; /* Init task features */
372 new_task->taskFeatures[1] = 0; /* Init task features */
373
374 #ifdef MACH_BSD
375 new_task->bsd_info = NULL;
376 #endif /* MACH_BSD */
377
378 #ifdef __i386__
379 new_task->i386_ldt = 0;
380 #endif
381
382 #ifdef __ppc__
383 if(BootProcInfo.pf.Available & pf64Bit) new_task->taskFeatures[0] |= tf64BitData; /* If 64-bit machine, show we have 64-bit registers at least */
384 #endif
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 CONFIG_MACF_MACH
392 /*mutex_init(&new_task->labellock, ETAP_NO_TRACE);*/
393 new_task->label = labelh_new(1);
394 mac_task_label_init (&new_task->maclabel);
395 #endif
396
397 ipc_task_init(new_task, parent_task);
398
399 new_task->total_user_time = 0;
400 new_task->total_system_time = 0;
401
402 new_task->vtimers = 0;
403
404 new_task->shared_region = NULL;
405
406 new_task->affinity_space = NULL;
407
408 if (parent_task != TASK_NULL) {
409 new_task->sec_token = parent_task->sec_token;
410 new_task->audit_token = parent_task->audit_token;
411
412 /* inherit the parent's shared region */
413 shared_region = vm_shared_region_get(parent_task);
414 vm_shared_region_set(new_task, shared_region);
415
416 new_task->wired_ledger_port = ledger_copy(
417 convert_port_to_ledger(parent_task->wired_ledger_port));
418 new_task->paged_ledger_port = ledger_copy(
419 convert_port_to_ledger(parent_task->paged_ledger_port));
420 if(task_has_64BitAddr(parent_task))
421 task_set_64BitAddr(new_task);
422
423 #ifdef __i386__
424 if (inherit_memory && parent_task->i386_ldt)
425 new_task->i386_ldt = user_ldt_copy(parent_task->i386_ldt);
426 #endif
427 if (inherit_memory && parent_task->affinity_space)
428 task_affinity_create(parent_task, new_task);
429 }
430 else {
431 new_task->sec_token = KERNEL_SECURITY_TOKEN;
432 new_task->audit_token = KERNEL_AUDIT_TOKEN;
433 new_task->wired_ledger_port = ledger_copy(root_wired_ledger);
434 new_task->paged_ledger_port = ledger_copy(root_paged_ledger);
435 }
436
437 if (kernel_task == TASK_NULL) {
438 new_task->priority = BASEPRI_KERNEL;
439 new_task->max_priority = MAXPRI_KERNEL;
440 }
441 else {
442 new_task->priority = BASEPRI_DEFAULT;
443 new_task->max_priority = MAXPRI_USER;
444 }
445
446 mutex_lock(&tasks_threads_lock);
447 queue_enter(&tasks, new_task, task_t, tasks);
448 tasks_count++;
449 mutex_unlock(&tasks_threads_lock);
450
451 if (vm_backing_store_low && parent_task != NULL)
452 new_task->priv_flags |= (parent_task->priv_flags&VM_BACKING_STORE_PRIV);
453
454 ipc_task_enable(new_task);
455
456 *child_task = new_task;
457 return(KERN_SUCCESS);
458 }
459
460 /*
461 * task_deallocate:
462 *
463 * Drop a reference on a task.
464 */
465 void
466 task_deallocate(
467 task_t task)
468 {
469 if (task == TASK_NULL)
470 return;
471
472 if (task_deallocate_internal(task) > 0)
473 return;
474
475 ipc_task_terminate(task);
476
477 if (task->affinity_space)
478 task_affinity_deallocate(task);
479
480 vm_map_deallocate(task->map);
481 is_release(task->itk_space);
482
483 #if CONFIG_MACF_MACH
484 labelh_release(task->label);
485 #endif
486 zfree(task_zone, task);
487 }
488
489 /*
490 * task_name_deallocate:
491 *
492 * Drop a reference on a task name.
493 */
494 void
495 task_name_deallocate(
496 task_name_t task_name)
497 {
498 return(task_deallocate((task_t)task_name));
499 }
500
501
502 /*
503 * task_terminate:
504 *
505 * Terminate the specified task. See comments on thread_terminate
506 * (kern/thread.c) about problems with terminating the "current task."
507 */
508
509 kern_return_t
510 task_terminate(
511 task_t task)
512 {
513 if (task == TASK_NULL)
514 return (KERN_INVALID_ARGUMENT);
515
516 if (task->bsd_info)
517 return (KERN_FAILURE);
518
519 return (task_terminate_internal(task));
520 }
521
522 kern_return_t
523 task_terminate_internal(
524 task_t task)
525 {
526 thread_t thread, self;
527 task_t self_task;
528 boolean_t interrupt_save;
529
530 assert(task != kernel_task);
531
532 self = current_thread();
533 self_task = self->task;
534
535 /*
536 * Get the task locked and make sure that we are not racing
537 * with someone else trying to terminate us.
538 */
539 if (task == self_task)
540 task_lock(task);
541 else
542 if (task < self_task) {
543 task_lock(task);
544 task_lock(self_task);
545 }
546 else {
547 task_lock(self_task);
548 task_lock(task);
549 }
550
551 if (!task->active || !self->active) {
552 /*
553 * Task or current act is already being terminated.
554 * Just return an error. If we are dying, this will
555 * just get us to our AST special handler and that
556 * will get us to finalize the termination of ourselves.
557 */
558 task_unlock(task);
559 if (self_task != task)
560 task_unlock(self_task);
561
562 return (KERN_FAILURE);
563 }
564
565 if (self_task != task)
566 task_unlock(self_task);
567
568 /*
569 * Make sure the current thread does not get aborted out of
570 * the waits inside these operations.
571 */
572 interrupt_save = thread_interrupt_level(THREAD_UNINT);
573
574 /*
575 * Indicate that we want all the threads to stop executing
576 * at user space by holding the task (we would have held
577 * each thread independently in thread_terminate_internal -
578 * but this way we may be more likely to already find it
579 * held there). Mark the task inactive, and prevent
580 * further task operations via the task port.
581 */
582 task_hold_locked(task);
583 task->active = FALSE;
584 ipc_task_disable(task);
585
586 /*
587 * Terminate each thread in the task.
588 */
589 queue_iterate(&task->threads, thread, thread_t, task_threads) {
590 thread_terminate_internal(thread);
591 }
592
593 /*
594 * Give the machine dependent code a chance
595 * to perform cleanup before ripping apart
596 * the task.
597 */
598 if (self_task == task)
599 machine_thread_terminate_self();
600
601 task_unlock(task);
602
603 /*
604 * Destroy all synchronizers owned by the task.
605 */
606 task_synchronizer_destroy_all(task);
607
608 /*
609 * Destroy the IPC space, leaving just a reference for it.
610 */
611 ipc_space_destroy(task->itk_space);
612
613 #ifdef __ppc__
614 /* LP64todo - make this clean */
615 /*
616 * PPC51: ppc64 is limited to 51-bit addresses.
617 */
618 pmap_unmap_sharedpage(task->map->pmap); /* Unmap commpage */
619 #endif /* __ppc__ */
620
621 if (vm_map_has_4GB_pagezero(task->map))
622 vm_map_clear_4GB_pagezero(task->map);
623
624 /*
625 * If the current thread is a member of the task
626 * being terminated, then the last reference to
627 * the task will not be dropped until the thread
628 * is finally reaped. To avoid incurring the
629 * expense of removing the address space regions
630 * at reap time, we do it explictly here.
631 */
632 vm_map_remove(task->map,
633 task->map->min_offset,
634 task->map->max_offset,
635 VM_MAP_NO_FLAGS);
636
637 /* release our shared region */
638 vm_shared_region_set(task, NULL);
639
640 mutex_lock(&tasks_threads_lock);
641 queue_remove(&tasks, task, task_t, tasks);
642 tasks_count--;
643 mutex_unlock(&tasks_threads_lock);
644
645 /*
646 * We no longer need to guard against being aborted, so restore
647 * the previous interruptible state.
648 */
649 thread_interrupt_level(interrupt_save);
650
651 #if __ppc__
652 perfmon_release_facility(task); // notify the perfmon facility
653 #endif
654
655 /*
656 * Get rid of the task active reference on itself.
657 */
658 task_deallocate(task);
659
660 return (KERN_SUCCESS);
661 }
662
663 /*
664 * task_halt:
665 *
666 * Shut the current task down (except for the current thread) in
667 * preparation for dramatic changes to the task (probably exec).
668 * We hold the task, terminate all other threads in the task and
669 * wait for them to terminate, clean up the portspace, and when
670 * all done, let the current thread go.
671 */
672 kern_return_t
673 task_halt(
674 task_t task)
675 {
676 thread_t thread, self;
677
678 assert(task != kernel_task);
679
680 self = current_thread();
681
682 if (task != self->task)
683 return (KERN_INVALID_ARGUMENT);
684
685 task_lock(task);
686
687 if (!task->active || !self->active) {
688 /*
689 * Task or current thread is already being terminated.
690 * Hurry up and return out of the current kernel context
691 * so that we run our AST special handler to terminate
692 * ourselves.
693 */
694 task_unlock(task);
695
696 return (KERN_FAILURE);
697 }
698
699 if (task->thread_count > 1) {
700 /*
701 * Mark all the threads to keep them from starting any more
702 * user-level execution. The thread_terminate_internal code
703 * would do this on a thread by thread basis anyway, but this
704 * gives us a better chance of not having to wait there.
705 */
706 task_hold_locked(task);
707
708 /*
709 * Terminate all the other threads in the task.
710 */
711 queue_iterate(&task->threads, thread, thread_t, task_threads) {
712 if (thread != self)
713 thread_terminate_internal(thread);
714 }
715
716 task_release_locked(task);
717 }
718
719 /*
720 * Give the machine dependent code a chance
721 * to perform cleanup before ripping apart
722 * the task.
723 */
724 machine_thread_terminate_self();
725
726 task_unlock(task);
727
728 /*
729 * Destroy all synchronizers owned by the task.
730 */
731 task_synchronizer_destroy_all(task);
732
733 /*
734 * Destroy the contents of the IPC space, leaving just
735 * a reference for it.
736 */
737 ipc_space_clean(task->itk_space);
738
739 /*
740 * Clean out the address space, as we are going to be
741 * getting a new one.
742 */
743 vm_map_remove(task->map, task->map->min_offset,
744 task->map->max_offset, VM_MAP_NO_FLAGS);
745
746 return (KERN_SUCCESS);
747 }
748
749 /*
750 * task_hold_locked:
751 *
752 * Suspend execution of the specified task.
753 * This is a recursive-style suspension of the task, a count of
754 * suspends is maintained.
755 *
756 * CONDITIONS: the task is locked and active.
757 */
758 void
759 task_hold_locked(
760 register task_t task)
761 {
762 register thread_t thread;
763
764 assert(task->active);
765
766 if (task->suspend_count++ > 0)
767 return;
768
769 /*
770 * Iterate through all the threads and hold them.
771 */
772 queue_iterate(&task->threads, thread, thread_t, task_threads) {
773 thread_mtx_lock(thread);
774 thread_hold(thread);
775 thread_mtx_unlock(thread);
776 }
777 }
778
779 /*
780 * task_hold:
781 *
782 * Same as the internal routine above, except that is must lock
783 * and verify that the task is active. This differs from task_suspend
784 * in that it places a kernel hold on the task rather than just a
785 * user-level hold. This keeps users from over resuming and setting
786 * it running out from under the kernel.
787 *
788 * CONDITIONS: the caller holds a reference on the task
789 */
790 kern_return_t
791 task_hold(
792 register task_t task)
793 {
794 if (task == TASK_NULL)
795 return (KERN_INVALID_ARGUMENT);
796
797 task_lock(task);
798
799 if (!task->active) {
800 task_unlock(task);
801
802 return (KERN_FAILURE);
803 }
804
805 task_hold_locked(task);
806 task_unlock(task);
807
808 return (KERN_SUCCESS);
809 }
810
811 /*
812 * task_wait_locked:
813 *
814 * Wait for all threads in task to stop.
815 *
816 * Conditions:
817 * Called with task locked, active, and held.
818 */
819 void
820 task_wait_locked(
821 register task_t task)
822 {
823 register thread_t thread, self;
824
825 assert(task->active);
826 assert(task->suspend_count > 0);
827
828 self = current_thread();
829
830 /*
831 * Iterate through all the threads and wait for them to
832 * stop. Do not wait for the current thread if it is within
833 * the task.
834 */
835 queue_iterate(&task->threads, thread, thread_t, task_threads) {
836 if (thread != self)
837 thread_wait(thread);
838 }
839 }
840
841 /*
842 * task_release_locked:
843 *
844 * Release a kernel hold on a task.
845 *
846 * CONDITIONS: the task is locked and active
847 */
848 void
849 task_release_locked(
850 register task_t task)
851 {
852 register thread_t thread;
853
854 assert(task->active);
855 assert(task->suspend_count > 0);
856
857 if (--task->suspend_count > 0)
858 return;
859
860 queue_iterate(&task->threads, thread, thread_t, task_threads) {
861 thread_mtx_lock(thread);
862 thread_release(thread);
863 thread_mtx_unlock(thread);
864 }
865 }
866
867 /*
868 * task_release:
869 *
870 * Same as the internal routine above, except that it must lock
871 * and verify that the task is active.
872 *
873 * CONDITIONS: The caller holds a reference to the task
874 */
875 kern_return_t
876 task_release(
877 task_t task)
878 {
879 if (task == TASK_NULL)
880 return (KERN_INVALID_ARGUMENT);
881
882 task_lock(task);
883
884 if (!task->active) {
885 task_unlock(task);
886
887 return (KERN_FAILURE);
888 }
889
890 task_release_locked(task);
891 task_unlock(task);
892
893 return (KERN_SUCCESS);
894 }
895
896 kern_return_t
897 task_threads(
898 task_t task,
899 thread_act_array_t *threads_out,
900 mach_msg_type_number_t *count)
901 {
902 mach_msg_type_number_t actual;
903 thread_t *thread_list;
904 thread_t thread;
905 vm_size_t size, size_needed;
906 void *addr;
907 unsigned int i, j;
908
909 if (task == TASK_NULL)
910 return (KERN_INVALID_ARGUMENT);
911
912 size = 0; addr = NULL;
913
914 for (;;) {
915 task_lock(task);
916 if (!task->active) {
917 task_unlock(task);
918
919 if (size != 0)
920 kfree(addr, size);
921
922 return (KERN_FAILURE);
923 }
924
925 actual = task->thread_count;
926
927 /* do we have the memory we need? */
928 size_needed = actual * sizeof (mach_port_t);
929 if (size_needed <= size)
930 break;
931
932 /* unlock the task and allocate more memory */
933 task_unlock(task);
934
935 if (size != 0)
936 kfree(addr, size);
937
938 assert(size_needed > 0);
939 size = size_needed;
940
941 addr = kalloc(size);
942 if (addr == 0)
943 return (KERN_RESOURCE_SHORTAGE);
944 }
945
946 /* OK, have memory and the task is locked & active */
947 thread_list = (thread_t *)addr;
948
949 i = j = 0;
950
951 for (thread = (thread_t)queue_first(&task->threads); i < actual;
952 ++i, thread = (thread_t)queue_next(&thread->task_threads)) {
953 thread_reference_internal(thread);
954 thread_list[j++] = thread;
955 }
956
957 assert(queue_end(&task->threads, (queue_entry_t)thread));
958
959 actual = j;
960 size_needed = actual * sizeof (mach_port_t);
961
962 /* can unlock task now that we've got the thread refs */
963 task_unlock(task);
964
965 if (actual == 0) {
966 /* no threads, so return null pointer and deallocate memory */
967
968 *threads_out = NULL;
969 *count = 0;
970
971 if (size != 0)
972 kfree(addr, size);
973 }
974 else {
975 /* if we allocated too much, must copy */
976
977 if (size_needed < size) {
978 void *newaddr;
979
980 newaddr = kalloc(size_needed);
981 if (newaddr == 0) {
982 for (i = 0; i < actual; ++i)
983 thread_deallocate(thread_list[i]);
984 kfree(addr, size);
985 return (KERN_RESOURCE_SHORTAGE);
986 }
987
988 bcopy(addr, newaddr, size_needed);
989 kfree(addr, size);
990 thread_list = (thread_t *)newaddr;
991 }
992
993 *threads_out = thread_list;
994 *count = actual;
995
996 /* do the conversion that Mig should handle */
997
998 for (i = 0; i < actual; ++i)
999 ((ipc_port_t *) thread_list)[i] = convert_thread_to_port(thread_list[i]);
1000 }
1001
1002 return (KERN_SUCCESS);
1003 }
1004
1005 /*
1006 * task_suspend:
1007 *
1008 * Implement a user-level suspension on a task.
1009 *
1010 * Conditions:
1011 * The caller holds a reference to the task
1012 */
1013 kern_return_t
1014 task_suspend(
1015 register task_t task)
1016 {
1017 if (task == TASK_NULL || task == kernel_task)
1018 return (KERN_INVALID_ARGUMENT);
1019
1020 task_lock(task);
1021
1022 if (!task->active) {
1023 task_unlock(task);
1024
1025 return (KERN_FAILURE);
1026 }
1027
1028 if (task->user_stop_count++ > 0) {
1029 /*
1030 * If the stop count was positive, the task is
1031 * already stopped and we can exit.
1032 */
1033 task_unlock(task);
1034
1035 return (KERN_SUCCESS);
1036 }
1037
1038 /*
1039 * Put a kernel-level hold on the threads in the task (all
1040 * user-level task suspensions added together represent a
1041 * single kernel-level hold). We then wait for the threads
1042 * to stop executing user code.
1043 */
1044 task_hold_locked(task);
1045 task_wait_locked(task);
1046
1047 task_unlock(task);
1048
1049 return (KERN_SUCCESS);
1050 }
1051
1052 /*
1053 * task_resume:
1054 * Release a kernel hold on a task.
1055 *
1056 * Conditions:
1057 * The caller holds a reference to the task
1058 */
1059 kern_return_t
1060 task_resume(
1061 register task_t task)
1062 {
1063 register boolean_t release = FALSE;
1064
1065 if (task == TASK_NULL || task == kernel_task)
1066 return (KERN_INVALID_ARGUMENT);
1067
1068 task_lock(task);
1069
1070 if (!task->active) {
1071 task_unlock(task);
1072
1073 return (KERN_FAILURE);
1074 }
1075
1076 if (task->user_stop_count > 0) {
1077 if (--task->user_stop_count == 0)
1078 release = TRUE;
1079 }
1080 else {
1081 task_unlock(task);
1082
1083 return (KERN_FAILURE);
1084 }
1085
1086 /*
1087 * Release the task if necessary.
1088 */
1089 if (release)
1090 task_release_locked(task);
1091
1092 task_unlock(task);
1093
1094 return (KERN_SUCCESS);
1095 }
1096
1097 kern_return_t
1098 host_security_set_task_token(
1099 host_security_t host_security,
1100 task_t task,
1101 security_token_t sec_token,
1102 audit_token_t audit_token,
1103 host_priv_t host_priv)
1104 {
1105 ipc_port_t host_port;
1106 kern_return_t kr;
1107
1108 if (task == TASK_NULL)
1109 return(KERN_INVALID_ARGUMENT);
1110
1111 if (host_security == HOST_NULL)
1112 return(KERN_INVALID_SECURITY);
1113
1114 task_lock(task);
1115 task->sec_token = sec_token;
1116 task->audit_token = audit_token;
1117 task_unlock(task);
1118
1119 if (host_priv != HOST_PRIV_NULL) {
1120 kr = host_get_host_priv_port(host_priv, &host_port);
1121 } else {
1122 kr = host_get_host_port(host_priv_self(), &host_port);
1123 }
1124 assert(kr == KERN_SUCCESS);
1125 kr = task_set_special_port(task, TASK_HOST_PORT, host_port);
1126 return(kr);
1127 }
1128
1129 /*
1130 * Utility routine to set a ledger
1131 */
1132 kern_return_t
1133 task_set_ledger(
1134 task_t task,
1135 ledger_t wired,
1136 ledger_t paged)
1137 {
1138 if (task == TASK_NULL)
1139 return(KERN_INVALID_ARGUMENT);
1140
1141 task_lock(task);
1142 if (wired) {
1143 ipc_port_release_send(task->wired_ledger_port);
1144 task->wired_ledger_port = ledger_copy(wired);
1145 }
1146 if (paged) {
1147 ipc_port_release_send(task->paged_ledger_port);
1148 task->paged_ledger_port = ledger_copy(paged);
1149 }
1150 task_unlock(task);
1151
1152 return(KERN_SUCCESS);
1153 }
1154
1155 /*
1156 * This routine was added, pretty much exclusively, for registering the
1157 * RPC glue vector for in-kernel short circuited tasks. Rather than
1158 * removing it completely, I have only disabled that feature (which was
1159 * the only feature at the time). It just appears that we are going to
1160 * want to add some user data to tasks in the future (i.e. bsd info,
1161 * task names, etc...), so I left it in the formal task interface.
1162 */
1163 kern_return_t
1164 task_set_info(
1165 task_t task,
1166 task_flavor_t flavor,
1167 __unused task_info_t task_info_in, /* pointer to IN array */
1168 __unused mach_msg_type_number_t task_info_count)
1169 {
1170 if (task == TASK_NULL)
1171 return(KERN_INVALID_ARGUMENT);
1172
1173 switch (flavor) {
1174 default:
1175 return (KERN_INVALID_ARGUMENT);
1176 }
1177 return (KERN_SUCCESS);
1178 }
1179
1180 kern_return_t
1181 task_info(
1182 task_t task,
1183 task_flavor_t flavor,
1184 task_info_t task_info_out,
1185 mach_msg_type_number_t *task_info_count)
1186 {
1187 if (task == TASK_NULL)
1188 return (KERN_INVALID_ARGUMENT);
1189
1190 switch (flavor) {
1191
1192 case TASK_BASIC_INFO_32:
1193 case TASK_BASIC2_INFO_32:
1194 {
1195 task_basic_info_32_t basic_info;
1196 vm_map_t map;
1197
1198 if (*task_info_count < TASK_BASIC_INFO_32_COUNT)
1199 return (KERN_INVALID_ARGUMENT);
1200
1201 basic_info = (task_basic_info_32_t)task_info_out;
1202
1203 map = (task == kernel_task)? kernel_map: task->map;
1204 basic_info->virtual_size = CAST_DOWN(vm_offset_t,map->size);
1205 if (flavor == TASK_BASIC2_INFO_32) {
1206 /*
1207 * The "BASIC2" flavor gets the maximum resident
1208 * size instead of the current resident size...
1209 */
1210 basic_info->resident_size = pmap_resident_max(map->pmap);
1211 } else {
1212 basic_info->resident_size = pmap_resident_count(map->pmap);
1213 }
1214 basic_info->resident_size *= PAGE_SIZE;
1215
1216 task_lock(task);
1217 basic_info->policy = ((task != kernel_task)?
1218 POLICY_TIMESHARE: POLICY_RR);
1219 basic_info->suspend_count = task->user_stop_count;
1220
1221 absolutetime_to_microtime(task->total_user_time,
1222 (unsigned *)&basic_info->user_time.seconds,
1223 (unsigned *)&basic_info->user_time.microseconds);
1224 absolutetime_to_microtime(task->total_system_time,
1225 (unsigned *)&basic_info->system_time.seconds,
1226 (unsigned *)&basic_info->system_time.microseconds);
1227 task_unlock(task);
1228
1229 *task_info_count = TASK_BASIC_INFO_32_COUNT;
1230 break;
1231 }
1232
1233 case TASK_BASIC_INFO_64:
1234 {
1235 task_basic_info_64_t basic_info;
1236 vm_map_t map;
1237
1238 if (*task_info_count < TASK_BASIC_INFO_64_COUNT)
1239 return (KERN_INVALID_ARGUMENT);
1240
1241 basic_info = (task_basic_info_64_t)task_info_out;
1242
1243 map = (task == kernel_task)? kernel_map: task->map;
1244 basic_info->virtual_size = map->size;
1245 basic_info->resident_size =
1246 (mach_vm_size_t)(pmap_resident_count(map->pmap))
1247 * PAGE_SIZE_64;
1248
1249 task_lock(task);
1250 basic_info->policy = ((task != kernel_task)?
1251 POLICY_TIMESHARE: POLICY_RR);
1252 basic_info->suspend_count = task->user_stop_count;
1253
1254 absolutetime_to_microtime(task->total_user_time,
1255 (unsigned *)&basic_info->user_time.seconds,
1256 (unsigned *)&basic_info->user_time.microseconds);
1257 absolutetime_to_microtime(task->total_system_time,
1258 (unsigned *)&basic_info->system_time.seconds,
1259 (unsigned *)&basic_info->system_time.microseconds);
1260 task_unlock(task);
1261
1262 *task_info_count = TASK_BASIC_INFO_64_COUNT;
1263 break;
1264 }
1265
1266 case TASK_THREAD_TIMES_INFO:
1267 {
1268 register task_thread_times_info_t times_info;
1269 register thread_t thread;
1270
1271 if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT)
1272 return (KERN_INVALID_ARGUMENT);
1273
1274 times_info = (task_thread_times_info_t) task_info_out;
1275 times_info->user_time.seconds = 0;
1276 times_info->user_time.microseconds = 0;
1277 times_info->system_time.seconds = 0;
1278 times_info->system_time.microseconds = 0;
1279
1280 task_lock(task);
1281
1282 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1283 time_value_t user_time, system_time;
1284
1285 thread_read_times(thread, &user_time, &system_time);
1286
1287 time_value_add(&times_info->user_time, &user_time);
1288 time_value_add(&times_info->system_time, &system_time);
1289 }
1290
1291 task_unlock(task);
1292
1293 *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
1294 break;
1295 }
1296
1297 case TASK_ABSOLUTETIME_INFO:
1298 {
1299 task_absolutetime_info_t info;
1300 register thread_t thread;
1301
1302 if (*task_info_count < TASK_ABSOLUTETIME_INFO_COUNT)
1303 return (KERN_INVALID_ARGUMENT);
1304
1305 info = (task_absolutetime_info_t)task_info_out;
1306 info->threads_user = info->threads_system = 0;
1307
1308 task_lock(task);
1309
1310 info->total_user = task->total_user_time;
1311 info->total_system = task->total_system_time;
1312
1313 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1314 uint64_t tval;
1315
1316 tval = timer_grab(&thread->user_timer);
1317 info->threads_user += tval;
1318 info->total_user += tval;
1319
1320 tval = timer_grab(&thread->system_timer);
1321 info->threads_system += tval;
1322 info->total_system += tval;
1323 }
1324
1325 task_unlock(task);
1326
1327 *task_info_count = TASK_ABSOLUTETIME_INFO_COUNT;
1328 break;
1329 }
1330
1331 /* OBSOLETE */
1332 case TASK_SCHED_FIFO_INFO:
1333 {
1334
1335 if (*task_info_count < POLICY_FIFO_BASE_COUNT)
1336 return (KERN_INVALID_ARGUMENT);
1337
1338 return (KERN_INVALID_POLICY);
1339 }
1340
1341 /* OBSOLETE */
1342 case TASK_SCHED_RR_INFO:
1343 {
1344 register policy_rr_base_t rr_base;
1345
1346 if (*task_info_count < POLICY_RR_BASE_COUNT)
1347 return (KERN_INVALID_ARGUMENT);
1348
1349 rr_base = (policy_rr_base_t) task_info_out;
1350
1351 task_lock(task);
1352 if (task != kernel_task) {
1353 task_unlock(task);
1354 return (KERN_INVALID_POLICY);
1355 }
1356
1357 rr_base->base_priority = task->priority;
1358 task_unlock(task);
1359
1360 rr_base->quantum = std_quantum_us / 1000;
1361
1362 *task_info_count = POLICY_RR_BASE_COUNT;
1363 break;
1364 }
1365
1366 /* OBSOLETE */
1367 case TASK_SCHED_TIMESHARE_INFO:
1368 {
1369 register policy_timeshare_base_t ts_base;
1370
1371 if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT)
1372 return (KERN_INVALID_ARGUMENT);
1373
1374 ts_base = (policy_timeshare_base_t) task_info_out;
1375
1376 task_lock(task);
1377 if (task == kernel_task) {
1378 task_unlock(task);
1379 return (KERN_INVALID_POLICY);
1380 }
1381
1382 ts_base->base_priority = task->priority;
1383 task_unlock(task);
1384
1385 *task_info_count = POLICY_TIMESHARE_BASE_COUNT;
1386 break;
1387 }
1388
1389 case TASK_SECURITY_TOKEN:
1390 {
1391 register security_token_t *sec_token_p;
1392
1393 if (*task_info_count < TASK_SECURITY_TOKEN_COUNT)
1394 return (KERN_INVALID_ARGUMENT);
1395
1396 sec_token_p = (security_token_t *) task_info_out;
1397
1398 task_lock(task);
1399 *sec_token_p = task->sec_token;
1400 task_unlock(task);
1401
1402 *task_info_count = TASK_SECURITY_TOKEN_COUNT;
1403 break;
1404 }
1405
1406 case TASK_AUDIT_TOKEN:
1407 {
1408 register audit_token_t *audit_token_p;
1409
1410 if (*task_info_count < TASK_AUDIT_TOKEN_COUNT)
1411 return (KERN_INVALID_ARGUMENT);
1412
1413 audit_token_p = (audit_token_t *) task_info_out;
1414
1415 task_lock(task);
1416 *audit_token_p = task->audit_token;
1417 task_unlock(task);
1418
1419 *task_info_count = TASK_AUDIT_TOKEN_COUNT;
1420 break;
1421 }
1422
1423 case TASK_SCHED_INFO:
1424 return (KERN_INVALID_ARGUMENT);
1425
1426 case TASK_EVENTS_INFO:
1427 {
1428 register task_events_info_t events_info;
1429 register thread_t thread;
1430
1431 if (*task_info_count < TASK_EVENTS_INFO_COUNT)
1432 return (KERN_INVALID_ARGUMENT);
1433
1434 events_info = (task_events_info_t) task_info_out;
1435
1436 task_lock(task);
1437
1438 events_info->faults = task->faults;
1439 events_info->pageins = task->pageins;
1440 events_info->cow_faults = task->cow_faults;
1441 events_info->messages_sent = task->messages_sent;
1442 events_info->messages_received = task->messages_received;
1443 events_info->syscalls_mach = task->syscalls_mach;
1444 events_info->syscalls_unix = task->syscalls_unix;
1445
1446 events_info->csw = task->c_switch;
1447
1448 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1449 events_info->csw += thread->c_switch;
1450 }
1451
1452 task_unlock(task);
1453
1454 *task_info_count = TASK_EVENTS_INFO_COUNT;
1455 break;
1456 }
1457 case TASK_AFFINITY_TAG_INFO:
1458 {
1459 if (*task_info_count < TASK_AFFINITY_TAG_INFO_COUNT)
1460 return (KERN_INVALID_ARGUMENT);
1461
1462 return task_affinity_info(task, task_info_out, task_info_count);
1463 }
1464
1465 default:
1466 return (KERN_INVALID_ARGUMENT);
1467 }
1468
1469 return (KERN_SUCCESS);
1470 }
1471
1472 void
1473 task_vtimer_set(
1474 task_t task,
1475 integer_t which)
1476 {
1477 thread_t thread;
1478
1479 /* assert(task == current_task()); */ /* bogus assert 4803227 4807483 */
1480
1481 task_lock(task);
1482
1483 task->vtimers |= which;
1484
1485 switch (which) {
1486
1487 case TASK_VTIMER_USER:
1488 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1489 thread->vtimer_user_save = timer_grab(&thread->user_timer);
1490 }
1491 break;
1492
1493 case TASK_VTIMER_PROF:
1494 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1495 thread->vtimer_prof_save = timer_grab(&thread->user_timer);
1496 thread->vtimer_prof_save += timer_grab(&thread->system_timer);
1497 }
1498 break;
1499
1500 case TASK_VTIMER_RLIM:
1501 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1502 thread->vtimer_rlim_save = timer_grab(&thread->user_timer);
1503 thread->vtimer_rlim_save += timer_grab(&thread->system_timer);
1504 }
1505 break;
1506 }
1507
1508 task_unlock(task);
1509 }
1510
1511 void
1512 task_vtimer_clear(
1513 task_t task,
1514 integer_t which)
1515 {
1516 assert(task == current_task());
1517
1518 task_lock(task);
1519
1520 task->vtimers &= ~which;
1521
1522 task_unlock(task);
1523 }
1524
1525 void
1526 task_vtimer_update(
1527 __unused
1528 task_t task,
1529 integer_t which,
1530 uint32_t *microsecs)
1531 {
1532 thread_t thread = current_thread();
1533 uint32_t tdelt, secs;
1534 uint64_t tsum;
1535
1536 assert(task == current_task());
1537
1538 assert(task->vtimers & which);
1539
1540 tdelt = secs = 0;
1541
1542 switch (which) {
1543
1544 case TASK_VTIMER_USER:
1545 tdelt = timer_delta(&thread->user_timer,
1546 &thread->vtimer_user_save);
1547 break;
1548
1549 case TASK_VTIMER_PROF:
1550 tsum = timer_grab(&thread->user_timer);
1551 tsum += timer_grab(&thread->system_timer);
1552 tdelt = tsum - thread->vtimer_prof_save;
1553 thread->vtimer_prof_save = tsum;
1554 break;
1555
1556 case TASK_VTIMER_RLIM:
1557 tsum = timer_grab(&thread->user_timer);
1558 tsum += timer_grab(&thread->system_timer);
1559 tdelt = tsum - thread->vtimer_rlim_save;
1560 thread->vtimer_rlim_save = tsum;
1561 break;
1562 }
1563
1564 absolutetime_to_microtime(tdelt, &secs, microsecs);
1565 }
1566
1567 /*
1568 * task_assign:
1569 *
1570 * Change the assigned processor set for the task
1571 */
1572 kern_return_t
1573 task_assign(
1574 __unused task_t task,
1575 __unused processor_set_t new_pset,
1576 __unused boolean_t assign_threads)
1577 {
1578 return(KERN_FAILURE);
1579 }
1580
1581 /*
1582 * task_assign_default:
1583 *
1584 * Version of task_assign to assign to default processor set.
1585 */
1586 kern_return_t
1587 task_assign_default(
1588 task_t task,
1589 boolean_t assign_threads)
1590 {
1591 return (task_assign(task, &pset0, assign_threads));
1592 }
1593
1594 /*
1595 * task_get_assignment
1596 *
1597 * Return name of processor set that task is assigned to.
1598 */
1599 kern_return_t
1600 task_get_assignment(
1601 task_t task,
1602 processor_set_t *pset)
1603 {
1604 if (!task->active)
1605 return(KERN_FAILURE);
1606
1607 *pset = &pset0;
1608
1609 return (KERN_SUCCESS);
1610 }
1611
1612
1613 /*
1614 * task_policy
1615 *
1616 * Set scheduling policy and parameters, both base and limit, for
1617 * the given task. Policy must be a policy which is enabled for the
1618 * processor set. Change contained threads if requested.
1619 */
1620 kern_return_t
1621 task_policy(
1622 __unused task_t task,
1623 __unused policy_t policy_id,
1624 __unused policy_base_t base,
1625 __unused mach_msg_type_number_t count,
1626 __unused boolean_t set_limit,
1627 __unused boolean_t change)
1628 {
1629 return(KERN_FAILURE);
1630 }
1631
1632 /*
1633 * task_set_policy
1634 *
1635 * Set scheduling policy and parameters, both base and limit, for
1636 * the given task. Policy can be any policy implemented by the
1637 * processor set, whether enabled or not. Change contained threads
1638 * if requested.
1639 */
1640 kern_return_t
1641 task_set_policy(
1642 __unused task_t task,
1643 __unused processor_set_t pset,
1644 __unused policy_t policy_id,
1645 __unused policy_base_t base,
1646 __unused mach_msg_type_number_t base_count,
1647 __unused policy_limit_t limit,
1648 __unused mach_msg_type_number_t limit_count,
1649 __unused boolean_t change)
1650 {
1651 return(KERN_FAILURE);
1652 }
1653
1654 #if FAST_TAS
1655 kern_return_t
1656 task_set_ras_pc(
1657 task_t task,
1658 vm_offset_t pc,
1659 vm_offset_t endpc)
1660 {
1661 extern int fast_tas_debug;
1662
1663 if (fast_tas_debug) {
1664 printf("task 0x%x: setting fast_tas to [0x%x, 0x%x]\n",
1665 task, pc, endpc);
1666 }
1667 task_lock(task);
1668 task->fast_tas_base = pc;
1669 task->fast_tas_end = endpc;
1670 task_unlock(task);
1671 return KERN_SUCCESS;
1672 }
1673 #else /* FAST_TAS */
1674 kern_return_t
1675 task_set_ras_pc(
1676 __unused task_t task,
1677 __unused vm_offset_t pc,
1678 __unused vm_offset_t endpc)
1679 {
1680 return KERN_FAILURE;
1681 }
1682 #endif /* FAST_TAS */
1683
1684 void
1685 task_synchronizer_destroy_all(task_t task)
1686 {
1687 semaphore_t semaphore;
1688 lock_set_t lock_set;
1689
1690 /*
1691 * Destroy owned semaphores
1692 */
1693
1694 while (!queue_empty(&task->semaphore_list)) {
1695 semaphore = (semaphore_t) queue_first(&task->semaphore_list);
1696 (void) semaphore_destroy(task, semaphore);
1697 }
1698
1699 /*
1700 * Destroy owned lock sets
1701 */
1702
1703 while (!queue_empty(&task->lock_set_list)) {
1704 lock_set = (lock_set_t) queue_first(&task->lock_set_list);
1705 (void) lock_set_destroy(task, lock_set);
1706 }
1707 }
1708
1709 /*
1710 * We need to export some functions to other components that
1711 * are currently implemented in macros within the osfmk
1712 * component. Just export them as functions of the same name.
1713 */
1714 boolean_t is_kerneltask(task_t t)
1715 {
1716 if (t == kernel_task)
1717 return (TRUE);
1718
1719 return (FALSE);
1720 }
1721
1722 #undef current_task
1723 task_t current_task(void);
1724 task_t current_task(void)
1725 {
1726 return (current_task_fast());
1727 }
1728
1729 #undef task_reference
1730 void task_reference(task_t task);
1731 void
1732 task_reference(
1733 task_t task)
1734 {
1735 if (task != TASK_NULL)
1736 task_reference_internal(task);
1737 }
1738
1739 #if CONFIG_MACF_MACH
1740 /*
1741 * Protect 2 task labels against modification by adding a reference on
1742 * both label handles. The locks do not actually have to be held while
1743 * using the labels as only labels with one reference can be modified
1744 * in place.
1745 */
1746
1747 void
1748 tasklabel_lock2(
1749 task_t a,
1750 task_t b)
1751 {
1752 labelh_reference(a->label);
1753 labelh_reference(b->label);
1754 }
1755
1756 void
1757 tasklabel_unlock2(
1758 task_t a,
1759 task_t b)
1760 {
1761 labelh_release(a->label);
1762 labelh_release(b->label);
1763 }
1764
1765 void
1766 mac_task_label_update_internal(
1767 struct label *pl,
1768 struct task *task)
1769 {
1770
1771 tasklabel_lock(task);
1772 task->label = labelh_modify(task->label);
1773 mac_task_label_update(pl, &task->maclabel);
1774 tasklabel_unlock(task);
1775 ip_lock(task->itk_self);
1776 mac_port_label_update_cred(pl, &task->itk_self->ip_label);
1777 ip_unlock(task->itk_self);
1778 }
1779
1780 void
1781 mac_task_label_modify(
1782 struct task *task,
1783 void *arg,
1784 void (*f) (struct label *l, void *arg))
1785 {
1786
1787 tasklabel_lock(task);
1788 task->label = labelh_modify(task->label);
1789 (*f)(&task->maclabel, arg);
1790 tasklabel_unlock(task);
1791 }
1792
1793 struct label *
1794 mac_task_get_label(struct task *task)
1795 {
1796 return (&task->maclabel);
1797 }
1798 #endif