]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/task.c
6911821503806905d95c37b99610733c6ee761e5
[apple/xnu.git] / osfmk / kern / task.c
1 /*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * @OSF_FREE_COPYRIGHT@
32 */
33 /*
34 * Mach Operating System
35 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
36 * All Rights Reserved.
37 *
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
43 *
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
47 *
48 * Carnegie Mellon requests users of this software to return to
49 *
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
54 *
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
57 */
58 /*
59 * File: kern/task.c
60 * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub,
61 * David Black
62 *
63 * Task management primitives implementation.
64 */
65 /*
66 * Copyright (c) 1993 The University of Utah and
67 * the Computer Systems Laboratory (CSL). All rights reserved.
68 *
69 * Permission to use, copy, modify and distribute this software and its
70 * documentation is hereby granted, provided that both the copyright
71 * notice and this permission notice appear in all copies of the
72 * software, derivative works or modified versions, and any portions
73 * thereof, and that both notices appear in supporting documentation.
74 *
75 * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
76 * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
77 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
78 *
79 * CSL requests users of this software to return to csl-dist@cs.utah.edu any
80 * improvements that they make and grant CSL redistribution rights.
81 *
82 */
83
84 #include <mach_kdb.h>
85 #include <mach_host.h>
86 #include <mach_prof.h>
87 #include <fast_tas.h>
88 #include <platforms.h>
89
90 #include <mach/mach_types.h>
91 #include <mach/boolean.h>
92 #include <mach/host_priv.h>
93 #include <mach/machine/vm_types.h>
94 #include <mach/vm_param.h>
95 #include <mach/semaphore.h>
96 #include <mach/task_info.h>
97 #include <mach/task_special_ports.h>
98
99 #include <ipc/ipc_types.h>
100 #include <ipc/ipc_space.h>
101 #include <ipc/ipc_entry.h>
102
103 #include <kern/kern_types.h>
104 #include <kern/mach_param.h>
105 #include <kern/misc_protos.h>
106 #include <kern/task.h>
107 #include <kern/thread.h>
108 #include <kern/zalloc.h>
109 #include <kern/kalloc.h>
110 #include <kern/processor.h>
111 #include <kern/sched_prim.h> /* for thread_wakeup */
112 #include <kern/ipc_tt.h>
113 #include <kern/ledger.h>
114 #include <kern/host.h>
115 #include <kern/clock.h>
116 #include <kern/timer.h>
117 #include <kern/profile.h>
118 #include <kern/assert.h>
119 #include <kern/sync_lock.h>
120
121 #include <vm/pmap.h>
122 #include <vm/vm_map.h>
123 #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */
124 #include <vm/vm_pageout.h>
125 #include <vm/vm_protos.h> /* for vm_map_remove_commpage64 */
126
127 #if MACH_KDB
128 #include <ddb/db_sym.h>
129 #endif /* MACH_KDB */
130
131 #ifdef __ppc__
132 #include <ppc/exception.h>
133 #include <ppc/hw_perfmon.h>
134 #endif
135
136 /*
137 * Exported interfaces
138 */
139
140 #include <mach/task_server.h>
141 #include <mach/mach_host_server.h>
142 #include <mach/host_security_server.h>
143 #include <mach/mach_port_server.h>
144
145 #include <vm/task_working_set.h>
146 #include <vm/vm_shared_memory_server.h>
147
148 task_t kernel_task;
149 zone_t task_zone;
150
151 /* Forwards */
152
153 void task_hold_locked(
154 task_t task);
155 void task_wait_locked(
156 task_t task);
157 void task_release_locked(
158 task_t task);
159 void task_free(
160 task_t task );
161 void task_synchronizer_destroy_all(
162 task_t task);
163
164 kern_return_t task_set_ledger(
165 task_t task,
166 ledger_t wired,
167 ledger_t paged);
168
169 void
170 task_backing_store_privileged(
171 task_t task)
172 {
173 task_lock(task);
174 task->priv_flags |= VM_BACKING_STORE_PRIV;
175 task_unlock(task);
176 return;
177 }
178
179 void
180 task_working_set_disable(task_t task)
181 {
182 struct tws_hash *ws;
183
184 task_lock(task);
185 ws = task->dynamic_working_set;
186 task->dynamic_working_set = NULL;
187 task_unlock(task);
188 if (ws) {
189 tws_hash_ws_flush(ws);
190 tws_hash_destroy(ws);
191 }
192 }
193
194 void
195 task_set_64bit(
196 task_t task,
197 boolean_t is64bit)
198 {
199 if(is64bit) {
200 /* LP64todo - no task working set for 64-bit */
201 task_set_64BitAddr(task);
202 task_working_set_disable(task);
203 task->map->max_offset = MACH_VM_MAX_ADDRESS;
204 } else {
205 /*
206 * Deallocate all memory previously allocated
207 * above the 32-bit address space, since it won't
208 * be accessible anymore.
209 */
210 /* LP64todo - make this clean */
211 #ifdef __ppc__
212 vm_map_remove_commpage64(task->map);
213 pmap_unmap_sharedpage(task->map->pmap); /* Unmap commpage */
214 #endif
215 (void) vm_map_remove(task->map,
216 (vm_map_offset_t) VM_MAX_ADDRESS,
217 MACH_VM_MAX_ADDRESS,
218 VM_MAP_NO_FLAGS);
219 task_clear_64BitAddr(task);
220 task->map->max_offset = (vm_map_offset_t)VM_MAX_ADDRESS;
221 }
222 }
223
224 void
225 task_init(void)
226 {
227 task_zone = zinit(
228 sizeof(struct task),
229 TASK_MAX * sizeof(struct task),
230 TASK_CHUNK * sizeof(struct task),
231 "tasks");
232
233 /*
234 * Create the kernel task as the first task.
235 */
236 if (task_create_internal(TASK_NULL, FALSE, &kernel_task) != KERN_SUCCESS)
237 panic("task_init\n");
238
239 vm_map_deallocate(kernel_task->map);
240 kernel_task->map = kernel_map;
241 }
242
243 #if MACH_HOST
244
245 #if 0
246 static void
247 task_freeze(
248 task_t task)
249 {
250 task_lock(task);
251 /*
252 * If may_assign is false, task is already being assigned,
253 * wait for that to finish.
254 */
255 while (task->may_assign == FALSE) {
256 wait_result_t res;
257
258 task->assign_active = TRUE;
259 res = thread_sleep_mutex((event_t) &task->assign_active,
260 &task->lock, THREAD_UNINT);
261 assert(res == THREAD_AWAKENED);
262 }
263 task->may_assign = FALSE;
264 task_unlock(task);
265 return;
266 }
267 #else
268 #define thread_freeze(thread) assert(task->processor_set == &default_pset)
269 #endif
270
271 #if 0
272 static void
273 task_unfreeze(
274 task_t task)
275 {
276 task_lock(task);
277 assert(task->may_assign == FALSE);
278 task->may_assign = TRUE;
279 if (task->assign_active == TRUE) {
280 task->assign_active = FALSE;
281 thread_wakeup((event_t)&task->assign_active);
282 }
283 task_unlock(task);
284 return;
285 }
286 #else
287 #define thread_unfreeze(thread) assert(task->processor_set == &default_pset)
288 #endif
289
290 #endif /* MACH_HOST */
291
292 /*
293 * Create a task running in the kernel address space. It may
294 * have its own map of size mem_size and may have ipc privileges.
295 */
296 kern_return_t
297 kernel_task_create(
298 __unused task_t parent_task,
299 __unused vm_offset_t map_base,
300 __unused vm_size_t map_size,
301 __unused task_t *child_task)
302 {
303 return (KERN_INVALID_ARGUMENT);
304 }
305
306 kern_return_t
307 task_create(
308 task_t parent_task,
309 __unused ledger_port_array_t ledger_ports,
310 __unused mach_msg_type_number_t num_ledger_ports,
311 boolean_t inherit_memory,
312 task_t *child_task) /* OUT */
313 {
314 if (parent_task == TASK_NULL)
315 return(KERN_INVALID_ARGUMENT);
316
317 return task_create_internal(
318 parent_task, inherit_memory, child_task);
319 }
320
321 kern_return_t
322 host_security_create_task_token(
323 host_security_t host_security,
324 task_t parent_task,
325 security_token_t sec_token,
326 audit_token_t audit_token,
327 host_priv_t host_priv,
328 __unused ledger_port_array_t ledger_ports,
329 __unused mach_msg_type_number_t num_ledger_ports,
330 boolean_t inherit_memory,
331 task_t *child_task) /* OUT */
332 {
333 kern_return_t result;
334
335 if (parent_task == TASK_NULL)
336 return(KERN_INVALID_ARGUMENT);
337
338 if (host_security == HOST_NULL)
339 return(KERN_INVALID_SECURITY);
340
341 result = task_create_internal(
342 parent_task, inherit_memory, child_task);
343
344 if (result != KERN_SUCCESS)
345 return(result);
346
347 result = host_security_set_task_token(host_security,
348 *child_task,
349 sec_token,
350 audit_token,
351 host_priv);
352
353 if (result != KERN_SUCCESS)
354 return(result);
355
356 return(result);
357 }
358
359 kern_return_t
360 task_create_internal(
361 task_t parent_task,
362 boolean_t inherit_memory,
363 task_t *child_task) /* OUT */
364 {
365 task_t new_task;
366 processor_set_t pset;
367
368 new_task = (task_t) zalloc(task_zone);
369
370 if (new_task == TASK_NULL)
371 return(KERN_RESOURCE_SHORTAGE);
372
373 /* one ref for just being alive; one for our caller */
374 new_task->ref_count = 2;
375
376 if (inherit_memory)
377 new_task->map = vm_map_fork(parent_task->map);
378 else
379 new_task->map = vm_map_create(pmap_create(0),
380 (vm_map_offset_t)(VM_MIN_ADDRESS),
381 (vm_map_offset_t)(VM_MAX_ADDRESS), TRUE);
382
383 mutex_init(&new_task->lock, 0);
384 queue_init(&new_task->threads);
385 new_task->suspend_count = 0;
386 new_task->thread_count = 0;
387 new_task->active_thread_count = 0;
388 new_task->user_stop_count = 0;
389 new_task->role = TASK_UNSPECIFIED;
390 new_task->active = TRUE;
391 new_task->user_data = 0;
392 new_task->faults = 0;
393 new_task->cow_faults = 0;
394 new_task->pageins = 0;
395 new_task->messages_sent = 0;
396 new_task->messages_received = 0;
397 new_task->syscalls_mach = 0;
398 new_task->priv_flags = 0;
399 new_task->syscalls_unix=0;
400 new_task->csw=0;
401 new_task->taskFeatures[0] = 0; /* Init task features */
402 new_task->taskFeatures[1] = 0; /* Init task features */
403 new_task->dynamic_working_set = 0;
404
405 task_working_set_create(new_task, TWS_SMALL_HASH_LINE_COUNT,
406 0, TWS_HASH_STYLE_DEFAULT);
407
408 #ifdef MACH_BSD
409 new_task->bsd_info = 0;
410 #endif /* MACH_BSD */
411
412 #ifdef __ppc__
413 if(BootProcInfo.pf.Available & pf64Bit) new_task->taskFeatures[0] |= tf64BitData; /* If 64-bit machine, show we have 64-bit registers at least */
414 #endif
415
416 queue_init(&new_task->semaphore_list);
417 queue_init(&new_task->lock_set_list);
418 new_task->semaphores_owned = 0;
419 new_task->lock_sets_owned = 0;
420
421 #if MACH_HOST
422 new_task->may_assign = TRUE;
423 new_task->assign_active = FALSE;
424 #endif /* MACH_HOST */
425
426 ipc_task_init(new_task, parent_task);
427
428 new_task->total_user_time = 0;
429 new_task->total_system_time = 0;
430
431 task_prof_init(new_task);
432
433 if (parent_task != TASK_NULL) {
434 #if MACH_HOST
435 /*
436 * Freeze the parent, so that parent_task->processor_set
437 * cannot change.
438 */
439 task_freeze(parent_task);
440 #endif /* MACH_HOST */
441 pset = parent_task->processor_set;
442 if (!pset->active)
443 pset = &default_pset;
444
445 new_task->sec_token = parent_task->sec_token;
446 new_task->audit_token = parent_task->audit_token;
447
448 shared_region_mapping_ref(parent_task->system_shared_region);
449 new_task->system_shared_region = parent_task->system_shared_region;
450
451 new_task->wired_ledger_port = ledger_copy(
452 convert_port_to_ledger(parent_task->wired_ledger_port));
453 new_task->paged_ledger_port = ledger_copy(
454 convert_port_to_ledger(parent_task->paged_ledger_port));
455 if(task_has_64BitAddr(parent_task))
456 task_set_64BitAddr(new_task);
457 }
458 else {
459 pset = &default_pset;
460
461 new_task->sec_token = KERNEL_SECURITY_TOKEN;
462 new_task->audit_token = KERNEL_AUDIT_TOKEN;
463 new_task->wired_ledger_port = ledger_copy(root_wired_ledger);
464 new_task->paged_ledger_port = ledger_copy(root_paged_ledger);
465 }
466
467 if (kernel_task == TASK_NULL) {
468 new_task->priority = BASEPRI_KERNEL;
469 new_task->max_priority = MAXPRI_KERNEL;
470 }
471 else {
472 new_task->priority = BASEPRI_DEFAULT;
473 new_task->max_priority = MAXPRI_USER;
474 }
475
476 pset_lock(pset);
477 pset_add_task(pset, new_task);
478 pset_unlock(pset);
479 #if MACH_HOST
480 if (parent_task != TASK_NULL)
481 task_unfreeze(parent_task);
482 #endif /* MACH_HOST */
483
484 if (vm_backing_store_low && parent_task != NULL)
485 new_task->priv_flags |= (parent_task->priv_flags&VM_BACKING_STORE_PRIV);
486
487 ipc_task_enable(new_task);
488
489 *child_task = new_task;
490 return(KERN_SUCCESS);
491 }
492
493 /*
494 * task_deallocate:
495 *
496 * Drop a reference on a task.
497 */
498 void
499 task_deallocate(
500 task_t task)
501 {
502 processor_set_t pset;
503
504 if (task == TASK_NULL)
505 return;
506
507 if (task_deallocate_internal(task) > 0)
508 return;
509
510 pset = task->processor_set;
511 pset_deallocate(pset);
512
513 if(task->dynamic_working_set)
514 tws_hash_destroy(task->dynamic_working_set);
515
516 ipc_task_terminate(task);
517
518 vm_map_deallocate(task->map);
519 is_release(task->itk_space);
520
521 task_prof_deallocate(task);
522 zfree(task_zone, task);
523 }
524
525 /*
526 * task_terminate:
527 *
528 * Terminate the specified task. See comments on thread_terminate
529 * (kern/thread.c) about problems with terminating the "current task."
530 */
531
532 kern_return_t
533 task_terminate(
534 task_t task)
535 {
536 if (task == TASK_NULL)
537 return (KERN_INVALID_ARGUMENT);
538
539 if (task->bsd_info)
540 return (KERN_FAILURE);
541
542 return (task_terminate_internal(task));
543 }
544
545 kern_return_t
546 task_terminate_internal(
547 task_t task)
548 {
549 processor_set_t pset;
550 thread_t thread, self;
551 task_t self_task;
552 boolean_t interrupt_save;
553
554 assert(task != kernel_task);
555
556 self = current_thread();
557 self_task = self->task;
558
559 /*
560 * Get the task locked and make sure that we are not racing
561 * with someone else trying to terminate us.
562 */
563 if (task == self_task)
564 task_lock(task);
565 else
566 if (task < self_task) {
567 task_lock(task);
568 task_lock(self_task);
569 }
570 else {
571 task_lock(self_task);
572 task_lock(task);
573 }
574
575 if (!task->active || !self->active) {
576 /*
577 * Task or current act is already being terminated.
578 * Just return an error. If we are dying, this will
579 * just get us to our AST special handler and that
580 * will get us to finalize the termination of ourselves.
581 */
582 task_unlock(task);
583 if (self_task != task)
584 task_unlock(self_task);
585
586 return (KERN_FAILURE);
587 }
588
589 if (self_task != task)
590 task_unlock(self_task);
591
592 /*
593 * Make sure the current thread does not get aborted out of
594 * the waits inside these operations.
595 */
596 interrupt_save = thread_interrupt_level(THREAD_UNINT);
597
598 /*
599 * Indicate that we want all the threads to stop executing
600 * at user space by holding the task (we would have held
601 * each thread independently in thread_terminate_internal -
602 * but this way we may be more likely to already find it
603 * held there). Mark the task inactive, and prevent
604 * further task operations via the task port.
605 */
606 task_hold_locked(task);
607 task->active = FALSE;
608 ipc_task_disable(task);
609
610 /*
611 * Terminate each thread in the task.
612 */
613 queue_iterate(&task->threads, thread, thread_t, task_threads) {
614 thread_terminate_internal(thread);
615 }
616
617 /*
618 * Give the machine dependent code a chance
619 * to perform cleanup before ripping apart
620 * the task.
621 */
622 if (self_task == task)
623 machine_thread_terminate_self();
624
625 task_unlock(task);
626
627 /*
628 * Destroy all synchronizers owned by the task.
629 */
630 task_synchronizer_destroy_all(task);
631
632 /*
633 * Destroy the IPC space, leaving just a reference for it.
634 */
635 ipc_space_destroy(task->itk_space);
636
637 /* LP64todo - make this clean */
638 #ifdef __ppc__
639 vm_map_remove_commpage64(task->map);
640 pmap_unmap_sharedpage(task->map->pmap); /* Unmap commpage */
641 #endif
642
643 /*
644 * If the current thread is a member of the task
645 * being terminated, then the last reference to
646 * the task will not be dropped until the thread
647 * is finally reaped. To avoid incurring the
648 * expense of removing the address space regions
649 * at reap time, we do it explictly here.
650 */
651 vm_map_remove(task->map, task->map->min_offset,
652 task->map->max_offset, VM_MAP_NO_FLAGS);
653
654 shared_region_mapping_dealloc(task->system_shared_region);
655
656 /*
657 * Flush working set here to avoid I/O in reaper thread
658 */
659 if (task->dynamic_working_set)
660 tws_hash_ws_flush(task->dynamic_working_set);
661
662 pset = task->processor_set;
663 pset_lock(pset);
664 pset_remove_task(pset,task);
665 pset_unlock(pset);
666
667 /*
668 * We no longer need to guard against being aborted, so restore
669 * the previous interruptible state.
670 */
671 thread_interrupt_level(interrupt_save);
672
673 #if __ppc__
674 perfmon_release_facility(task); // notify the perfmon facility
675 #endif
676
677 /*
678 * Get rid of the task active reference on itself.
679 */
680 task_deallocate(task);
681
682 return (KERN_SUCCESS);
683 }
684
685 /*
686 * task_halt:
687 *
688 * Shut the current task down (except for the current thread) in
689 * preparation for dramatic changes to the task (probably exec).
690 * We hold the task, terminate all other threads in the task and
691 * wait for them to terminate, clean up the portspace, and when
692 * all done, let the current thread go.
693 */
694 kern_return_t
695 task_halt(
696 task_t task)
697 {
698 thread_t thread, self;
699
700 assert(task != kernel_task);
701
702 self = current_thread();
703
704 if (task != self->task)
705 return (KERN_INVALID_ARGUMENT);
706
707 task_lock(task);
708
709 if (!task->active || !self->active) {
710 /*
711 * Task or current thread is already being terminated.
712 * Hurry up and return out of the current kernel context
713 * so that we run our AST special handler to terminate
714 * ourselves.
715 */
716 task_unlock(task);
717
718 return (KERN_FAILURE);
719 }
720
721 if (task->thread_count > 1) {
722 /*
723 * Mark all the threads to keep them from starting any more
724 * user-level execution. The thread_terminate_internal code
725 * would do this on a thread by thread basis anyway, but this
726 * gives us a better chance of not having to wait there.
727 */
728 task_hold_locked(task);
729
730 /*
731 * Terminate all the other threads in the task.
732 */
733 queue_iterate(&task->threads, thread, thread_t, task_threads) {
734 if (thread != self)
735 thread_terminate_internal(thread);
736 }
737
738 task_release_locked(task);
739 }
740
741 /*
742 * Give the machine dependent code a chance
743 * to perform cleanup before ripping apart
744 * the task.
745 */
746 machine_thread_terminate_self();
747
748 task_unlock(task);
749
750 /*
751 * Destroy all synchronizers owned by the task.
752 */
753 task_synchronizer_destroy_all(task);
754
755 /*
756 * Destroy the contents of the IPC space, leaving just
757 * a reference for it.
758 */
759 ipc_space_clean(task->itk_space);
760
761 /*
762 * Clean out the address space, as we are going to be
763 * getting a new one.
764 */
765 vm_map_remove(task->map, task->map->min_offset,
766 task->map->max_offset, VM_MAP_NO_FLAGS);
767
768 return (KERN_SUCCESS);
769 }
770
771 /*
772 * task_hold_locked:
773 *
774 * Suspend execution of the specified task.
775 * This is a recursive-style suspension of the task, a count of
776 * suspends is maintained.
777 *
778 * CONDITIONS: the task is locked and active.
779 */
780 void
781 task_hold_locked(
782 register task_t task)
783 {
784 register thread_t thread;
785
786 assert(task->active);
787
788 if (task->suspend_count++ > 0)
789 return;
790
791 /*
792 * Iterate through all the threads and hold them.
793 */
794 queue_iterate(&task->threads, thread, thread_t, task_threads) {
795 thread_mtx_lock(thread);
796 thread_hold(thread);
797 thread_mtx_unlock(thread);
798 }
799 }
800
801 /*
802 * task_hold:
803 *
804 * Same as the internal routine above, except that is must lock
805 * and verify that the task is active. This differs from task_suspend
806 * in that it places a kernel hold on the task rather than just a
807 * user-level hold. This keeps users from over resuming and setting
808 * it running out from under the kernel.
809 *
810 * CONDITIONS: the caller holds a reference on the task
811 */
812 kern_return_t
813 task_hold(
814 register task_t task)
815 {
816 if (task == TASK_NULL)
817 return (KERN_INVALID_ARGUMENT);
818
819 task_lock(task);
820
821 if (!task->active) {
822 task_unlock(task);
823
824 return (KERN_FAILURE);
825 }
826
827 task_hold_locked(task);
828 task_unlock(task);
829
830 return (KERN_SUCCESS);
831 }
832
833 /*
834 * task_wait_locked:
835 *
836 * Wait for all threads in task to stop.
837 *
838 * Conditions:
839 * Called with task locked, active, and held.
840 */
841 void
842 task_wait_locked(
843 register task_t task)
844 {
845 register thread_t thread, self;
846
847 assert(task->active);
848 assert(task->suspend_count > 0);
849
850 self = current_thread();
851
852 /*
853 * Iterate through all the threads and wait for them to
854 * stop. Do not wait for the current thread if it is within
855 * the task.
856 */
857 queue_iterate(&task->threads, thread, thread_t, task_threads) {
858 if (thread != self)
859 thread_wait(thread);
860 }
861 }
862
863 /*
864 * task_release_locked:
865 *
866 * Release a kernel hold on a task.
867 *
868 * CONDITIONS: the task is locked and active
869 */
870 void
871 task_release_locked(
872 register task_t task)
873 {
874 register thread_t thread;
875
876 assert(task->active);
877 assert(task->suspend_count > 0);
878
879 if (--task->suspend_count > 0)
880 return;
881
882 queue_iterate(&task->threads, thread, thread_t, task_threads) {
883 thread_mtx_lock(thread);
884 thread_release(thread);
885 thread_mtx_unlock(thread);
886 }
887 }
888
889 /*
890 * task_release:
891 *
892 * Same as the internal routine above, except that it must lock
893 * and verify that the task is active.
894 *
895 * CONDITIONS: The caller holds a reference to the task
896 */
897 kern_return_t
898 task_release(
899 task_t task)
900 {
901 if (task == TASK_NULL)
902 return (KERN_INVALID_ARGUMENT);
903
904 task_lock(task);
905
906 if (!task->active) {
907 task_unlock(task);
908
909 return (KERN_FAILURE);
910 }
911
912 task_release_locked(task);
913 task_unlock(task);
914
915 return (KERN_SUCCESS);
916 }
917
918 kern_return_t
919 task_threads(
920 task_t task,
921 thread_act_array_t *threads_out,
922 mach_msg_type_number_t *count)
923 {
924 mach_msg_type_number_t actual;
925 thread_t *threads;
926 thread_t thread;
927 vm_size_t size, size_needed;
928 void *addr;
929 unsigned int i, j;
930
931 if (task == TASK_NULL)
932 return (KERN_INVALID_ARGUMENT);
933
934 size = 0; addr = 0;
935
936 for (;;) {
937 task_lock(task);
938 if (!task->active) {
939 task_unlock(task);
940
941 if (size != 0)
942 kfree(addr, size);
943
944 return (KERN_FAILURE);
945 }
946
947 actual = task->thread_count;
948
949 /* do we have the memory we need? */
950 size_needed = actual * sizeof (mach_port_t);
951 if (size_needed <= size)
952 break;
953
954 /* unlock the task and allocate more memory */
955 task_unlock(task);
956
957 if (size != 0)
958 kfree(addr, size);
959
960 assert(size_needed > 0);
961 size = size_needed;
962
963 addr = kalloc(size);
964 if (addr == 0)
965 return (KERN_RESOURCE_SHORTAGE);
966 }
967
968 /* OK, have memory and the task is locked & active */
969 threads = (thread_t *)addr;
970
971 i = j = 0;
972
973 for (thread = (thread_t)queue_first(&task->threads); i < actual;
974 ++i, thread = (thread_t)queue_next(&thread->task_threads)) {
975 thread_reference_internal(thread);
976 threads[j++] = thread;
977 }
978
979 assert(queue_end(&task->threads, (queue_entry_t)thread));
980
981 actual = j;
982 size_needed = actual * sizeof (mach_port_t);
983
984 /* can unlock task now that we've got the thread refs */
985 task_unlock(task);
986
987 if (actual == 0) {
988 /* no threads, so return null pointer and deallocate memory */
989
990 *threads_out = 0;
991 *count = 0;
992
993 if (size != 0)
994 kfree(addr, size);
995 }
996 else {
997 /* if we allocated too much, must copy */
998
999 if (size_needed < size) {
1000 void *newaddr;
1001
1002 newaddr = kalloc(size_needed);
1003 if (newaddr == 0) {
1004 for (i = 0; i < actual; ++i)
1005 thread_deallocate(threads[i]);
1006 kfree(addr, size);
1007 return (KERN_RESOURCE_SHORTAGE);
1008 }
1009
1010 bcopy(addr, newaddr, size_needed);
1011 kfree(addr, size);
1012 threads = (thread_t *)newaddr;
1013 }
1014
1015 *threads_out = threads;
1016 *count = actual;
1017
1018 /* do the conversion that Mig should handle */
1019
1020 for (i = 0; i < actual; ++i)
1021 ((ipc_port_t *) threads)[i] = convert_thread_to_port(threads[i]);
1022 }
1023
1024 return (KERN_SUCCESS);
1025 }
1026
1027 /*
1028 * task_suspend:
1029 *
1030 * Implement a user-level suspension on a task.
1031 *
1032 * Conditions:
1033 * The caller holds a reference to the task
1034 */
1035 kern_return_t
1036 task_suspend(
1037 register task_t task)
1038 {
1039 if (task == TASK_NULL || task == kernel_task)
1040 return (KERN_INVALID_ARGUMENT);
1041
1042 task_lock(task);
1043
1044 if (!task->active) {
1045 task_unlock(task);
1046
1047 return (KERN_FAILURE);
1048 }
1049
1050 if (task->user_stop_count++ > 0) {
1051 /*
1052 * If the stop count was positive, the task is
1053 * already stopped and we can exit.
1054 */
1055 task_unlock(task);
1056
1057 return (KERN_SUCCESS);
1058 }
1059
1060 /*
1061 * Put a kernel-level hold on the threads in the task (all
1062 * user-level task suspensions added together represent a
1063 * single kernel-level hold). We then wait for the threads
1064 * to stop executing user code.
1065 */
1066 task_hold_locked(task);
1067 task_wait_locked(task);
1068
1069 task_unlock(task);
1070
1071 return (KERN_SUCCESS);
1072 }
1073
1074 /*
1075 * task_resume:
1076 * Release a kernel hold on a task.
1077 *
1078 * Conditions:
1079 * The caller holds a reference to the task
1080 */
1081 kern_return_t
1082 task_resume(
1083 register task_t task)
1084 {
1085 register boolean_t release = FALSE;
1086
1087 if (task == TASK_NULL || task == kernel_task)
1088 return (KERN_INVALID_ARGUMENT);
1089
1090 task_lock(task);
1091
1092 if (!task->active) {
1093 task_unlock(task);
1094
1095 return (KERN_FAILURE);
1096 }
1097
1098 if (task->user_stop_count > 0) {
1099 if (--task->user_stop_count == 0)
1100 release = TRUE;
1101 }
1102 else {
1103 task_unlock(task);
1104
1105 return (KERN_FAILURE);
1106 }
1107
1108 /*
1109 * Release the task if necessary.
1110 */
1111 if (release)
1112 task_release_locked(task);
1113
1114 task_unlock(task);
1115
1116 return (KERN_SUCCESS);
1117 }
1118
1119 kern_return_t
1120 host_security_set_task_token(
1121 host_security_t host_security,
1122 task_t task,
1123 security_token_t sec_token,
1124 audit_token_t audit_token,
1125 host_priv_t host_priv)
1126 {
1127 ipc_port_t host_port;
1128 kern_return_t kr;
1129
1130 if (task == TASK_NULL)
1131 return(KERN_INVALID_ARGUMENT);
1132
1133 if (host_security == HOST_NULL)
1134 return(KERN_INVALID_SECURITY);
1135
1136 task_lock(task);
1137 task->sec_token = sec_token;
1138 task->audit_token = audit_token;
1139 task_unlock(task);
1140
1141 if (host_priv != HOST_PRIV_NULL) {
1142 kr = host_get_host_priv_port(host_priv, &host_port);
1143 } else {
1144 kr = host_get_host_port(host_priv_self(), &host_port);
1145 }
1146 assert(kr == KERN_SUCCESS);
1147 kr = task_set_special_port(task, TASK_HOST_PORT, host_port);
1148 return(kr);
1149 }
1150
1151 /*
1152 * Utility routine to set a ledger
1153 */
1154 kern_return_t
1155 task_set_ledger(
1156 task_t task,
1157 ledger_t wired,
1158 ledger_t paged)
1159 {
1160 if (task == TASK_NULL)
1161 return(KERN_INVALID_ARGUMENT);
1162
1163 task_lock(task);
1164 if (wired) {
1165 ipc_port_release_send(task->wired_ledger_port);
1166 task->wired_ledger_port = ledger_copy(wired);
1167 }
1168 if (paged) {
1169 ipc_port_release_send(task->paged_ledger_port);
1170 task->paged_ledger_port = ledger_copy(paged);
1171 }
1172 task_unlock(task);
1173
1174 return(KERN_SUCCESS);
1175 }
1176
1177 /*
1178 * This routine was added, pretty much exclusively, for registering the
1179 * RPC glue vector for in-kernel short circuited tasks. Rather than
1180 * removing it completely, I have only disabled that feature (which was
1181 * the only feature at the time). It just appears that we are going to
1182 * want to add some user data to tasks in the future (i.e. bsd info,
1183 * task names, etc...), so I left it in the formal task interface.
1184 */
1185 kern_return_t
1186 task_set_info(
1187 task_t task,
1188 task_flavor_t flavor,
1189 __unused task_info_t task_info_in, /* pointer to IN array */
1190 __unused mach_msg_type_number_t task_info_count)
1191 {
1192 if (task == TASK_NULL)
1193 return(KERN_INVALID_ARGUMENT);
1194
1195 switch (flavor) {
1196 default:
1197 return (KERN_INVALID_ARGUMENT);
1198 }
1199 return (KERN_SUCCESS);
1200 }
1201
1202 kern_return_t
1203 task_info(
1204 task_t task,
1205 task_flavor_t flavor,
1206 task_info_t task_info_out,
1207 mach_msg_type_number_t *task_info_count)
1208 {
1209 if (task == TASK_NULL)
1210 return (KERN_INVALID_ARGUMENT);
1211
1212 switch (flavor) {
1213
1214 case TASK_BASIC_INFO_32:
1215 {
1216 task_basic_info_32_t basic_info;
1217 vm_map_t map;
1218
1219 if (*task_info_count < TASK_BASIC_INFO_32_COUNT)
1220 return (KERN_INVALID_ARGUMENT);
1221
1222 basic_info = (task_basic_info_32_t)task_info_out;
1223
1224 map = (task == kernel_task)? kernel_map: task->map;
1225 basic_info->virtual_size = CAST_DOWN(vm_offset_t,map->size);
1226 basic_info->resident_size = pmap_resident_count(map->pmap)
1227 * PAGE_SIZE;
1228
1229 task_lock(task);
1230 basic_info->policy = ((task != kernel_task)?
1231 POLICY_TIMESHARE: POLICY_RR);
1232 basic_info->suspend_count = task->user_stop_count;
1233
1234 absolutetime_to_microtime(
1235 task->total_user_time,
1236 &basic_info->user_time.seconds,
1237 &basic_info->user_time.microseconds);
1238 absolutetime_to_microtime(
1239 task->total_system_time,
1240 &basic_info->system_time.seconds,
1241 &basic_info->system_time.microseconds);
1242 task_unlock(task);
1243
1244 *task_info_count = TASK_BASIC_INFO_32_COUNT;
1245 break;
1246 }
1247
1248 case TASK_BASIC_INFO_64:
1249 {
1250 task_basic_info_64_t basic_info;
1251 vm_map_t map;
1252
1253 if (*task_info_count < TASK_BASIC_INFO_64_COUNT)
1254 return (KERN_INVALID_ARGUMENT);
1255
1256 basic_info = (task_basic_info_64_t)task_info_out;
1257
1258 map = (task == kernel_task)? kernel_map: task->map;
1259 basic_info->virtual_size = map->size;
1260 basic_info->resident_size = (mach_vm_size_t)(pmap_resident_count(map->pmap)
1261 * PAGE_SIZE);
1262
1263 task_lock(task);
1264 basic_info->policy = ((task != kernel_task)?
1265 POLICY_TIMESHARE: POLICY_RR);
1266 basic_info->suspend_count = task->user_stop_count;
1267
1268 absolutetime_to_microtime(
1269 task->total_user_time,
1270 &basic_info->user_time.seconds,
1271 &basic_info->user_time.microseconds);
1272 absolutetime_to_microtime(
1273 task->total_system_time,
1274 &basic_info->system_time.seconds,
1275 &basic_info->system_time.microseconds);
1276 task_unlock(task);
1277
1278 *task_info_count = TASK_BASIC_INFO_64_COUNT;
1279 break;
1280 }
1281
1282 case TASK_THREAD_TIMES_INFO:
1283 {
1284 register task_thread_times_info_t times_info;
1285 register thread_t thread;
1286
1287 if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT)
1288 return (KERN_INVALID_ARGUMENT);
1289
1290 times_info = (task_thread_times_info_t) task_info_out;
1291 times_info->user_time.seconds = 0;
1292 times_info->user_time.microseconds = 0;
1293 times_info->system_time.seconds = 0;
1294 times_info->system_time.microseconds = 0;
1295
1296 task_lock(task);
1297
1298 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1299 time_value_t user_time, system_time;
1300
1301 thread_read_times(thread, &user_time, &system_time);
1302
1303 time_value_add(&times_info->user_time, &user_time);
1304 time_value_add(&times_info->system_time, &system_time);
1305 }
1306
1307 task_unlock(task);
1308
1309 *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
1310 break;
1311 }
1312
1313 case TASK_ABSOLUTETIME_INFO:
1314 {
1315 task_absolutetime_info_t info;
1316 register thread_t thread;
1317
1318 if (*task_info_count < TASK_ABSOLUTETIME_INFO_COUNT)
1319 return (KERN_INVALID_ARGUMENT);
1320
1321 info = (task_absolutetime_info_t)task_info_out;
1322 info->threads_user = info->threads_system = 0;
1323
1324 task_lock(task);
1325
1326 info->total_user = task->total_user_time;
1327 info->total_system = task->total_system_time;
1328
1329 queue_iterate(&task->threads, thread, thread_t, task_threads) {
1330 uint64_t tval;
1331
1332 tval = timer_grab(&thread->user_timer);
1333 info->threads_user += tval;
1334 info->total_user += tval;
1335
1336 tval = timer_grab(&thread->system_timer);
1337 info->threads_system += tval;
1338 info->total_system += tval;
1339 }
1340
1341 task_unlock(task);
1342
1343 *task_info_count = TASK_ABSOLUTETIME_INFO_COUNT;
1344 break;
1345 }
1346
1347 /* OBSOLETE */
1348 case TASK_SCHED_FIFO_INFO:
1349 {
1350
1351 if (*task_info_count < POLICY_FIFO_BASE_COUNT)
1352 return (KERN_INVALID_ARGUMENT);
1353
1354 return (KERN_INVALID_POLICY);
1355 }
1356
1357 /* OBSOLETE */
1358 case TASK_SCHED_RR_INFO:
1359 {
1360 register policy_rr_base_t rr_base;
1361
1362 if (*task_info_count < POLICY_RR_BASE_COUNT)
1363 return (KERN_INVALID_ARGUMENT);
1364
1365 rr_base = (policy_rr_base_t) task_info_out;
1366
1367 task_lock(task);
1368 if (task != kernel_task) {
1369 task_unlock(task);
1370 return (KERN_INVALID_POLICY);
1371 }
1372
1373 rr_base->base_priority = task->priority;
1374 task_unlock(task);
1375
1376 rr_base->quantum = std_quantum_us / 1000;
1377
1378 *task_info_count = POLICY_RR_BASE_COUNT;
1379 break;
1380 }
1381
1382 /* OBSOLETE */
1383 case TASK_SCHED_TIMESHARE_INFO:
1384 {
1385 register policy_timeshare_base_t ts_base;
1386
1387 if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT)
1388 return (KERN_INVALID_ARGUMENT);
1389
1390 ts_base = (policy_timeshare_base_t) task_info_out;
1391
1392 task_lock(task);
1393 if (task == kernel_task) {
1394 task_unlock(task);
1395 return (KERN_INVALID_POLICY);
1396 }
1397
1398 ts_base->base_priority = task->priority;
1399 task_unlock(task);
1400
1401 *task_info_count = POLICY_TIMESHARE_BASE_COUNT;
1402 break;
1403 }
1404
1405 case TASK_SECURITY_TOKEN:
1406 {
1407 register security_token_t *sec_token_p;
1408
1409 if (*task_info_count < TASK_SECURITY_TOKEN_COUNT)
1410 return (KERN_INVALID_ARGUMENT);
1411
1412 sec_token_p = (security_token_t *) task_info_out;
1413
1414 task_lock(task);
1415 *sec_token_p = task->sec_token;
1416 task_unlock(task);
1417
1418 *task_info_count = TASK_SECURITY_TOKEN_COUNT;
1419 break;
1420 }
1421
1422 case TASK_AUDIT_TOKEN:
1423 {
1424 register audit_token_t *audit_token_p;
1425
1426 if (*task_info_count < TASK_AUDIT_TOKEN_COUNT)
1427 return (KERN_INVALID_ARGUMENT);
1428
1429 audit_token_p = (audit_token_t *) task_info_out;
1430
1431 task_lock(task);
1432 *audit_token_p = task->audit_token;
1433 task_unlock(task);
1434
1435 *task_info_count = TASK_AUDIT_TOKEN_COUNT;
1436 break;
1437 }
1438
1439 case TASK_SCHED_INFO:
1440 return (KERN_INVALID_ARGUMENT);
1441
1442 case TASK_EVENTS_INFO:
1443 {
1444 register task_events_info_t events_info;
1445
1446 if (*task_info_count < TASK_EVENTS_INFO_COUNT)
1447 return (KERN_INVALID_ARGUMENT);
1448
1449 events_info = (task_events_info_t) task_info_out;
1450
1451 task_lock(task);
1452 events_info->faults = task->faults;
1453 events_info->pageins = task->pageins;
1454 events_info->cow_faults = task->cow_faults;
1455 events_info->messages_sent = task->messages_sent;
1456 events_info->messages_received = task->messages_received;
1457 events_info->syscalls_mach = task->syscalls_mach;
1458 events_info->syscalls_unix = task->syscalls_unix;
1459 events_info->csw = task->csw;
1460 task_unlock(task);
1461
1462 *task_info_count = TASK_EVENTS_INFO_COUNT;
1463 break;
1464 }
1465
1466 default:
1467 return (KERN_INVALID_ARGUMENT);
1468 }
1469
1470 return (KERN_SUCCESS);
1471 }
1472
1473 /*
1474 * task_assign:
1475 *
1476 * Change the assigned processor set for the task
1477 */
1478 kern_return_t
1479 task_assign(
1480 __unused task_t task,
1481 __unused processor_set_t new_pset,
1482 __unused boolean_t assign_threads)
1483 {
1484 return(KERN_FAILURE);
1485 }
1486
1487 /*
1488 * task_assign_default:
1489 *
1490 * Version of task_assign to assign to default processor set.
1491 */
1492 kern_return_t
1493 task_assign_default(
1494 task_t task,
1495 boolean_t assign_threads)
1496 {
1497 return (task_assign(task, &default_pset, assign_threads));
1498 }
1499
1500 /*
1501 * task_get_assignment
1502 *
1503 * Return name of processor set that task is assigned to.
1504 */
1505 kern_return_t
1506 task_get_assignment(
1507 task_t task,
1508 processor_set_t *pset)
1509 {
1510 if (!task->active)
1511 return(KERN_FAILURE);
1512
1513 *pset = task->processor_set;
1514 pset_reference(*pset);
1515 return(KERN_SUCCESS);
1516 }
1517
1518
1519 /*
1520 * task_policy
1521 *
1522 * Set scheduling policy and parameters, both base and limit, for
1523 * the given task. Policy must be a policy which is enabled for the
1524 * processor set. Change contained threads if requested.
1525 */
1526 kern_return_t
1527 task_policy(
1528 __unused task_t task,
1529 __unused policy_t policy_id,
1530 __unused policy_base_t base,
1531 __unused mach_msg_type_number_t count,
1532 __unused boolean_t set_limit,
1533 __unused boolean_t change)
1534 {
1535 return(KERN_FAILURE);
1536 }
1537
1538 /*
1539 * task_set_policy
1540 *
1541 * Set scheduling policy and parameters, both base and limit, for
1542 * the given task. Policy can be any policy implemented by the
1543 * processor set, whether enabled or not. Change contained threads
1544 * if requested.
1545 */
1546 kern_return_t
1547 task_set_policy(
1548 __unused task_t task,
1549 __unused processor_set_t pset,
1550 __unused policy_t policy_id,
1551 __unused policy_base_t base,
1552 __unused mach_msg_type_number_t base_count,
1553 __unused policy_limit_t limit,
1554 __unused mach_msg_type_number_t limit_count,
1555 __unused boolean_t change)
1556 {
1557 return(KERN_FAILURE);
1558 }
1559
1560 #if FAST_TAS
1561 kern_return_t
1562 task_set_ras_pc(
1563 task_t task,
1564 vm_offset_t pc,
1565 vm_offset_t endpc)
1566 {
1567 extern int fast_tas_debug;
1568
1569 if (fast_tas_debug) {
1570 printf("task 0x%x: setting fast_tas to [0x%x, 0x%x]\n",
1571 task, pc, endpc);
1572 }
1573 task_lock(task);
1574 task->fast_tas_base = pc;
1575 task->fast_tas_end = endpc;
1576 task_unlock(task);
1577 return KERN_SUCCESS;
1578 }
1579 #else /* FAST_TAS */
1580 kern_return_t
1581 task_set_ras_pc(
1582 __unused task_t task,
1583 __unused vm_offset_t pc,
1584 __unused vm_offset_t endpc)
1585 {
1586 return KERN_FAILURE;
1587 }
1588 #endif /* FAST_TAS */
1589
1590 void
1591 task_synchronizer_destroy_all(task_t task)
1592 {
1593 semaphore_t semaphore;
1594 lock_set_t lock_set;
1595
1596 /*
1597 * Destroy owned semaphores
1598 */
1599
1600 while (!queue_empty(&task->semaphore_list)) {
1601 semaphore = (semaphore_t) queue_first(&task->semaphore_list);
1602 (void) semaphore_destroy(task, semaphore);
1603 }
1604
1605 /*
1606 * Destroy owned lock sets
1607 */
1608
1609 while (!queue_empty(&task->lock_set_list)) {
1610 lock_set = (lock_set_t) queue_first(&task->lock_set_list);
1611 (void) lock_set_destroy(task, lock_set);
1612 }
1613 }
1614
1615 /*
1616 * We need to export some functions to other components that
1617 * are currently implemented in macros within the osfmk
1618 * component. Just export them as functions of the same name.
1619 */
1620 boolean_t is_kerneltask(task_t t)
1621 {
1622 if (t == kernel_task)
1623 return (TRUE);
1624
1625 return (FALSE);
1626 }
1627
1628 #undef current_task
1629 task_t current_task(void);
1630 task_t current_task(void)
1631 {
1632 return (current_task_fast());
1633 }
1634
1635 #undef task_reference
1636 void task_reference(task_t task);
1637 void
1638 task_reference(
1639 task_t task)
1640 {
1641 if (task != TASK_NULL)
1642 task_reference_internal(task);
1643 }