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