xref: /NextBSD/sys/compat/mach/kern/task.c (revision 6283aa8b8e910d10094766cf10d892a509825cc1)
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(&times_info->user_time, &user_time);
881 		    time_value_add(&times_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