1 /*-
2 * Copyright (c) 2014-2015, Matthew Macy <mmacy@nextbsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Neither the name of Matthew Macy nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27 /*
28 * Copyright 1991-1998 by Open Software Foundation, Inc.
29 * All Rights Reserved
30 *
31 * Permission to use, copy, modify, and distribute this software and
32 * its documentation for any purpose and without fee is hereby granted,
33 * provided that the above copyright notice appears in all copies and
34 * that both the copyright notice and this permission notice appear in
35 * supporting documentation.
36 *
37 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
38 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
39 * FOR A PARTICULAR PURPOSE.
40 *
41 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
42 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
43 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
44 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
45 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46 */
47 /*
48 * Mach Operating System
49 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
50 * All Rights Reserved.
51 *
52 * Permission to use, copy, modify and distribute this software and its
53 * documentation is hereby granted, provided that both the copyright
54 * notice and this permission notice appear in all copies of the
55 * software, derivative works or modified versions, and any portions
56 * thereof, and that both notices appear in supporting documentation.
57 *
58 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
59 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
60 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
61 *
62 * Carnegie Mellon requests users of this software to return to
63 *
64 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
65 * School of Computer Science
66 * Carnegie Mellon University
67 * Pittsburgh PA 15213-3890
68 *
69 * any improvements or extensions that they make and grant Carnegie Mellon
70 * the rights to redistribute these changes.
71 */
72 /*
73 * File: kern/task.c
74 * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub,
75 * David Black
76 *
77 * Task management primitives implementation.
78 */
79 /*
80 * Copyright (c) 1993 The University of Utah and
81 * the Computer Systems Laboratory (CSL). All rights reserved.
82 *
83 * Permission to use, copy, modify and distribute this software and its
84 * documentation is hereby granted, provided that both the copyright
85 * notice and this permission notice appear in all copies of the
86 * software, derivative works or modified versions, and any portions
87 * thereof, and that both notices appear in supporting documentation.
88 *
89 * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
90 * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
91 * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
92 *
93 * CSL requests users of this software to return to csl-dist@cs.utah.edu any
94 * improvements that they make and grant CSL redistribution rights.
95 *
96 */
97
98 #include <sys/cdefs.h>
99 #include <sys/types.h>
100 #include <sys/param.h>
101 #include <sys/eventhandler.h>
102 #include <sys/kernel.h>
103 #include <sys/mach/vm_types.h>
104
105 #include <sys/mach/task_info.h>
106 #include <sys/mach/task_special_ports.h>
107 #include <sys/mach/mach_types.h>
108 #include <sys/mach/rpc.h>
109 #include <sys/mach/ipc/ipc_space.h>
110 #include <sys/mach/ipc/ipc_entry.h>
111 #include <sys/mach/mach_param.h>
112
113 #include <sys/mach/task.h>
114 #include <sys/mach/ipc/ipc_kmsg.h>
115 #include <sys/mach/thread.h>
116
117 #include <sys/mach/sched_prim.h> /* for thread_wakeup */
118 #include <sys/mach/ipc_tt.h>
119 #if 0
120 #include <sys/mach/ledger.h>
121 #endif
122 #include <sys/mach/host_special_ports.h>
123 #include <sys/mach/host.h>
124 #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */
125 #include <vm/uma.h>
126 #if MACH_KDB
127 #include <ddb/db_sym.h>
128 #endif /* MACH_KDB */
129
130 #include <sys/mach/queue.h>
131 /*
132 * Exported interfaces
133 */
134 #include <sys/mach/task_server.h>
135 #include <sys/mach/mach_host_server.h>
136 #include <sys/mach/mach_port_server.h>
137
138 struct processor_set default_pset;
139 unsigned int sched_ticks;
140 task_t kernel_task;
141 uma_zone_t task_zone;
142
143 /* Forwards */
144
145
146 kern_return_t task_hold_locked(
147 task_t task);
148 void task_wait_locked(
149 task_t task);
150 kern_return_t task_release(
151 task_t task);
152 void task_act_iterate(
153 task_t task,
154 kern_return_t (*func)(thread_act_t inc));
155 void task_free(
156 task_t task );
157 void task_synchronizer_destroy_all(
158 task_t task);
159
160
161 kern_return_t
task_create(task_t parent_task,__unused ledger_array_t ledger_ports,__unused mach_msg_type_number_t num_ledger_ports,__unused boolean_t inherit_memory,__unused task_t * child_task)162 task_create(
163 task_t parent_task,
164 __unused ledger_array_t ledger_ports,
165 __unused mach_msg_type_number_t num_ledger_ports,
166 __unused boolean_t inherit_memory,
167 __unused task_t *child_task) /* OUT */
168 {
169 if (parent_task == TASK_NULL)
170 return(KERN_INVALID_ARGUMENT);
171
172 return(KERN_FAILURE);
173 }
174
175
176 static kern_return_t
task_create_internal(task_t new_task)177 task_create_internal(
178 task_t new_task)
179 {
180
181 /* one ref for just being alive; one for our caller */
182 new_task->ref_count = 2;
183 new_task->semaphores_owned = 0;
184
185 ipc_task_create(new_task);
186
187 return (KERN_SUCCESS);
188 }
189
190 static kern_return_t
task_init_internal(task_t parent_task,task_t new_task)191 task_init_internal(
192 task_t parent_task,
193 task_t new_task)
194 {
195 register processor_set_t pset;
196
197 /* one ref for just being alive; one for our caller */
198 new_task->ref_count = 2;
199 new_task->semaphores_owned = 0;
200
201 ipc_task_init(new_task, parent_task);
202
203 if (parent_task != TASK_NULL) {
204 #ifdef notyet
205 pset = parent_task->processor_set;
206 if (!pset->active)
207 pset = &default_pset;
208 #endif
209 set_security_token(new_task);
210 new_task->policy = parent_task->policy;
211 } else {
212 pset = &default_pset;
213 new_task->policy = POLICY_TIMESHARE;
214 new_task->sec_token = KERNEL_SECURITY_TOKEN;
215 new_task->audit_token = KERNEL_AUDIT_TOKEN;
216 }
217 ipc_task_enable(new_task);
218 return(KERN_SUCCESS);
219 }
220
221
222
223 /*
224 * task_free:
225 *
226 * Called by task_deallocate when the task's reference count drops to zero.
227 * Task is locked.
228 */
229 void
task_free(register task_t task)230 task_free( register task_t task )
231 {
232 register processor_set_t pset;
233
234 /* tasks are tied to proc structures so should only be freed if proc goes away */
235 task_unlock(task);
236 return;
237 /*
238 * Temporarily restore the reference we dropped above, then
239 * freeze the task so that the task->processor_set field
240 * cannot change. In the !MACH_HOST case, the logic can be
241 * simplified, since the default_pset is the only pset.
242 */
243 ++task->ref_count;
244 task_unlock(task);
245 pset = task->processor_set;
246 task_lock(task);
247 if (--task->ref_count > 0) {
248 /*
249 * A new reference appeared (probably from the pset).
250 * Back out. Must unfreeze inline since we'already
251 * dropped our reference.
252 */
253 task_unlock(task);
254 return;
255 }
256 task_unlock(task);
257 is_release(task->itk_space);
258 uma_zfree(task_zone, task);
259 }
260
261
262 void
task_deallocate(task_t task)263 task_deallocate( task_t task )
264 {
265 if (task != TASK_NULL) {
266 int x;
267 task_lock(task);
268 x = --task->ref_count;
269 if (x == 0)
270 task_free(task); /* unlocks task */
271 else
272 task_unlock(task);
273 }
274 }
275
276 void
task_reference(register task_t task)277 task_reference( register task_t task )
278 {
279 if (task != TASK_NULL) {
280 task_lock(task);
281 task->ref_count++;
282 task_unlock(task);
283 }
284 }
285
286 /*
287 * task_terminate:
288 *
289 * Terminate the specified task. See comments on thread_terminate
290 * (kern/thread.c) about problems with terminating the "current task."
291 */
292 kern_return_t
task_terminate(register task_t task)293 task_terminate(
294 register task_t task)
295 {
296 #ifdef notyet
297 register thread_t thread, cur_thread;
298 #if 0
299 register queue_head_t *list;
300 #endif
301 register task_t cur_task;
302 thread_act_t thr_act, cur_thr_act;
303
304 if (task == TASK_NULL)
305 return(KERN_INVALID_ARGUMENT);
306
307 assert(task != kernel_task);
308 #if 0
309 list = &task->thr_acts;
310 cur_task = current_task();
311 cur_thr_act = current_thread()->top_act;
312 #endif
313
314 /*
315 * Deactivate task so that it can't be terminated again,
316 * and so lengthy operations in progress will abort.
317 *
318 * If the current thread is in this task, remove it from
319 * the task's thread list to keep the thread-termination
320 * loop simple.
321 */
322 if (task == cur_task) {
323 task_lock(task);
324 if (!task->active) {
325 /*
326 * Task is already being terminated.
327 */
328 task_unlock(task);
329 thread_block();
330 return(KERN_FAILURE);
331 }
332
333 task_hold_locked(task);
334 #if 0
335 task->active = FALSE;
336
337 /*
338 * Make sure current thread is not being terminated.
339 */
340 mutex_lock(&task->act_list_lock);
341 cur_thread = act_lock_thread(cur_thr_act);
342 if (!cur_thr_act->active) {
343 act_unlock_thread(cur_thr_act);
344 mutex_unlock(&task->act_list_lock);
345 task_unlock(task);
346 thread_terminate(cur_thr_act);
347 return(KERN_FAILURE);
348 }
349
350 /*
351 * make sure that this thread is the last one in the list
352 */
353 queue_remove(list, cur_thr_act, thread_act_t, thr_acts);
354 queue_enter(list, cur_thr_act, thread_act_t, thr_acts);
355 act_unlock_thread(cur_thr_act);
356 mutex_unlock(&task->act_list_lock);
357 /*
358 * Shut down this thread's ipc now because it must
359 * be left alone to terminate the task.
360 */
361 ipc_thr_act_disable(cur_thr_act);
362 ipc_thr_act_terminate(cur_thr_act);
363 #endif
364 }
365 else {
366 /*
367 * Lock both current and victim task to check for
368 * potential deadlock.
369 */
370 if (task < cur_task) {
371 task_lock(task);
372 task_lock(cur_task);
373 }
374 else {
375 task_lock(cur_task);
376 task_lock(task);
377 }
378 /*
379 * Check if current thread_act or task is being terminated.
380 */
381 cur_thread = act_lock_thread(cur_thr_act);
382 if ((!cur_task->active) || (!cur_thr_act->active)) {
383 /*
384 * Current task or thread is being terminated.
385 */
386 act_unlock_thread(cur_thr_act);
387 task_unlock(task);
388 task_unlock(cur_task);
389 return(KERN_FAILURE);
390 }
391 act_unlock_thread(cur_thr_act);
392 task_unlock(cur_task);
393
394 if (!task->active) {
395 /*
396 * Task is already being terminated.
397 */
398 task_unlock(task);
399 thread_block();
400 return(KERN_FAILURE);
401 }
402 task_hold_locked(task);
403 task->active = FALSE;
404 }
405
406 /*
407 * Prevent further execution of the task. ipc_task_disable
408 * prevents further task operations via the task port.
409 * If this is the current task, the current thread will
410 * be left running.
411 */
412 ipc_task_disable(task);
413 task_wait_locked(task);
414
415 /*
416 * Terminate each thread in the task. Depending on the
417 * state of the thread, this can mean a number of things.
418 * However, we just call thread_terminate(), which
419 * takes care of all cases (see that code for details).
420 *
421 * The task_port is closed down, so no more thread_create
422 * operations can be done. Thread_terminate closes the
423 * thread port for each thread; when that is done, the
424 * thread will eventually disappear. Thus the loop will
425 * terminate.
426 * Need to call thread_block() inside loop because some
427 * other thread (e.g., the reaper) may have to run to get rid
428 * of all references to the thread; it won't vanish from
429 * the task's thread list until the last one is gone.
430 */
431 while (!queue_empty(list)) {
432 thr_act = (thread_act_t) queue_first(list);
433 act_reference(thr_act);
434 task_unlock(task);
435 thread_terminate(thr_act);
436 act_deallocate(thr_act);
437 task_lock(task);
438 }
439 task_unlock(task);
440 #endif
441 /*
442 * Destroy all synchronizers owned by the task.
443 */
444 task_synchronizer_destroy_all(task);
445
446 /*
447 * Shut down IPC.
448 */
449 ipc_task_terminate(task);
450
451 /*
452 * Deallocate the task's reference to itself.
453 */
454 task_deallocate(task);
455
456 return(KERN_SUCCESS);
457 }
458
459 /*
460 * task_hold_locked:
461 *
462 * Suspend execution of the specified task.
463 * This is a recursive-style suspension of the task, a count of
464 * suspends is maintained.
465 *
466 * CONDITIONS: the task is locked.
467 */
468 kern_return_t
task_hold_locked(register task_t task)469 task_hold_locked(
470 register task_t task)
471 {
472 #if 0
473 register queue_head_t *list;
474 register thread_act_t thr_act, cur_thr_act;
475
476 cur_thr_act = current_act();
477 #endif
478
479 if (!task->active) {
480 return(KERN_FAILURE);
481 }
482 #if 0
483
484 task->suspend_count++;
485 /*
486 * Iterate through all the thread_act's and hold them.
487 * Do not hold the current thread_act if it is within the
488 * task.
489 */
490 list = &task->thr_acts;
491 thr_act = (thread_act_t) queue_first(list);
492 while (!queue_end(list, (queue_entry_t) thr_act)) {
493 (void)act_lock_thread(thr_act);
494 thread_hold(thr_act);
495 act_unlock_thread(thr_act);
496 thr_act = (thread_act_t) queue_next(&thr_act->thr_acts);
497 }
498 #endif
499 return(KERN_SUCCESS);
500 }
501
502
503 kern_return_t
task_release(register task_t task)504 task_release(
505 register task_t task)
506 {
507 #if 0
508 register queue_head_t *list;
509 register thread_act_t thr_act, next;
510
511 task_lock(task);
512 if (!task->active) {
513 task_unlock(task);
514 return(KERN_FAILURE);
515 }
516
517 task->suspend_count--;
518
519 /*
520 * Iterate through all the thread_act's and release them.
521 */
522 list = &task->thr_acts;
523 thr_act = (thread_act_t) queue_first(list);
524 while (!queue_end(list, (queue_entry_t) thr_act)) {
525 next = (thread_act_t) queue_next(&thr_act->thr_acts);
526 (void)act_lock_thread(thr_act);
527 thread_release(thr_act);
528 act_unlock_thread(thr_act);
529 thr_act = next;
530 }
531 task_unlock(task);
532 #endif
533 return(KERN_SUCCESS);
534 }
535
536 kern_return_t
task_threads(task_t task,thread_act_array_t * thr_act_list,mach_msg_type_number_t * count)537 task_threads(
538 task_t task,
539 thread_act_array_t *thr_act_list,
540 mach_msg_type_number_t *count)
541 {
542 #if 0
543 unsigned int actual; /* this many thr_acts */
544 thread_act_t thr_act;
545 thread_act_t *thr_acts;
546 thread_t thread;
547 int i, j;
548 boolean_t rt = FALSE; /* ### This boolean is FALSE, because there
549 * currently exists no mechanism to determine
550 * whether or not the reply port is an RT port
551 */
552
553
554 vm_size_t size, size_needed;
555 vm_offset_t addr;
556
557 if (task == TASK_NULL)
558 return KERN_INVALID_ARGUMENT;
559
560 size = 0; addr = 0;
561
562 for (;;) {
563 task_lock(task);
564 if (!task->active) {
565 task_unlock(task);
566 if (size != 0)
567 KFREE(addr, size, rt);
568 return KERN_FAILURE;
569 }
570
571 actual = task->thr_act_count;
572
573 /* do we have the memory we need? */
574 size_needed = actual * sizeof(mach_port_t);
575 if (size_needed <= size)
576 break;
577
578 /* unlock the task and allocate more memory */
579 task_unlock(task);
580
581 if (size != 0)
582 KFREE(addr, size, rt);
583
584 assert(size_needed > 0);
585 size = size_needed;
586
587 addr = KALLOC(size, rt);
588 if (addr == 0)
589 return KERN_RESOURCE_SHORTAGE;
590 }
591
592 /* OK, have memory and the task is locked & active */
593 thr_acts = (thread_act_t *) addr;
594
595 for (i = j = 0, thr_act = (thread_act_t) queue_first(&task->thr_acts);
596 i < actual;
597 i++, thr_act = (thread_act_t) queue_next(&thr_act->thr_acts)) {
598 act_reference(thr_act);
599 thr_acts[j++] = thr_act;
600 }
601 assert(queue_end(&task->thr_acts, (queue_entry_t) thr_act));
602 actual = j;
603
604 /* can unlock task now that we've got the thr_act refs */
605 task_unlock(task);
606
607 if (actual == 0) {
608 /* no thr_acts, so return null pointer and deallocate memory */
609
610 *thr_act_list = 0;
611 *count = 0;
612
613 if (size != 0)
614 KFREE(addr, size, rt);
615 } else {
616 /* if we allocated too much, must copy */
617
618 if (size_needed < size) {
619 vm_offset_t newaddr;
620
621 newaddr = KALLOC(size_needed, rt);
622 if (newaddr == 0) {
623 for (i = 0; i < actual; i++)
624 act_deallocate(thr_acts[i]);
625 KFREE(addr, size, rt);
626 return KERN_RESOURCE_SHORTAGE;
627 }
628
629 bcopy((char *) addr, (char *) newaddr, size_needed);
630 KFREE(addr, size, rt);
631 thr_acts = (thread_act_t *) newaddr;
632 }
633
634 *thr_act_list = (mach_port_t *) thr_acts;
635 *count = actual;
636
637 /* do the conversion that Mig should handle */
638
639 for (i = 0; i < actual; i++)
640 ((ipc_port_t *) thr_acts)[i] =
641 convert_act_to_port(thr_acts[i]);
642 }
643 #endif
644 return KERN_SUCCESS;
645 }
646
647 kern_return_t
task_suspend(register task_t task)648 task_suspend(
649 register task_t task)
650 {
651 #if 0
652 if (task == TASK_NULL)
653 return (KERN_INVALID_ARGUMENT);
654
655 task_lock(task);
656 if (!task->active) {
657 task_unlock(task);
658 return (KERN_FAILURE);
659 }
660 if ((task->user_stop_count)++ > 0) {
661 /*
662 * If the stop count was positive, the task is
663 * already stopped and we can exit.
664 */
665 task_unlock(task);
666 return (KERN_SUCCESS);
667 }
668
669 /*
670 * Hold all of the threads in the task, and wait for
671 * them to stop. If the current thread is within
672 * this task, hold it separately so that all of the
673 * other threads can stop first.
674 */
675 if (task_hold_locked(task) != KERN_SUCCESS) {
676 task_unlock(task);
677 return (KERN_FAILURE);
678 }
679
680 task_wait_locked(task);
681 task_unlock(task);
682 #endif
683 return (KERN_SUCCESS);
684 }
685
686 /*
687 * Wait for all threads in task to stop. Called with task locked.
688 */
689 void
task_wait_locked(register task_t task)690 task_wait_locked(
691 register task_t task)
692 {
693 #if 0
694 register queue_head_t *list;
695 register thread_act_t thr_act, refd_thr_act;
696 register thread_t thread, cur_thr;
697
698 cur_thr = current_thread();
699 /*
700 * Iterate through all the thread's and wait for them to
701 * stop. Do not wait for the current thread if it is within
702 * the task.
703 */
704 list = &task->thr_acts;
705 refd_thr_act = THR_ACT_NULL;
706 while (1) {
707 thr_act = (thread_act_t) queue_first(list);
708 while (!queue_end(list, (queue_entry_t) thr_act)) {
709 thread = act_lock_thread(thr_act);
710 if (refd_thr_act != THR_ACT_NULL) {
711 act_deallocate(refd_thr_act);
712 refd_thr_act = THR_ACT_NULL;
713 }
714 if (thread &&
715 thr_act == thread->top_act && thread != cur_thr) {
716 refd_thr_act = thr_act;
717 act_locked_act_reference(thr_act);
718 act_unlock_thread(thr_act);
719 task_unlock(task);
720 (void)thread_wait(thread);
721 task_lock(task);
722 thread = act_lock_thread(thr_act);
723 if (!thr_act->active) {
724 act_unlock_thread(thr_act);
725 break;
726 }
727 }
728 act_unlock_thread(thr_act);
729 thr_act = (thread_act_t) queue_next(&thr_act->thr_acts);
730 }
731 if (queue_end(list, (queue_entry_t)thr_act))
732 break;
733 }
734 if (refd_thr_act != THR_ACT_NULL) {
735 act_deallocate(refd_thr_act);
736 refd_thr_act = THR_ACT_NULL;
737 }
738 #endif
739 }
740
741 kern_return_t
task_resume(register task_t task)742 task_resume(register task_t task)
743 {
744 register boolean_t release;
745
746 if (task == TASK_NULL)
747 return(KERN_INVALID_ARGUMENT);
748
749 release = FALSE;
750 #if 0
751 task_lock(task);
752 if (!task->active) {
753 task_unlock(task);
754 return(KERN_FAILURE);
755 }
756 if (task->user_stop_count > 0) {
757 if (--(task->user_stop_count) == 0)
758 release = TRUE;
759 }
760 else {
761 task_unlock(task);
762 return(KERN_FAILURE);
763 }
764 task_unlock(task);
765 #endif
766 /*
767 * Release the task if necessary.
768 */
769 if (release)
770 return(task_release(task));
771
772 return(KERN_SUCCESS);
773 }
774
775 kern_return_t
task_set_info(task_t task,task_flavor_t flavor,task_info_t task_info_in __unused,mach_msg_type_number_t task_info_count __unused)776 task_set_info(
777 task_t task,
778 task_flavor_t flavor,
779 task_info_t task_info_in __unused, /* pointer to IN array */
780 mach_msg_type_number_t task_info_count __unused)
781 {
782
783 if (task == TASK_NULL)
784 return(KERN_INVALID_ARGUMENT);
785
786 switch (flavor) {
787 default:
788 return (KERN_INVALID_ARGUMENT);
789 }
790 return (KERN_SUCCESS);
791 }
792
793 kern_return_t
task_info(task_t task,task_flavor_t flavor,task_info_t task_info_out,mach_msg_type_number_t * task_info_count)794 task_info(
795 task_t task,
796 task_flavor_t flavor,
797 task_info_t task_info_out,
798 mach_msg_type_number_t *task_info_count)
799 {
800
801 if (task == TASK_NULL)
802 return(KERN_INVALID_ARGUMENT);
803
804 switch (flavor) {
805 case TASK_BASIC_INFO:
806 {
807 register task_basic_info_t basic_info;
808
809 if (*task_info_count < TASK_BASIC_INFO_COUNT) {
810 return(KERN_INVALID_ARGUMENT);
811 }
812
813 basic_info = (task_basic_info_t) task_info_out;
814 #ifdef notyet
815 map = (task == kernel_task) ? kernel_map : task->map;
816
817 basic_info->virtual_size = map->size;
818 basic_info->resident_size = pmap_resident_count(map->pmap)
819 * PAGE_SIZE;
820 task_lock(task);
821 basic_info->policy = task->policy;
822 basic_info->suspend_count = task->user_stop_count;
823 basic_info->user_time.seconds
824 = task->total_user_time.seconds;
825 basic_info->user_time.microseconds
826 = task->total_user_time.microseconds;
827 basic_info->system_time.seconds
828 = task->total_system_time.seconds;
829 basic_info->system_time.microseconds
830 = task->total_system_time.microseconds;
831 task_unlock(task);
832 #endif
833
834 *task_info_count = TASK_BASIC_INFO_COUNT;
835 break;
836 }
837
838 case TASK_THREAD_TIMES_INFO:
839 {
840 register task_thread_times_info_t times_info;
841
842 if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
843 return (KERN_INVALID_ARGUMENT);
844 }
845
846 times_info = (task_thread_times_info_t) task_info_out;
847 times_info->user_time.seconds = 0;
848 times_info->user_time.microseconds = 0;
849 times_info->system_time.seconds = 0;
850 times_info->system_time.microseconds = 0;
851
852 #ifdef notyet
853 task_lock(task);
854 queue_iterate(&task->thr_acts, thr_act,
855 thread_act_t, thr_acts)
856 {
857 thread_t thread;
858 time_value_t user_time, system_time;
859 spl_t s;
860
861 thread = act_lock_thread(thr_act);
862
863 /* Skip empty threads and threads that have migrated
864 * into this task:
865 */
866 if (thr_act->ith_object) {
867 act_unlock_thread(thr_act);
868 continue;
869 }
870 assert(thread); /* Must have thread, if no thread_pool*/
871 s = splsched();
872 thread_lock(thread);
873
874 thread_read_times(thread, &user_time, &system_time);
875
876 thread_unlock(thread);
877 splx(s);
878 act_unlock_thread(thr_act);
879
880 time_value_add(×_info->user_time, &user_time);
881 time_value_add(×_info->system_time, &system_time);
882 }
883 task_unlock(task);
884 #endif
885 *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
886 break;
887 }
888
889 case TASK_SCHED_FIFO_INFO:
890 {
891 register policy_fifo_base_t fifo_base;
892
893 if (*task_info_count < POLICY_FIFO_BASE_COUNT)
894 return(KERN_INVALID_ARGUMENT);
895
896 fifo_base = (policy_fifo_base_t) task_info_out;
897
898 task_lock(task);
899 if (task->policy != POLICY_FIFO) {
900 task_unlock(task);
901 return(KERN_INVALID_POLICY);
902 }
903 fifo_base->base_priority = task->priority;
904 task_unlock(task);
905
906 *task_info_count = POLICY_FIFO_BASE_COUNT;
907 break;
908 }
909
910 case TASK_SCHED_RR_INFO:
911 {
912 register policy_rr_base_t rr_base;
913
914 if (*task_info_count < POLICY_RR_BASE_COUNT)
915 return(KERN_INVALID_ARGUMENT);
916
917 rr_base = (policy_rr_base_t) task_info_out;
918
919 task_lock(task);
920 if (task->policy != POLICY_RR) {
921 task_unlock(task);
922 return(KERN_INVALID_POLICY);
923 }
924 rr_base->base_priority = task->priority;
925 rr_base->quantum = (task->sched_data * ticks)/1000;
926 task_unlock(task);
927
928 *task_info_count = POLICY_RR_BASE_COUNT;
929 break;
930 }
931
932 case TASK_SCHED_TIMESHARE_INFO:
933 {
934 register policy_timeshare_base_t ts_base;
935
936 if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT)
937 return(KERN_INVALID_ARGUMENT);
938
939 ts_base = (policy_timeshare_base_t) task_info_out;
940
941 task_lock(task);
942 if (task->policy != POLICY_TIMESHARE) {
943 task_unlock(task);
944 return(KERN_INVALID_POLICY);
945 }
946 ts_base->base_priority = task->priority;
947 task_unlock(task);
948
949 *task_info_count = POLICY_TIMESHARE_BASE_COUNT;
950 break;
951 }
952
953 case TASK_SECURITY_TOKEN:
954 {
955 register security_token_t *sec_token_p;
956
957 if (*task_info_count < TASK_SECURITY_TOKEN_COUNT) {
958 return(KERN_INVALID_ARGUMENT);
959 }
960
961 sec_token_p = (security_token_t *) task_info_out;
962
963 task_lock(task);
964 *sec_token_p = task->sec_token;
965 task_unlock(task);
966
967 *task_info_count = TASK_SECURITY_TOKEN_COUNT;
968 break;
969 }
970
971 default:
972 return (KERN_INVALID_ARGUMENT);
973 }
974
975 return(KERN_SUCCESS);
976 }
977
978 /*
979 * task_assign:
980 *
981 * Change the assigned processor set for the task
982 */
983 kern_return_t
task_assign(task_t task __unused,processor_set_t new_pset __unused,boolean_t assign_threads __unused)984 task_assign(
985 task_t task __unused,
986 processor_set_t new_pset __unused,
987 boolean_t assign_threads __unused)
988 {
989
990 return (KERN_FAILURE);
991 }
992
993 /*
994 * task_assign_default:
995 *
996 * Version of task_assign to assign to default processor set.
997 */
998 kern_return_t
task_assign_default(task_t task,boolean_t assign_threads)999 task_assign_default(
1000 task_t task,
1001 boolean_t assign_threads)
1002 {
1003 return (task_assign(task, &default_pset, assign_threads));
1004 }
1005
1006 /*
1007 * task_get_assignment
1008 *
1009 * Return name of processor set that task is assigned to.
1010 */
1011 kern_return_t
task_get_assignment(task_t task,processor_set_t * pset)1012 task_get_assignment(
1013 task_t task,
1014 processor_set_t *pset)
1015 {
1016 if (!task->active)
1017 return(KERN_FAILURE);
1018
1019 *pset = task->processor_set;
1020 pset_reference(*pset);
1021 return(KERN_SUCCESS);
1022 }
1023
1024 /*
1025 * task_policy
1026 *
1027 * Set scheduling policy and parameters, both base and limit, for
1028 * the given task. Policy must be a policy which is enabled for the
1029 * processor set. Change contained threads if requested.
1030 */
1031 kern_return_t
task_policy(task_t task,policy_t policy,policy_base_t base,mach_msg_type_number_t count,boolean_t set_limit,boolean_t change)1032 task_policy(
1033 task_t task,
1034 policy_t policy,
1035 policy_base_t base,
1036 mach_msg_type_number_t count,
1037 boolean_t set_limit,
1038 boolean_t change)
1039 {
1040
1041 return (KERN_FAILURE);
1042 }
1043
1044 kern_return_t
task_set_policy(task_t task __unused,processor_set_t pset __unused,policy_t policy __unused,policy_base_t base __unused,mach_msg_type_number_t base_count __unused,policy_limit_t limit __unused,mach_msg_type_number_t limit_count __unused,boolean_t change __unused)1045 task_set_policy(
1046 task_t task __unused,
1047 processor_set_t pset __unused,
1048 policy_t policy __unused,
1049 policy_base_t base __unused,
1050 mach_msg_type_number_t base_count __unused,
1051 policy_limit_t limit __unused,
1052 mach_msg_type_number_t limit_count __unused,
1053 boolean_t change __unused)
1054 {
1055
1056 return (KERN_FAILURE);
1057 }
1058
1059
1060 kern_return_t
task_set_ras_pc(task_t task __unused,vm_offset_t pc __unused,vm_offset_t endpc __unused)1061 task_set_ras_pc(
1062 task_t task __unused,
1063 vm_offset_t pc __unused,
1064 vm_offset_t endpc __unused)
1065 {
1066
1067 return (KERN_FAILURE);
1068 }
1069
1070 void
task_synchronizer_destroy_all(task_t task)1071 task_synchronizer_destroy_all(task_t task)
1072 {
1073 semaphore_t semaphore;
1074
1075 /*
1076 * Destroy owned semaphores
1077 */
1078
1079 while (!queue_empty(&task->semaphore_list)) {
1080 semaphore = (semaphore_t) queue_first(&task->semaphore_list);
1081 (void) semaphore_destroy(task, semaphore);
1082 }
1083 }
1084
1085 static long task_uniqueid;
1086
1087 static void
mach_task_init(void * arg __unused,struct proc * p)1088 mach_task_init(void *arg __unused, struct proc *p)
1089 {
1090 task_t task;
1091
1092 p->p_machdata = task = uma_zalloc(task_zone, M_WAITOK|M_ZERO);
1093 task->itk_p = p;
1094
1095 mach_mutex_init(&task->lock, "ETAP_THREAD_TASK_NEW");
1096 mach_mutex_init(&task->itk_lock_data, "ETAP_THREAD_TASK_ITK");
1097 queue_init(&task->semaphore_list);
1098
1099 if (p == &proc0) {
1100 kernel_task = task;
1101 task_create_internal(task);
1102 task_init_internal(TASK_NULL, task);
1103 } else {
1104 task_create_internal(task);
1105 }
1106 }
1107
1108 static void
mach_task_fork(void * arg __unused,struct proc * p1,struct proc * p2,int flags __unused)1109 mach_task_fork(void *arg __unused, struct proc *p1, struct proc *p2, int flags __unused)
1110 {
1111 task_t task = p2->p_machdata;
1112 task_t parent_task = p1->p_machdata;
1113
1114 atomic_add_long(&task_uniqueid, 1);
1115 task->itk_uniqueid = task_uniqueid;
1116 task->itk_puniqueid = parent_task->itk_uniqueid;
1117 task_init_internal(parent_task, task);
1118 }
1119
1120 static int
uma_task_init(void * _thread,int a,int b)1121 uma_task_init(void *_thread, int a, int b)
1122 {
1123 /* allocate task substructures */
1124 return (0);
1125 }
1126
1127 static void
uma_task_fini(void * _thread,int a)1128 uma_task_fini(void *_thread, int a)
1129 {
1130 /* deallocate task substructures */
1131 }
1132
1133
1134 static void
task_sysinit(void * arg __unused)1135 task_sysinit(void *arg __unused)
1136 {
1137 task_zone = uma_zcreate("mach_task_zone",
1138 sizeof(struct mach_task),
1139 NULL, NULL, uma_task_init,
1140 uma_task_fini, 1, 0);
1141
1142 EVENTHANDLER_REGISTER(process_init, mach_task_init, NULL, EVENTHANDLER_PRI_ANY);
1143 EVENTHANDLER_REGISTER(process_fork, mach_task_fork, NULL, EVENTHANDLER_PRI_ANY);
1144 }
1145
1146 /* before SI_SUB_INTRINSIC and after SI_SUB_EVENTHANDLER */
1147 SYSINIT(mach_thread, SI_SUB_KLD, SI_ORDER_ANY, task_sysinit, NULL);
1148