|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_FREE_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: * File: kern/task.c
52: * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub,
53: * David Black
54: *
55: * Task management primitives implementation.
56: */
57: /*
58: * Copyright (c) 1993 The University of Utah and
59: * the Computer Systems Laboratory (CSL). All rights reserved.
60: *
61: * Permission to use, copy, modify and distribute this software and its
62: * documentation is hereby granted, provided that both the copyright
63: * notice and this permission notice appear in all copies of the
64: * software, derivative works or modified versions, and any portions
65: * thereof, and that both notices appear in supporting documentation.
66: *
67: * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
68: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
69: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
70: *
71: * CSL requests users of this software to return to [email protected] any
72: * improvements that they make and grant CSL redistribution rights.
73: *
74: */
75:
76: #include <mach_kdb.h>
77: #include <mach_host.h>
78: #include <mach_prof.h>
79: #include <fast_tas.h>
80: #include <task_swapper.h>
81: #include <platforms.h>
82:
83: #include <mach/boolean.h>
84: #include <mach/machine/vm_types.h>
85: #include <mach/vm_param.h>
86: #include <mach/task_info.h>
87: #include <mach/task_special_ports.h>
88: #include <mach/mach_types.h>
89: #include <mach/machine/rpc.h>
90: #include <ipc/ipc_space.h>
91: #include <ipc/ipc_entry.h>
92: #include <kern/mach_param.h>
93: #include <kern/misc_protos.h>
94: #include <kern/task.h>
95: #include <kern/thread.h>
96: #include <kern/zalloc.h>
97: #include <kern/kalloc.h>
98: #include <kern/rtmalloc.h>
99: #include <kern/processor.h>
100: #include <kern/sched_prim.h> /* for thread_wakeup */
101: #include <kern/sf.h>
102: #include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/
103: #include <kern/ipc_tt.h>
104: #include <kern/ledger.h>
105: #include <kern/host.h>
106: #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */
107: #include <kern/profile.h>
108: #include <kern/assert.h>
109: #include <kern/sync_lock.h>
110: #include <kern/sync_sema.h>
111: #if MACH_KDB
112: #include <ddb/db_sym.h>
113: #endif /* MACH_KDB */
114:
115: #if TASK_SWAPPER
116: #include <kern/task_swap.h>
117: #endif /* TASK_SWAPPER */
118:
119: /*
120: * Exported interfaces
121: */
122:
123: #include <mach/task_server.h>
124: #include <mach/mach_host_server.h>
125: #include <mach/host_security_server.h>
126:
127: security_token_t DEFAULT_USER_SECURITY_TOKEN = { {930624, 610120} };
128:
129: task_t kernel_task;
130: zone_t task_zone;
131:
132: /* Forwards */
133:
134: kern_return_t task_hold_locked(
135: task_t task);
136: void task_wait_locked(
137: task_t task);
138: kern_return_t task_release(
139: task_t task);
140: void task_collect_scan(void);
141: void task_act_iterate(
142: task_t task,
143: kern_return_t (*func)(thread_act_t inc));
144: void task_free(
145: task_t task );
146: void task_synchronizer_destroy_all(
147: task_t task);
148: void task_subsystem_destroy_all(
149: task_t task);
150:
151: kern_return_t task_set_ledger(
152: task_t task,
153: ledger_t wired,
154: ledger_t paged);
155:
156: void
157: task_init(void)
158: {
159: task_zone = zinit(
160: sizeof(struct task),
161: TASK_MAX * sizeof(struct task),
162: TASK_CHUNK * sizeof(struct task),
163: "tasks");
164:
165: eml_init();
166:
167: /*
168: * Create the kernel task as the first task.
169: * Task_create_local must assign to kernel_task as a side effect,
170: * for other initialization. (:-()
171: */
172: if (task_create_local(
173: TASK_NULL, FALSE, FALSE, &kernel_task) != KERN_SUCCESS)
174: panic("task_init\n");
175: vm_map_deallocate(kernel_task->map);
176: kernel_task->map = kernel_map;
177:
178: #if MACH_ASSERT
179: if (watchacts & WA_TASK)
180: printf("task_init: kernel_task = %x map=%x\n",
181: kernel_task, kernel_map);
182: #endif /* MACH_ASSERT */
183: }
184:
185: #if MACH_HOST
186: void
187: task_freeze(
188: task_t task)
189: {
190: task_lock(task);
191: /*
192: * If may_assign is false, task is already being assigned,
193: * wait for that to finish.
194: */
195: while (task->may_assign == FALSE) {
196: task->assign_active = TRUE;
197: thread_sleep_mutex((event_t) &task->assign_active,
198: &task->lock, THREAD_INTERRUPTIBLE);
199: task_lock(task);
200: }
201: task->may_assign = FALSE;
202: task_unlock(task);
203:
204: return;
205: }
206:
207: void
208: task_unfreeze(
209: task_t task)
210: {
211: task_lock(task);
212: assert(task->may_assign == FALSE);
213: task->may_assign = TRUE;
214: if (task->assign_active == TRUE) {
215: task->assign_active = FALSE;
216: thread_wakeup((event_t)&task->assign_active);
217: }
218: task_unlock(task);
219:
220: return;
221: }
222: #endif /* MACH_HOST */
223:
224: /*
225: * Create a task running in the kernel address space. It may
226: * have its own map of size mem_size and may have ipc privileges.
227: */
228: kern_return_t
229: kernel_task_create(
230: task_t parent_task,
231: vm_offset_t map_base,
232: vm_size_t map_size,
233: task_t *child_task)
234: {
235: kern_return_t result;
236: task_t new_task;
237: vm_map_t old_map;
238:
239: /*
240: * Create the task.
241: */
242: result = task_create_local(parent_task, FALSE, TRUE, &new_task);
243: if (result != KERN_SUCCESS)
244: return (result);
245:
246: /*
247: * Task_create_local creates the task with a user-space map.
248: * We attempt to replace the map and free it afterwards; else
249: * task_deallocate will free it (can NOT set map to null before
250: * task_deallocate, this impersonates a norma placeholder task).
251: * _Mark the memory as pageable_ -- this is what we
252: * want for images (like servers) loaded into the kernel.
253: */
254: if (map_size == 0) {
255: vm_map_deallocate(new_task->map);
256: new_task->map = kernel_map;
257: *child_task = new_task;
258: } else {
259: old_map = new_task->map;
260: if ((result = kmem_suballoc(kernel_map, &map_base,
261: map_size, TRUE, FALSE,
262: &new_task->map)) != KERN_SUCCESS) {
263: /*
264: * New task created with ref count of 2 -- decrement by
265: * one to force task deletion.
266: */
267: printf("kmem_suballoc(%x,%x,%x,1,0,&new) Fails\n",
268: kernel_map, map_base, map_size);
269: --new_task->ref_count;
270: task_deallocate(new_task);
271: return (result);
272: }
273: vm_map_deallocate(old_map);
274: *child_task = new_task;
275: }
276: return (KERN_SUCCESS);
277: }
278:
279: kern_return_t
280: task_create(
281: task_t parent_task,
282: ledger_port_array_t ledger_ports,
283: mach_msg_type_number_t num_ledger_ports,
284: boolean_t inherit_memory,
285: task_t *child_task) /* OUT */
286: {
287: if (parent_task == TASK_NULL)
288: return(KERN_INVALID_ARGUMENT);
289:
290: return task_create_local(
291: parent_task, inherit_memory, FALSE, child_task);
292: }
293:
294: kern_return_t
295: host_security_create_task_token(
296: host_security_t host_security,
297: task_t parent_task,
298: security_token_t sec_token,
299: ledger_port_array_t ledger_ports,
300: mach_msg_type_number_t num_ledger_ports,
301: boolean_t inherit_memory,
302: task_t *child_task) /* OUT */
303: {
304: kern_return_t result;
305:
306: if (parent_task == TASK_NULL)
307: return(KERN_INVALID_ARGUMENT);
308:
309: if (host_security == HOST_NULL)
310: return(KERN_INVALID_SECURITY);
311:
312: result = task_create_local(
313: parent_task, inherit_memory, FALSE, child_task);
314:
315: if (result != KERN_SUCCESS)
316: return(result);
317: result = host_security_set_task_token(host_security,
318: *child_task,
319: sec_token);
320: return(result);
321: }
322:
323: kern_return_t
324: task_create_local(
325: task_t parent_task,
326: boolean_t inherit_memory,
327: boolean_t kernel_loaded,
328: task_t *child_task) /* OUT */
329: {
330: task_t new_task;
331: processor_set_t pset;
332:
333: new_task = (task_t) zalloc(task_zone);
334:
335: if (new_task == TASK_NULL)
336: return(KERN_RESOURCE_SHORTAGE);
337:
338: /* one ref for just being alive; one for our caller */
339: new_task->ref_count = 2;
340:
341: if (inherit_memory)
342: new_task->map = vm_map_fork(parent_task->map);
343: else
344: new_task->map = vm_map_create(pmap_create(0),
345: round_page(VM_MIN_ADDRESS),
346: trunc_page(VM_MAX_ADDRESS), TRUE);
347:
348: mutex_init(&new_task->lock, ETAP_THREAD_TASK_NEW);
349: queue_init(&new_task->subsystem_list);
350: queue_init(&new_task->thr_acts);
351: mutex_init(&new_task->act_list_lock, ETAP_THREAD_ACT_LIST);
352: new_task->suspend_count = 0;
353: new_task->thr_act_count = 0;
354: new_task->user_stop_count = 0;
355: new_task->active = TRUE;
356: new_task->kernel_loaded = kernel_loaded;
357: new_task->user_data = 0;
358: new_task->faults = 0;
359: new_task->cow_faults = 0;
360: new_task->pageins = 0;
361: new_task->messages_sent = 0;
362: new_task->messages_received = 0;
363: new_task->syscalls_mach = 0;
364: new_task->syscalls_unix=0;
365: new_task->csw=0;
366:
367: #ifdef MACH_BSD
368: new_task->bsd_info = 0;
369: #endif /* MACH_BSD */
370:
371: new_task->res_act_count = 0; /* used unconditionally */
372: #if TASK_SWAPPER
373: new_task->swap_state = TASK_SW_IN;
374: new_task->swap_flags = 0;
375: new_task->swap_ast_waiting = 0;
376: new_task->swap_stamp = sched_tick;
377: new_task->swap_rss = 0;
378: new_task->swap_nswap = 0;
379: #endif /* TASK_SWAPPER */
380:
381: queue_init(&new_task->semaphore_list);
382: queue_init(&new_task->lock_set_list);
383: new_task->semaphores_owned = 0;
384: new_task->lock_sets_owned = 0;
385:
386: #if MACH_HOST
387: new_task->may_assign = TRUE;
388: new_task->assign_active = FALSE;
389: #endif /* MACH_HOST */
390: eml_task_reference(new_task, parent_task);
391:
392: ipc_task_init(new_task, parent_task);
393:
394: new_task->total_user_time.seconds = 0;
395: new_task->total_user_time.microseconds = 0;
396: new_task->total_system_time.seconds = 0;
397: new_task->total_system_time.microseconds = 0;
398:
399: task_prof_init(new_task);
400:
401: if (parent_task != TASK_NULL) {
402: #if MACH_HOST
403: /*
404: * Freeze the parent, so that parent_task->processor_set
405: * cannot change.
406: */
407: task_freeze(parent_task);
408: #endif /* MACH_HOST */
409: pset = parent_task->processor_set;
410: if (!pset->active)
411: pset = &default_pset;
412: new_task->policy = parent_task->policy;
413:
414: /* allocate space for scheduling attributes */
415: new_task->sp_attributes = (sp_attributes_t)kalloc(
416: sched_policy[new_task->policy].sched_attributes_size);
417:
418: if (new_task->sp_attributes == SP_ATTRIBUTES_NULL) {
419: zfree(task_zone, (vm_offset_t) new_task);
420:
421: return(KERN_RESOURCE_SHORTAGE);
422: }
423:
424: /* initialize scheduling attributes */
425: bcopy((char *)parent_task->sp_attributes,
426: (char *)new_task->sp_attributes,
427: sched_policy[new_task->policy].sched_attributes_size);
428:
429: new_task->sec_token = parent_task->sec_token;
430: new_task->wired_ledger_port = ledger_copy(
431: convert_port_to_ledger(parent_task->wired_ledger_port));
432: new_task->paged_ledger_port = ledger_copy(
433: convert_port_to_ledger(parent_task->paged_ledger_port));
434: }
435: else {
436: pset = &default_pset;
437: /*** ??? fix me, so that I am policy independent ***/
438: if (kernel_task == TASK_NULL)
439: new_task->policy = POLICY_FIFO;
440: else
441: new_task->policy = POLICY_TIMESHARE;
442:
443: /* allocate space for scheduling attributes */
444: new_task->sp_attributes =
445: (sp_attributes_t)kalloc(sizeof(mk_sp_attribute_struct_t));
446:
447: if (new_task->sp_attributes == SP_ATTRIBUTES_NULL) {
448: zfree(task_zone, (vm_offset_t) new_task);
449:
450: return(KERN_RESOURCE_SHORTAGE);
451: }
452:
453: /* initialize scheduling attributes */
454: {
455: /*** ??? fix me ***/
456: mk_sp_attributes_t sched_attribute;
457:
458: sched_attribute = (mk_sp_attributes_t)new_task->sp_attributes;
459: if (kernel_task == TASK_NULL) {
460: sched_attribute->policy_id = POLICY_FIFO;
461: sched_attribute->priority = BASEPRI_SYSTEM;
462: sched_attribute->max_priority = BASEPRI_SYSTEM;
463: }
464: else {
465: sched_attribute->policy_id = POLICY_TIMESHARE;
466: sched_attribute->priority = BASEPRI_USER;
467: sched_attribute->max_priority = BASEPRI_USER;
468: }
469:
470: sched_attribute->sched_data = 0;
471: sched_attribute->unconsumed_quantum = 0;
472: }
473:
474: new_task->sec_token = DEFAULT_USER_SECURITY_TOKEN;
475: new_task->wired_ledger_port = ledger_copy(root_wired_ledger);
476: new_task->paged_ledger_port = ledger_copy(root_paged_ledger);
477: }
478: pset_lock(pset);
479: pset_add_task(pset, new_task);
480: pset_unlock(pset);
481: #if MACH_HOST
482: if (parent_task != TASK_NULL)
483: task_unfreeze(parent_task);
484: #endif /* MACH_HOST */
485:
486: #if FAST_TAS
487: if (inherit_memory) {
488: new_task->fast_tas_base = parent_task->fast_tas_base;
489: new_task->fast_tas_end = parent_task->fast_tas_end;
490: } else {
491: new_task->fast_tas_base = (vm_offset_t)0;
492: new_task->fast_tas_end = (vm_offset_t)0;
493: }
494: #endif /* FAST_TAS */
495:
496: ipc_task_enable(new_task);
497:
498: #if TASK_SWAPPER
499: task_swapout_eligible(new_task);
500: #endif /* TASK_SWAPPER */
501:
502: #if MACH_ASSERT
503: if (watchacts & WA_TASK)
504: printf("*** task_create_local(par=%x inh=%x) == 0x%x\n",
505: parent_task, inherit_memory, new_task);
506: #endif /* MACH_ASSERT */
507:
508: *child_task = new_task;
509: return(KERN_SUCCESS);
510: }
511:
512: /*
513: * task_free:
514: *
515: * Called by task_deallocate when the task's reference count drops to zero.
516: * Task is locked.
517: */
518: void
519: task_free(
520: task_t task)
521: {
522: processor_set_t pset;
523:
524: #if MACH_ASSERT
525: assert(task != 0);
526: if (watchacts & (WA_EXIT|WA_TASK))
527: printf("task_free(%x(%d)) map ref %d\n", task, task->ref_count,
528: task->map->ref_count);
529: #endif /* MACH_ASSERT */
530:
531: #if TASK_SWAPPER
532: /* task_terminate guarantees that this task is off the list */
533: assert((task->swap_state & TASK_SW_ELIGIBLE) == 0);
534: #endif /* TASK_SWAPPER */
535:
536: eml_task_deallocate(task);
537:
538: /*
539: * Temporarily restore the reference we dropped above, then
540: * freeze the task so that the task->processor_set field
541: * cannot change. In the !MACH_HOST case, the logic can be
542: * simplified, since the default_pset is the only pset.
543: */
544: ++task->ref_count;
545: task_unlock(task);
546: #if MACH_HOST
547: task_freeze(task);
548: #endif /* MACH_HOST */
549:
550: pset = task->processor_set;
551: pset_lock(pset);
552: task_lock(task);
553: if (--task->ref_count > 0) {
554: /*
555: * A new reference appeared (probably from the pset).
556: * Back out. Must unfreeze inline since we'already
557: * dropped our reference.
558: */
559: #if MACH_HOST
560: assert(task->may_assign == FALSE);
561: task->may_assign = TRUE;
562: if (task->assign_active == TRUE) {
563: task->assign_active = FALSE;
564: thread_wakeup((event_t)&task->assign_active);
565: }
566: #endif /* MACH_HOST */
567: task_unlock(task);
568: pset_unlock(pset);
569: return;
570: }
571: ipc_port_release_send(task->wired_ledger_port);
572: ipc_port_release_send(task->paged_ledger_port);
573: pset_remove_task(pset,task);
574: task_unlock(task);
575: pset_unlock(pset);
576: pset_deallocate(pset);
577: if (task->kernel_loaded)
578: vm_map_remove(kernel_map, task->map->min_offset,
579: task->map->max_offset, VM_MAP_NO_FLAGS);
580: vm_map_deallocate(task->map);
581: is_release(task->itk_space);
582: task_prof_deallocate(task);
583: kfree((vm_offset_t)task->sp_attributes,
584: sched_policy[task->policy].sched_attributes_size);
585: zfree(task_zone, (vm_offset_t) task);
586: }
587:
588: /*
589: * task_act_iterate
590: *
591: * Ignores returncodes from called function.
592: * Already locked: Task
593: */
594: void
595: task_act_iterate(
596: task_t task,
597: kern_return_t (*func)(thread_act_t inc))
598: {
599: thread_act_t inc, ninc;
600: #if MACH_ASSERT
601: int c1 = task->thr_act_count, c2 = 0;
602: if (watchacts & WA_TASK)
603: printf("\ttask_act_iterate(task=%x, func=%x)\n", task, func);
604: #endif /* MACH_ASSERT */
605:
606: /* During iteration, find the next act _before_ calling the function,
607: because the function might remove the act from the task. */
608: for (inc = (thread_act_t)queue_first(&task->thr_acts);
609: inc != (thread_act_t)&task->thr_acts;
610: inc = ninc) {
611: ninc = (thread_act_t)queue_next(&inc->thr_acts);
612: #if MACH_ASSERT
613: c2++;
614: #endif
615: (void) (*func)(inc);
616: }
617:
618: #if MACH_ASSERT
619: if (c1 != c2) {
620: printf("task_act_iterate: thr_act_count %d not %d\n", c1, c2);
621: /* Recount in case above (*func)() changed list */
622: for (c2 = 0, inc = (thread_act_t)queue_first(&task->thr_acts);
623: inc != (thread_act_t)&task->thr_acts; inc = ninc) {
624: ninc = (thread_act_t)queue_next(&inc->thr_acts);
625: c2++;
626: }
627: printf("\t reset thr_act_count to %d\n",
628: task->thr_act_count = c2);
629: }
630: #endif
631: }
632:
633: void
634: task_deallocate(
635: task_t task)
636: {
637: if (task != TASK_NULL) {
638: int c;
639:
640: task_lock(task);
641: c = --task->ref_count;
642: if (c == 0)
643: task_free(task); /* unlocks task */
644: else
645: task_unlock(task);
646: }
647: }
648:
649: void
650: task_reference(
651: task_t task)
652: {
653: if (task != TASK_NULL) {
654: task_lock(task);
655: task->ref_count++;
656: task_unlock(task);
657: }
658: }
659:
660: /*
661: * task_terminate:
662: *
663: * Terminate the specified task. See comments on thread_terminate
664: * (kern/thread.c) about problems with terminating the "current task."
665: */
666:
667: kern_return_t
668: task_terminate(
669: task_t task)
670: {
671: if (task == TASK_NULL)
672: return(KERN_INVALID_ARGUMENT);
673: if (task->bsd_info)
674: return(KERN_FAILURE);
675: return (task_terminate_internal(task));
676: }
677:
678: kern_return_t
679: task_terminate_internal(
680: task_t task)
681: {
682: register thread_t thread, cur_thread;
683: register queue_head_t *list;
684: register task_t cur_task;
685: thread_act_t thr_act, next_thr_act, cur_thr_act;
686: spl_t s;
687:
688: assert(task != kernel_task);
689:
690: list = &task->thr_acts;
691: cur_task = current_task();
692: cur_thr_act = current_thread()->top_act;
693:
694: #if TASK_SWAPPER
695: /*
696: * If task is not resident (swapped out, or being swapped
697: * out), we want to bring it back in (this can block).
698: * NOTE: The only way that this can happen in the current
699: * system is if the task is swapped while it has a thread
700: * in exit(), and the thread does not hit a clean point
701: * to swap itself before getting here.
702: * Terminating other tasks is another way to this code, but
703: * it is not yet fully supported.
704: * The task_swapin is unconditional. It used to be done
705: * only if the task is not resident. Swapping in a
706: * resident task will prevent it from being swapped out
707: * while it terminates.
708: */
709: task_swapin(task, TRUE); /* TRUE means make it unswappable */
710: #endif /* TASK_SWAPPER */
711:
712: /*
713: * Deactivate task so that it can't be terminated again,
714: * and so lengthy operations in progress will abort.
715: *
716: * If the current thread is in this task, remove it from
717: * the task's thread list to keep the thread-termination
718: * loop simple.
719: */
720: if (task == cur_task) {
721: task_lock(task);
722: if (!task->active) {
723: /*
724: * Task is already being terminated.
725: */
726: task_unlock(task);
727: thread_block((void (*)(void)) 0);
728: return(KERN_FAILURE);
729: }
730:
731: task_hold_locked(task);
732:
733: task->active = FALSE;
734:
735: /*
736: * Make sure current thread is not being terminated.
737: */
738: mutex_lock(&task->act_list_lock);
739: cur_thread = act_lock_thread(cur_thr_act);
740: if (!cur_thr_act->active) {
741: act_unlock_thread(cur_thr_act);
742: mutex_unlock(&task->act_list_lock);
743: task_unlock(task);
744: task_release(task);
745: thread_terminate(cur_thr_act);
746: return(KERN_FAILURE);
747: }
748:
749: /*
750: * make sure that this thread is the last one in the list
751: */
752: queue_remove(list, cur_thr_act, thread_act_t, thr_acts);
753: queue_enter(list, cur_thr_act, thread_act_t, thr_acts);
754: act_unlock_thread(cur_thr_act);
755: mutex_unlock(&task->act_list_lock);
756:
757: /*
758: * Shut down this thread's ipc now because it must
759: * be left alone to terminate the task.
760: */
761: ipc_thr_act_disable(cur_thr_act);
762: ipc_thr_act_terminate(cur_thr_act);
763: }
764: else {
765: /*
766: * Lock both current and victim task to check for
767: * potential deadlock.
768: */
769: if (task < cur_task) {
770: task_lock(task);
771: task_lock(cur_task);
772: }
773: else {
774: task_lock(cur_task);
775: task_lock(task);
776: }
777: /*
778: * Check if current thread_act or task is being terminated.
779: */
780: cur_thread = act_lock_thread(cur_thr_act);
781: if ((!cur_task->active) || (!cur_thr_act->active)) {
782: /*
783: * Current task or thread is being terminated.
784: */
785: act_unlock_thread(cur_thr_act);
786: task_unlock(task);
787: task_unlock(cur_task);
788: return(KERN_FAILURE);
789: }
790: act_unlock_thread(cur_thr_act);
791: task_unlock(cur_task);
792:
793: if (!task->active) {
794: /*
795: * Task is already being terminated.
796: */
797: task_unlock(task);
798: thread_block((void (*)(void)) 0);
799: return(KERN_FAILURE);
800: }
801: task_hold_locked(task);
802: task->active = FALSE;
803: }
804:
805: /*
806: * Prevent further execution of the task. ipc_task_disable
807: * prevents further task operations via the task port.
808: * If this is the current task, the current thread will
809: * be left running.
810: */
811: ipc_task_disable(task);
812: task_wait_locked(task);
813:
814: /*
815: * Terminate each thread in the task. Depending on the
816: * state of the thread, this can mean a number of things.
817: * However, we just call thread_terminate(), which
818: * takes care of all cases (see that code for details).
819: *
820: * The task_port is closed down, so no more thread_create
821: * operations can be done. Thread_terminate closes the
822: * thread port for each thread; when that is done, the
823: * thread will eventually disappear. Thus the loop will
824: * terminate.
825: * Need to call thread_block() inside loop because some
826: * other thread (e.g., the reaper) may have to run to get rid
827: * of all references to the thread; it won't vanish from
828: * the task's thread list until the last one is gone.
829: */
830: thr_act = (thread_act_t)queue_first(&task->thr_acts);
831: while ( thr_act!= (thread_act_t)&task->thr_acts) {
832: act_reference(thr_act);
833: next_thr_act = (thread_act_t)queue_next(&thr_act->thr_acts);
834: task_unlock(task);
835: thread_terminate(thr_act);
836: act_deallocate(thr_act);
837: task_lock(task);
838: thr_act = next_thr_act;
839: }
840:
841: task_unlock(task);
842:
843: /*
844: * Destroy all synchronizers owned by the task.
845: */
846: task_synchronizer_destroy_all(task);
847:
848: /*
849: * Shut down IPC.
850: */
851: ipc_task_terminate(task);
852:
853: /*
854: * Deallocate all subsystems owned by the task.
855: */
856: task_subsystem_destroy_all(task);
857:
858: /*
859: * If the current thread is a member of the task
860: * being terminated, then the last reference to
861: * the task will not be dropped until the thread
862: * is finally reaped. To avoid incurring the
863: * expense of removing the address space regions
864: * at reap time, we do it explictly here.
865: */
866: (void) vm_map_remove(task->map,
867: task->map->min_offset,
868: task->map->max_offset, VM_MAP_NO_FLAGS);
869:
870: /*
871: * Deallocate the task's reference to itself.
872: */
873: task_deallocate(task);
874:
875: return(KERN_SUCCESS);
876: }
877:
878: /*
879: * Wait for all threads in task to terminate (except current).
880: * We rely on the fact that all the other threads cache references
881: * to the task's VM map, and when we are alone in the task the
882: * reference count on the map should reach two (one for the task
883: * itself and one for the current act).
884: */
885: void
886: task_halt_wait(
887: register task_t task)
888: {
889: vm_map_t map = task->map;
890:
891: assert(current_thread()->top_act->task == task);
892:
893: /*
894: * Wait for the current thread to become the only thread in
895: * this task.
896: */
897: /*
898: * Now wait for the map users to settle down.
899: */
900: mutex_lock(&map->s_lock);
901: while (map->ref_count > 2) {
902: assert_wait(&map->ref_count, THREAD_UNINT);
903: mutex_unlock(&map->s_lock);
904: thread_block(0);
905: mutex_lock(&map->s_lock);
906: }
907: mutex_unlock(&map->s_lock);
908: }
909:
910: /*
911: * task_halt - Shut the current task down (except for the current thread) in
912: * preparation for dramatic changes to the task (probably exec).
913: * We hold the task, terminate all other threads in the task and
914: * wait for them to terminate, clean up the portspace, and when
915: * all done, let the current thread go.
916: */
917: kern_return_t
918: task_halt(
919: task_t task)
920: {
921: register thread_t thread, cur_thread;
922: register queue_head_t *list;
923: register task_t cur_task;
924: thread_act_t thr_act, cur_thr_act;
925: spl_t s;
926:
927: assert(task != kernel_task);
928:
929: cur_task = current_task();
930: if (task != cur_task) {
931: return(KERN_INVALID_ARGUMENT);
932: }
933:
934: #if TASK_SWAPPER
935: /*
936: * If task is not resident (swapped out, or being swapped
937: * out), we want to bring it back in (this can block).
938: * NOTE: The only way that this can happen in the current
939: * system is if the task is swapped while it has a thread
940: * in exit(), and the thread does not hit a clean point
941: * to swap itself before getting here.
942: * Terminating other tasks is another way to this code, but
943: * it is not yet fully supported.
944: * The task_swapin is unconditional. It used to be done
945: * only if the task is not resident. Swapping in a
946: * resident task will prevent it from being swapped out
947: * while it terminates.
948: */
949: task_swapin(task, TRUE); /* TRUE means make it unswappable */
950: #endif /* TASK_SWAPPER */
951:
952: /*
953: * Deactivate task so that it can't be terminated again,
954: * and so lengthy operations in progress will abort.
955: *
956: * If the current thread is in this task, remove it from
957: * the task's thread list to keep the thread-termination
958: * loop simple.
959: */
960: task_lock(task);
961: if (!task->active) {
962: /*
963: * Task is already being terminated.
964: */
965: task_unlock(task);
966: thread_block((void (*)(void)) 0);
967: return(KERN_FAILURE);
968: }
969: task_hold_locked(task);
970:
971: /*
972: * Make sure current thread is not being terminated.
973: */
974: cur_thr_act = current_thread()->top_act;
975: mutex_lock(&task->act_list_lock);
976: cur_thread = act_lock_thread(cur_thr_act);
977: if (!cur_thr_act->active) {
978: act_unlock_thread(cur_thr_act);
979: mutex_unlock(&task->act_list_lock);
980: task_unlock(task);
981: task_release(task);
982: thread_terminate(cur_thr_act);
983: return(KERN_FAILURE);
984: }
985:
986: task->active = FALSE;
987:
988: /*
989: * Make sure that this thread is the last one in the list
990: */
991: list = &task->thr_acts;
992: queue_remove(list, cur_thr_act, thread_act_t, thr_acts);
993: queue_enter(list, cur_thr_act, thread_act_t, thr_acts);
994: act_unlock_thread(cur_thr_act);
995: mutex_unlock(&task->act_list_lock);
996:
997: /*
998: * Wait for threads to get to clean points.
999: */
1000: task_wait_locked(task);
1001:
1002: /*
1003: * Now that each thread in the task is at a clean point (and the
1004: * task is temporarily marked inactive so no new threads can be
1005: * created), we terminate each of those other threads.
1006: */
1007: for (thr_act = (thread_act_t)queue_first(&task->thr_acts);
1008: thr_act != (thread_act_t)cur_thr_act;
1009: thr_act = (thread_act_t)queue_next(&thr_act->thr_acts)) {
1010: act_reference(thr_act);
1011: task_unlock(task);
1012: thread_terminate(thr_act);
1013: act_deallocate(thr_act);
1014: task_lock(task);
1015: }
1016: task_unlock(task);
1017:
1018: /*
1019: * Wait for the the other threads to exit.
1020: */
1021: task_halt_wait(task);
1022:
1023: /*
1024: * Put it back as active and release the hold on the task
1025: */
1026: task_lock(task);
1027: task->active = TRUE;
1028: task_unlock(task);
1029: task_release(task);
1030: return(KERN_SUCCESS);
1031: }
1032:
1033: /*
1034: * Clean up a task for possible reuse (like after exec).
1035: */
1036: void
1037: task_ipc_cleanup(
1038: task_t task)
1039: {
1040: /*
1041: * Remove all the port rights from the task's IPC port space.
1042: */
1043: ipc_space_clean(task->itk_space);
1044:
1045: /*
1046: * Destroy all synchronizers owned by the task.
1047: */
1048: task_synchronizer_destroy_all(task);
1049:
1050: /*
1051: * Deallocate all subsystems owned by the task.
1052: */
1053: task_subsystem_destroy_all(task);
1054:
1055: }
1056:
1057: /*
1058: * task_hold_locked:
1059: *
1060: * Suspend execution of the specified task.
1061: * This is a recursive-style suspension of the task, a count of
1062: * suspends is maintained.
1063: *
1064: * CONDITIONS: the task is locked.
1065: */
1066: kern_return_t
1067: task_hold_locked(
1068: register task_t task)
1069: {
1070: register queue_head_t *list;
1071: register thread_act_t thr_act, cur_thr_act;
1072:
1073: cur_thr_act = current_act();
1074:
1075: if (!task->active) {
1076: return(KERN_FAILURE);
1077: }
1078:
1079: task->suspend_count++;
1080:
1081: /*
1082: * Iterate through all the thread_act's and hold them.
1083: * Do not hold the current thread_act if it is within the
1084: * task.
1085: */
1086: list = &task->thr_acts;
1087: thr_act = (thread_act_t) queue_first(list);
1088: while (!queue_end(list, (queue_entry_t) thr_act)) {
1089: (void)act_lock_thread(thr_act);
1090: thread_hold(thr_act);
1091: act_unlock_thread(thr_act);
1092: thr_act = (thread_act_t) queue_next(&thr_act->thr_acts);
1093: }
1094: return(KERN_SUCCESS);
1095: }
1096:
1097: kern_return_t
1098: task_release(
1099: register task_t task)
1100: {
1101: register queue_head_t *list;
1102: register thread_act_t thr_act, next;
1103:
1104: task_lock(task);
1105: if (!task->active) {
1106: task_unlock(task);
1107: return(KERN_FAILURE);
1108: }
1109:
1110: task->suspend_count--;
1111:
1112: /*
1113: * Iterate through all the thread_act's and release them.
1114: */
1115: list = &task->thr_acts;
1116: thr_act = (thread_act_t) queue_first(list);
1117: while (!queue_end(list, (queue_entry_t) thr_act)) {
1118: next = (thread_act_t) queue_next(&thr_act->thr_acts);
1119: (void)act_lock_thread(thr_act);
1120: thread_release(thr_act);
1121: act_unlock_thread(thr_act);
1122: thr_act = next;
1123: }
1124: task_unlock(task);
1125: return(KERN_SUCCESS);
1126: }
1127:
1128: kern_return_t
1129: task_threads(
1130: task_t task,
1131: thread_act_array_t *thr_act_list,
1132: mach_msg_type_number_t *count)
1133: {
1134: unsigned int actual; /* this many thr_acts */
1135: thread_act_t thr_act;
1136: thread_act_t *thr_acts;
1137: thread_t thread;
1138: int i, j;
1139: boolean_t rt = FALSE; /* ### This boolean is FALSE, because there
1140: * currently exists no mechanism to determine
1141: * whether or not the reply port is an RT port
1142: */
1143:
1144:
1145: vm_size_t size, size_needed;
1146: vm_offset_t addr;
1147:
1148: if (task == TASK_NULL)
1149: return KERN_INVALID_ARGUMENT;
1150:
1151: size = 0; addr = 0;
1152:
1153: for (;;) {
1154: task_lock(task);
1155: if (!task->active) {
1156: task_unlock(task);
1157: if (size != 0)
1158: KFREE(addr, size, rt);
1159: return KERN_FAILURE;
1160: }
1161:
1162: actual = task->thr_act_count;
1163:
1164: /* do we have the memory we need? */
1165: size_needed = actual * sizeof(mach_port_t);
1166: if (size_needed <= size)
1167: break;
1168:
1169: /* unlock the task and allocate more memory */
1170: task_unlock(task);
1171:
1172: if (size != 0)
1173: KFREE(addr, size, rt);
1174:
1175: assert(size_needed > 0);
1176: size = size_needed;
1177:
1178: addr = KALLOC(size, rt);
1179: if (addr == 0)
1180: return KERN_RESOURCE_SHORTAGE;
1181: }
1182:
1183: /* OK, have memory and the task is locked & active */
1184: thr_acts = (thread_act_t *) addr;
1185:
1186: for (i = j = 0, thr_act = (thread_act_t) queue_first(&task->thr_acts);
1187: i < actual;
1188: i++, thr_act = (thread_act_t) queue_next(&thr_act->thr_acts)) {
1189: act_reference(thr_act);
1190: thr_acts[j++] = thr_act;
1191: }
1192: assert(queue_end(&task->thr_acts, (queue_entry_t) thr_act));
1193: actual = j;
1194:
1195: /* can unlock task now that we've got the thr_act refs */
1196: task_unlock(task);
1197:
1198: if (actual == 0) {
1199: /* no thr_acts, so return null pointer and deallocate memory */
1200:
1201: *thr_act_list = 0;
1202: *count = 0;
1203:
1204: if (size != 0)
1205: KFREE(addr, size, rt);
1206: } else {
1207: /* if we allocated too much, must copy */
1208:
1209: if (size_needed < size) {
1210: vm_offset_t newaddr;
1211:
1212: newaddr = KALLOC(size_needed, rt);
1213: if (newaddr == 0) {
1214: for (i = 0; i < actual; i++)
1215: act_deallocate(thr_acts[i]);
1216: KFREE(addr, size, rt);
1217: return KERN_RESOURCE_SHORTAGE;
1218: }
1219:
1220: bcopy((char *) addr, (char *) newaddr, size_needed);
1221: KFREE(addr, size, rt);
1222: thr_acts = (thread_act_t *) newaddr;
1223: }
1224:
1225: *thr_act_list = thr_acts;
1226: *count = actual;
1227:
1228: /* do the conversion that Mig should handle */
1229:
1230: for (i = 0; i < actual; i++)
1231: ((ipc_port_t *) thr_acts)[i] =
1232: convert_act_to_port(thr_acts[i]);
1233: }
1234:
1235: return KERN_SUCCESS;
1236: }
1237:
1238: kern_return_t
1239: task_suspend(
1240: register task_t task)
1241: {
1242: if (task == TASK_NULL)
1243: return (KERN_INVALID_ARGUMENT);
1244:
1245: task_lock(task);
1246: if (!task->active) {
1247: task_unlock(task);
1248: return (KERN_FAILURE);
1249: }
1250: if ((task->user_stop_count)++ > 0) {
1251: /*
1252: * If the stop count was positive, the task is
1253: * already stopped and we can exit.
1254: */
1255: task_unlock(task);
1256: return (KERN_SUCCESS);
1257: }
1258:
1259: /*
1260: * Hold all of the threads in the task, and wait for
1261: * them to stop. If the current thread is within
1262: * this task, hold it separately so that all of the
1263: * other threads can stop first.
1264: */
1265: if (task_hold_locked(task) != KERN_SUCCESS) {
1266: task_unlock(task);
1267: return (KERN_FAILURE);
1268: }
1269:
1270: task_wait_locked(task);
1271: task_unlock(task);
1272: return (KERN_SUCCESS);
1273: }
1274:
1275: /*
1276: * Wait for all threads in task to stop. Called with task locked.
1277: */
1278: void
1279: task_wait_locked(
1280: register task_t task)
1281: {
1282: register queue_head_t *list;
1283: register thread_act_t thr_act, refd_thr_act;
1284: register thread_t thread, cur_thr;
1285:
1286: cur_thr = current_thread();
1287: /*
1288: * Iterate through all the thread's and wait for them to
1289: * stop. Do not wait for the current thread if it is within
1290: * the task.
1291: */
1292: list = &task->thr_acts;
1293: refd_thr_act = THR_ACT_NULL;
1294: for (;;) {
1295: thr_act = (thread_act_t) queue_first(list);
1296: while (!queue_end(list, (queue_entry_t) thr_act)) {
1297: thread = act_lock_thread(thr_act);
1298: if (refd_thr_act != THR_ACT_NULL) {
1299: act_deallocate(refd_thr_act);
1300: refd_thr_act = THR_ACT_NULL;
1301: }
1302: if (thread != THREAD_NULL &&
1303: thr_act == thread->top_act &&
1304: thread != cur_thr) {
1305: refd_thr_act = thr_act;
1306: act_locked_act_reference(thr_act);
1307: act_unlock_thread(thr_act);
1308: task_unlock(task);
1309: (void)thread_wait(thread);
1310: task_lock(task);
1311: thread = act_lock_thread(thr_act);
1312: if (!thr_act->active) {
1313: act_unlock_thread(thr_act);
1314: /* drop reference to act immediately */
1315: task_unlock(task);
1316: act_deallocate(refd_thr_act);
1317: refd_thr_act = THR_ACT_NULL;
1318: task_lock(task);
1319: break;
1320: }
1321: }
1322: act_unlock_thread(thr_act);
1323: thr_act = (thread_act_t)queue_next(&thr_act->thr_acts);
1324: }
1325: if (queue_end(list, (queue_entry_t)thr_act))
1326: break;
1327: }
1328: if (refd_thr_act != THR_ACT_NULL) {
1329: act_deallocate(refd_thr_act);
1330: refd_thr_act = THR_ACT_NULL;
1331: }
1332: }
1333:
1334: kern_return_t
1335: task_resume(register task_t task)
1336: {
1337: register boolean_t release;
1338:
1339: if (task == TASK_NULL)
1340: return(KERN_INVALID_ARGUMENT);
1341:
1342: release = FALSE;
1343: task_lock(task);
1344: if (!task->active) {
1345: task_unlock(task);
1346: return(KERN_FAILURE);
1347: }
1348: if (task->user_stop_count > 0) {
1349: if (--(task->user_stop_count) == 0)
1350: release = TRUE;
1351: }
1352: else {
1353: task_unlock(task);
1354: return(KERN_FAILURE);
1355: }
1356: task_unlock(task);
1357:
1358: /*
1359: * Release the task if necessary.
1360: */
1361: if (release)
1362: return(task_release(task));
1363:
1364: return(KERN_SUCCESS);
1365: }
1366:
1367: kern_return_t
1368: host_security_set_task_token(
1369: host_security_t host_security,
1370: task_t task,
1371: security_token_t sec_token)
1372: {
1373: if (task == TASK_NULL)
1374: return(KERN_INVALID_ARGUMENT);
1375:
1376: if (host_security == HOST_NULL)
1377: return(KERN_INVALID_SECURITY);
1378:
1379: task_lock(task);
1380: task->sec_token = sec_token;
1381: task_unlock(task);
1382:
1383: return(KERN_SUCCESS);
1384: }
1385:
1386: /*
1387: * Utility routine to set a ledger
1388: */
1389: kern_return_t
1390: task_set_ledger(
1391: task_t task,
1392: ledger_t wired,
1393: ledger_t paged)
1394: {
1395: if (task == TASK_NULL)
1396: return(KERN_INVALID_ARGUMENT);
1397:
1398: task_lock(task);
1399: if (wired) {
1400: ipc_port_release_send(task->wired_ledger_port);
1401: task->wired_ledger_port = ledger_copy(wired);
1402: }
1403: if (paged) {
1404: ipc_port_release_send(task->paged_ledger_port);
1405: task->paged_ledger_port = ledger_copy(paged);
1406: }
1407: task_unlock(task);
1408:
1409: return(KERN_SUCCESS);
1410: }
1411:
1412: /*
1413: * This routine was added, pretty much exclusively, for registering the
1414: * RPC glue vector for in-kernel short circuited tasks. Rather than
1415: * removing it completely, I have only disabled that feature (which was
1416: * the only feature at the time). It just appears that we are going to
1417: * want to add some user data to tasks in the future (i.e. bsd info,
1418: * task names, etc...), so I left it in the formal task interface.
1419: */
1420: kern_return_t
1421: task_set_info(
1422: task_t task,
1423: task_flavor_t flavor,
1424: task_info_t task_info_in, /* pointer to IN array */
1425: mach_msg_type_number_t task_info_count)
1426: {
1427: vm_map_t map;
1428:
1429: if (task == TASK_NULL)
1430: return(KERN_INVALID_ARGUMENT);
1431:
1432: switch (flavor) {
1433: default:
1434: return (KERN_INVALID_ARGUMENT);
1435: }
1436: return (KERN_SUCCESS);
1437: }
1438:
1439: kern_return_t
1440: task_info(
1441: task_t task,
1442: task_flavor_t flavor,
1443: task_info_t task_info_out,
1444: mach_msg_type_number_t *task_info_count)
1445: {
1446: thread_t thread;
1447: vm_map_t map;
1448:
1449: if (task == TASK_NULL)
1450: return(KERN_INVALID_ARGUMENT);
1451:
1452: switch (flavor) {
1453:
1454: case TASK_BASIC_INFO:
1455: {
1456: register task_basic_info_t basic_info;
1457:
1458: if (*task_info_count < TASK_BASIC_INFO_COUNT) {
1459: return(KERN_INVALID_ARGUMENT);
1460: }
1461:
1462: basic_info = (task_basic_info_t) task_info_out;
1463:
1464: map = (task == kernel_task) ? kernel_map : task->map;
1465:
1466: basic_info->virtual_size = map->size;
1467: basic_info->resident_size = pmap_resident_count(map->pmap)
1468: * PAGE_SIZE;
1469:
1470: task_lock(task);
1471: basic_info->policy = task->policy;
1472: basic_info->suspend_count = task->user_stop_count;
1473: basic_info->user_time.seconds
1474: = task->total_user_time.seconds;
1475: basic_info->user_time.microseconds
1476: = task->total_user_time.microseconds;
1477: basic_info->system_time.seconds
1478: = task->total_system_time.seconds;
1479: basic_info->system_time.microseconds
1480: = task->total_system_time.microseconds;
1481: task_unlock(task);
1482:
1483: *task_info_count = TASK_BASIC_INFO_COUNT;
1484: break;
1485: }
1486:
1487: case TASK_THREAD_TIMES_INFO:
1488: {
1489: register task_thread_times_info_t times_info;
1490: register thread_t thread;
1491: register thread_act_t thr_act;
1492:
1493: if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
1494: return (KERN_INVALID_ARGUMENT);
1495: }
1496:
1497: times_info = (task_thread_times_info_t) task_info_out;
1498: times_info->user_time.seconds = 0;
1499: times_info->user_time.microseconds = 0;
1500: times_info->system_time.seconds = 0;
1501: times_info->system_time.microseconds = 0;
1502:
1503: task_lock(task);
1504: queue_iterate(&task->thr_acts, thr_act,
1505: thread_act_t, thr_acts)
1506: {
1507: time_value_t user_time, system_time;
1508: spl_t s;
1509:
1510: thread = act_lock_thread(thr_act);
1511:
1512: /* Skip empty threads and threads that have migrated
1513: * into this task:
1514: */
1515: if (thr_act->pool_port) {
1516: act_unlock_thread(thr_act);
1517: continue;
1518: }
1519: assert(thread); /* Must have thread, if no thread_pool*/
1520: s = splsched();
1521: thread_lock(thread);
1522:
1523: thread_read_times(thread, &user_time, &system_time);
1524:
1525: thread_unlock(thread);
1526: splx(s);
1527: act_unlock_thread(thr_act);
1528:
1529: time_value_add(×_info->user_time, &user_time);
1530: time_value_add(×_info->system_time, &system_time);
1531: }
1532: task_unlock(task);
1533:
1534: *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
1535: break;
1536: }
1537:
1538: case TASK_SCHED_FIFO_INFO:
1539: {
1540: register policy_fifo_base_t fifo_base;
1541:
1542: if (*task_info_count < POLICY_FIFO_BASE_COUNT)
1543: return(KERN_INVALID_ARGUMENT);
1544:
1545: fifo_base = (policy_fifo_base_t) task_info_out;
1546:
1547: task_lock(task);
1548: if (task->policy != POLICY_FIFO) {
1549: task_unlock(task);
1550: return(KERN_INVALID_POLICY);
1551: }
1552: /*** ??? fix me ***/
1553: assert(task->sp_attributes != SP_ATTRIBUTES_NULL);
1554: fifo_base->base_priority =
1555: ((mk_sp_attributes_t)task->sp_attributes)->priority;
1556: task_unlock(task);
1557:
1558: *task_info_count = POLICY_FIFO_BASE_COUNT;
1559: break;
1560: }
1561:
1562: case TASK_SCHED_RR_INFO:
1563: {
1564: register policy_rr_base_t rr_base;
1565:
1566: if (*task_info_count < POLICY_RR_BASE_COUNT)
1567: return(KERN_INVALID_ARGUMENT);
1568:
1569: rr_base = (policy_rr_base_t) task_info_out;
1570:
1571: task_lock(task);
1572: if (task->policy != POLICY_RR) {
1573: task_unlock(task);
1574: return(KERN_INVALID_POLICY);
1575: }
1576: /*** ??? fix me ***/
1577: assert(task->sp_attributes != SP_ATTRIBUTES_NULL);
1578: rr_base->base_priority =
1579: ((mk_sp_attributes_t)task->sp_attributes)->priority;
1580: rr_base->quantum =
1581: (((mk_sp_attributes_t)task->sp_attributes)->sched_data
1582: * tick) / 1000;
1583: task_unlock(task);
1584:
1585: *task_info_count = POLICY_RR_BASE_COUNT;
1586: break;
1587: }
1588:
1589: case TASK_SCHED_TIMESHARE_INFO:
1590: {
1591: register policy_timeshare_base_t ts_base;
1592:
1593: if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT)
1594: return(KERN_INVALID_ARGUMENT);
1595:
1596: ts_base = (policy_timeshare_base_t) task_info_out;
1597:
1598: task_lock(task);
1599: if (task->policy != POLICY_TIMESHARE) {
1600: task_unlock(task);
1601: return(KERN_INVALID_POLICY);
1602: }
1603: /*** ??? fix me ***/
1604: assert(task->sp_attributes != SP_ATTRIBUTES_NULL);
1605: ts_base->base_priority =
1606: ((mk_sp_attributes_t)task->sp_attributes)->priority;
1607: task_unlock(task);
1608:
1609: *task_info_count = POLICY_TIMESHARE_BASE_COUNT;
1610: break;
1611: }
1612:
1613: case TASK_SECURITY_TOKEN:
1614: {
1615: register security_token_t *sec_token_p;
1616:
1617: if (*task_info_count < TASK_SECURITY_TOKEN_COUNT) {
1618: return(KERN_INVALID_ARGUMENT);
1619: }
1620:
1621: sec_token_p = (security_token_t *) task_info_out;
1622:
1623: task_lock(task);
1624: *sec_token_p = task->sec_token;
1625: task_unlock(task);
1626:
1627: *task_info_count = TASK_SECURITY_TOKEN_COUNT;
1628: break;
1629: }
1630:
1631: case TASK_SCHED_INFO:
1632: {
1633: int count = sched_policy[task->policy].sched_attributes_size;
1634:
1635: if (*task_info_count < (((count-1)/sizeof(int)) + 1))
1636: return(KERN_INVALID_ARGUMENT);
1637:
1638: task_lock(task);
1639:
1640: bcopy((char *)task->sp_attributes,
1641: (char *)task_info_out,
1642: count);
1643:
1644: task_unlock(task);
1645:
1646: *task_info_count = count;
1647: break;
1648: }
1649:
1650: case TASK_EVENTS_INFO:
1651: {
1652: register task_events_info_t events_info;
1653:
1654: if (*task_info_count < TASK_EVENTS_INFO_COUNT) {
1655: return(KERN_INVALID_ARGUMENT);
1656: }
1657:
1658: events_info = (task_events_info_t) task_info_out;
1659:
1660: task_lock(task);
1661: events_info->faults = task->faults;
1662: events_info->pageins = task->pageins;
1663: events_info->cow_faults = task->cow_faults;
1664: events_info->messages_sent = task->messages_sent;
1665: events_info->messages_received = task->messages_received;
1666: events_info->syscalls_mach = task->syscalls_mach;
1667: events_info->syscalls_unix = task->syscalls_unix;
1668: events_info->csw = task->csw;
1669: task_unlock(task);
1670:
1671: *task_info_count = TASK_EVENTS_INFO_COUNT;
1672: break;
1673: }
1674:
1675: default:
1676: return (KERN_INVALID_ARGUMENT);
1677: }
1678:
1679: return(KERN_SUCCESS);
1680: }
1681:
1682: #if MACH_HOST
1683:
1684: /*
1685: * task_assign:
1686: *
1687: * Change the assigned processor set for the task
1688: */
1689: kern_return_t
1690: task_assign(
1691: task_t task,
1692: processor_set_t new_pset,
1693: boolean_t assign_threads)
1694: {
1695: kern_return_t ret = KERN_SUCCESS;
1696: register thread_t thread, prev_thread;
1697: register queue_head_t *list;
1698: register processor_set_t pset;
1699: int max_priority;
1700:
1701: if (task == TASK_NULL || new_pset == PROCESSOR_SET_NULL) {
1702: return(KERN_INVALID_ARGUMENT);
1703: }
1704:
1705: task_lock(task);
1706:
1707: /*
1708: * If may_assign is false, task is already being assigned,
1709: * wait for that to finish.
1710: */
1711: while (task->may_assign == FALSE) {
1712: task->assign_active = TRUE;
1713: assert_wait((event_t)&task->assign_active, THREAD_ABORTSAFE);
1714: task_unlock(task);
1715: thread_block((void (*)(void)) 0);
1716: task_lock(task);
1717: }
1718:
1719: /*
1720: * Do assignment. If new pset is dead, redirect to default.
1721: */
1722: pset = task->processor_set;
1723: pset_lock(pset);
1724: pset_remove_task(pset,task);
1725: pset_unlock(pset);
1726: pset_deallocate(pset);
1727:
1728: pset_lock(new_pset);
1729: if (!new_pset->active) {
1730: pset_unlock(new_pset);
1731: new_pset = &default_pset;
1732: pset_lock(new_pset);
1733: }
1734:
1735: /*
1736: * Reset policy and priorities if needed.
1737: *
1738: * There are three rules for tasks under assignment:
1739: *
1740: * (1) If the new pset has the old policy enabled, keep the
1741: * old policy. Otherwise, use the default policy for the pset.
1742: * (2) The new limits will be the pset limits for the new policy.
1743: * (3) The new base will be the same as the old base unless either
1744: * (a) the new policy changed to the pset default policy;
1745: * in this case, the new base is the default policy
1746: * base,
1747: * or
1748: * (b) the new limits are different from the old limits;
1749: * in this case, the new base is the new limits.
1750: */
1751: max_priority = pset_max_priority(new_pset, task->policy);
1752: if ((task->policy & new_pset->policies) == 0) {
1753: task->policy = new_pset->policy_default;
1754: task->sched_data = pset_sched_data(new_pset, task->policy);
1755: task->priority = pset_base_priority(new_pset, task->policy);
1756: max_priority = pset_max_priority(new_pset, task->policy);
1757: }
1758: else if (task->max_priority != max_priority) {
1759: task->priority = max_priority;
1760: }
1761:
1762: task->max_priority = max_priority;
1763:
1764: pset_add_task(new_pset,task);
1765: pset_unlock(new_pset);
1766:
1767: if (assign_threads == FALSE) {
1768: task_unlock(task);
1769: return(KERN_SUCCESS);
1770: }
1771:
1772: /*
1773: * Now freeze this assignment while we get the threads
1774: * to catch up to it.
1775: */
1776: task->may_assign = FALSE;
1777:
1778: /*
1779: * If current thread is in task, freeze its assignment.
1780: */
1781: if (current_act()->task == task) {
1782: task_unlock(task);
1783: thread_freeze(current_thread());
1784: task_lock(task);
1785: }
1786:
1787: /*
1788: * Iterate down the thread list reassigning all the threads.
1789: * ("Base" threads only, please; psets belong to them)
1790: * New threads pick up task's new processor set automatically.
1791: * Do current thread last because new pset may be empty.
1792: */
1793: { thread_act_t thr_act;
1794: int i;
1795:
1796: prev_thread = THREAD_NULL;
1797: for (i = 0, thr_act = (thread_act_t) queue_first(&task->thr_acts);
1798: i < task->thr_act_count;
1799: i++, thr_act = (thread_act_t)queue_next(&thr_act->thr_acts)) {
1800:
1801: thread = act_lock_thread(thr_act);
1802: if (thr_act->pool_port) {
1803: act_unlock_thread(thr_act);
1804: continue;
1805: }
1806: if (!(task->active)) {
1807: ret = KERN_FAILURE;
1808: act_unlock_thread(thr_act);
1809: break;
1810: }
1811: assert(thread);
1812: if (thread == current_thread())
1813: act_unlock_thread(thr_act);
1814: else {
1815: thread_reference(thread);
1816: task_unlock(task);
1817: if (prev_thread != THREAD_NULL)
1818: thread_deallocate(prev_thread); /* may block */
1819: assert(thread->top_act);
1820: assert(thread->top_act->thread == thread);
1821: /*
1822: * Inline thread_assign() here to avoid silly double
1823: * conversion.
1824: */
1825: thread_freeze(thread);
1826: thread_doassign(thread, new_pset, TRUE);
1827: /*
1828: * All thread-related locks released at this point.
1829: */
1830: prev_thread = thread;
1831: task_lock(task);
1832: }
1833: }
1834: assert(queue_end(&task->thr_acts, (queue_entry_t)thr_act));
1835: }
1836:
1837: /*
1838: * Done, wakeup anyone waiting for us.
1839: */
1840: task->may_assign = TRUE;
1841: if (task->assign_active) {
1842: task->assign_active = FALSE;
1843: thread_wakeup((event_t)&task->assign_active);
1844: }
1845: task_unlock(task);
1846: if (prev_thread != THREAD_NULL)
1847: thread_deallocate(prev_thread); /* may block */
1848:
1849: /*
1850: * Finish assignment of current thread.
1851: */
1852: if (current_act()->task == task) {
1853: thread = act_lock_thread(current_act());
1854: thread_doassign(thread, new_pset, TRUE);
1855: /*
1856: * All thread-related locks released at this point.
1857: */
1858: }
1859:
1860: return(ret);
1861: }
1862: #else /* MACH_HOST */
1863: /*
1864: * task_assign:
1865: *
1866: * Change the assigned processor set for the task
1867: */
1868: kern_return_t
1869: task_assign(
1870: task_t task,
1871: processor_set_t new_pset,
1872: boolean_t assign_threads)
1873: {
1874: #ifdef lint
1875: task++; new_pset++; assign_threads++;
1876: #endif /* lint */
1877: return(KERN_FAILURE);
1878: }
1879: #endif /* MACH_HOST */
1880:
1881:
1882: /*
1883: * task_assign_default:
1884: *
1885: * Version of task_assign to assign to default processor set.
1886: */
1887: kern_return_t
1888: task_assign_default(
1889: task_t task,
1890: boolean_t assign_threads)
1891: {
1892: return (task_assign(task, &default_pset, assign_threads));
1893: }
1894:
1895: /*
1896: * task_get_assignment
1897: *
1898: * Return name of processor set that task is assigned to.
1899: */
1900: kern_return_t
1901: task_get_assignment(
1902: task_t task,
1903: processor_set_t *pset)
1904: {
1905: if (!task->active)
1906: return(KERN_FAILURE);
1907:
1908: *pset = task->processor_set;
1909: pset_reference(*pset);
1910: return(KERN_SUCCESS);
1911: }
1912:
1913:
1914: /*
1915: * task_policy
1916: *
1917: * Set scheduling policy and parameters, both base and limit, for
1918: * the given task. Policy must be a policy which is enabled for the
1919: * processor set. Change contained threads if requested.
1920: */
1921: kern_return_t
1922: task_policy(
1923: task_t task,
1924: policy_t policy_id,
1925: policy_base_t base,
1926: mach_msg_type_number_t count,
1927: boolean_t set_limit,
1928: boolean_t change)
1929: {
1930: policy_limit_t limit;
1931: int limcount;
1932: processor_set_t pset;
1933: kern_return_t result = KERN_SUCCESS;
1934: sched_policy_t *policy;
1935:
1936: if ( task == TASK_NULL ||
1937: (pset = task->processor_set) == PROCESSOR_SET_NULL )
1938: return(KERN_INVALID_ARGUMENT);
1939:
1940: if (invalid_policy(policy_id) || (pset->policies & policy_id) == 0)
1941: return(KERN_INVALID_POLICY);
1942:
1943: /* call policy-specific routine */
1944: policy = &sched_policy[policy_id];
1945: result = policy->sp_ops.
1946: sp_task_policy(policy, task, policy_id,
1947: base, count, set_limit, change, &limit, &limcount);
1948:
1949: if (result != KERN_SUCCESS)
1950: return(result);
1951:
1952: result = task_set_policy(task, pset, policy_id,
1953: base, count, limit, limcount, change);
1954:
1955: return(result);
1956: }
1957:
1958: /*
1959: * task_set_policy
1960: *
1961: * Set scheduling policy and parameters, both base and limit, for
1962: * the given task. Policy can be any policy implemented by the
1963: * processor set, whether enabled or not. Change contained threads
1964: * if requested.
1965: */
1966: kern_return_t
1967: task_set_policy(
1968: task_t task,
1969: processor_set_t pset,
1970: policy_t policy_id,
1971: policy_base_t base,
1972: mach_msg_type_number_t base_count,
1973: policy_limit_t limit,
1974: mach_msg_type_number_t limit_count,
1975: boolean_t change)
1976: {
1977: kern_return_t result = KERN_SUCCESS;
1978: sched_policy_t *policy;
1979:
1980: if (task == TASK_NULL || pset == PROCESSOR_SET_NULL)
1981: return(KERN_INVALID_ARGUMENT);
1982:
1983: if (pset != task->processor_set)
1984: return(KERN_FAILURE);
1985:
1986: task_lock(task);
1987:
1988: /* call policy-specific routine */
1989: policy = &sched_policy[policy_id];
1990: result = policy->sp_ops.
1991: sp_task_set_policy(policy, task, pset, policy_id,
1992: base, base_count, limit, limit_count, change);
1993:
1994: if (result != KERN_SUCCESS) {
1995: task_unlock(task);
1996: return(result);
1997: }
1998:
1999: if (change) {
2000: register thread_act_t thr_act;
2001: register queue_head_t *list;
2002:
2003: list = &task->thr_acts;
2004: thr_act = (thread_act_t) queue_first(list);
2005: while (!queue_end(list, (queue_entry_t) thr_act)) {
2006: /*** ??? fix to call policy-dependent routine ***/
2007: thread_set_policy(thr_act, pset, policy_id,
2008: base, base_count,
2009: limit, limit_count);
2010: thr_act = (thread_act_t)queue_next(&thr_act->thr_acts);
2011: }
2012: }
2013:
2014: task_unlock(task);
2015: return(result);
2016: }
2017:
2018: /*
2019: * task_set_sched
2020: *
2021: * Set scheduling policy and parameters for the given task.
2022: * Policy must be a policy which is enabled for the
2023: * processor set. Change contained threads if requested.
2024: * (This should replace `task_policy()' with the addition
2025: * of the MK Scheduling Framework to the kernel.)
2026: */
2027: kern_return_t
2028: task_set_sched(
2029: task_t task,
2030: policy_t policy_id,
2031: sched_attr_t sched_attr,
2032: mach_msg_type_number_t sched_attrCnt,
2033: boolean_t set_limit,
2034: boolean_t change)
2035: {
2036: processor_set_t pset;
2037: sched_policy_t *policy;
2038:
2039: if ( task == TASK_NULL ||
2040: (pset = task->processor_set) == PROCESSOR_SET_NULL )
2041: return(KERN_INVALID_ARGUMENT);
2042:
2043: if (invalid_policy(policy_id) || (pset->policies & policy_id) == 0)
2044: return(KERN_INVALID_POLICY);
2045:
2046: /* call policy-specific routine */
2047: policy = &sched_policy[policy_id];
2048: return (policy->sp_ops.sp_task_set_sched(policy, task, policy_id,
2049: sched_attr, sched_attrCnt, set_limit, change));
2050: }
2051:
2052:
2053: /*
2054: * task_get_sched
2055: *
2056: * Get scheduling policy and parameters for the given task.
2057: * (This was added as part of the MK Scheduling Framework.)
2058: */
2059: kern_return_t
2060: task_get_sched(
2061: task_t task,
2062: policy_t policy_id,
2063: sched_attr_t sched_attr,
2064: mach_msg_type_number_t sched_attrCnt,
2065: int sched_attr_size)
2066: {
2067: processor_set_t pset;
2068: sched_policy_t *policy;
2069:
2070: if ( task == TASK_NULL ||
2071: (pset = task->processor_set) == PROCESSOR_SET_NULL )
2072: return(KERN_INVALID_ARGUMENT);
2073:
2074: /* call policy-specific routine */
2075: policy = &sched_policy[task->policy];
2076: return (policy->sp_ops.sp_task_get_sched(policy, task, policy_id,
2077: sched_attr, sched_attrCnt, sched_attr_size));
2078: }
2079:
2080:
2081: /*
2082: * task_collect_scan:
2083: *
2084: * Attempt to free resources owned by tasks.
2085: */
2086:
2087: void
2088: task_collect_scan(void)
2089: {
2090: register task_t task, prev_task;
2091: processor_set_t pset, prev_pset;
2092:
2093: prev_task = TASK_NULL;
2094: prev_pset = PROCESSOR_SET_NULL;
2095:
2096: mutex_lock(&all_psets_lock);
2097: pset = (processor_set_t) queue_first(&all_psets);
2098: while (!queue_end(&all_psets, (queue_entry_t) pset)) {
2099: pset_lock(pset);
2100: task = (task_t) queue_first(&pset->tasks);
2101: while (!queue_end(&pset->tasks, (queue_entry_t) task)) {
2102: task_reference(task);
2103: pset->ref_count++;
2104: pset_unlock(pset);
2105: mutex_unlock(&all_psets_lock);
2106:
2107: pmap_collect(task->map->pmap);
2108:
2109: if (prev_task != TASK_NULL)
2110: task_deallocate(prev_task);
2111: prev_task = task;
2112:
2113: if (prev_pset != PROCESSOR_SET_NULL)
2114: pset_deallocate(prev_pset);
2115: prev_pset = pset;
2116:
2117: mutex_lock(&all_psets_lock);
2118: pset_lock(pset);
2119: task = (task_t) queue_next(&task->pset_tasks);
2120: }
2121: pset_unlock(pset);
2122: pset = (processor_set_t) queue_next(&pset->all_psets);
2123: }
2124: mutex_unlock(&all_psets_lock);
2125:
2126: if (prev_task != TASK_NULL)
2127: task_deallocate(prev_task);
2128: if (prev_pset != PROCESSOR_SET_NULL)
2129: pset_deallocate(prev_pset);
2130: }
2131:
2132: boolean_t task_collect_allowed = TRUE;
2133: unsigned task_collect_last_tick = 0;
2134: unsigned task_collect_max_rate = 0; /* in ticks */
2135:
2136: /*
2137: * consider_task_collect:
2138: *
2139: * Called by the pageout daemon when the system needs more free pages.
2140: */
2141:
2142: void
2143: consider_task_collect(void)
2144: {
2145: /*
2146: * By default, don't attempt task collection more frequently
2147: * than once a second (a scheduler tick).
2148: */
2149:
2150: if (task_collect_max_rate == 0)
2151: task_collect_max_rate = 2; /* sched_tick is a 1 second resolution 2 here insures at least 1 second interval */
2152:
2153: if (task_collect_allowed &&
2154: (sched_tick > (task_collect_last_tick + task_collect_max_rate))) {
2155: task_collect_last_tick = sched_tick;
2156: task_collect_scan();
2157: }
2158: }
2159:
2160: kern_return_t
2161: task_set_ras_pc(
2162: task_t task,
2163: vm_offset_t pc,
2164: vm_offset_t endpc)
2165: {
2166: #if FAST_TAS
2167: extern int fast_tas_debug;
2168:
2169: if (fast_tas_debug) {
2170: printf("task 0x%x: setting fast_tas to [0x%x, 0x%x]\n",
2171: task, pc, endpc);
2172: }
2173: task_lock(task);
2174: task->fast_tas_base = pc;
2175: task->fast_tas_end = endpc;
2176: task_unlock(task);
2177: return KERN_SUCCESS;
2178:
2179: #else /* FAST_TAS */
2180: #ifdef lint
2181: task++;
2182: pc++;
2183: endpc++;
2184: #endif /* lint */
2185:
2186: return KERN_FAILURE;
2187:
2188: #endif /* FAST_TAS */
2189: }
2190:
2191: void
2192: task_synchronizer_destroy_all(task_t task)
2193: {
2194: semaphore_t semaphore;
2195: lock_set_t lock_set;
2196:
2197: /*
2198: * Destroy owned semaphores
2199: */
2200:
2201: while (!queue_empty(&task->semaphore_list)) {
2202: semaphore = (semaphore_t) queue_first(&task->semaphore_list);
2203: (void) semaphore_destroy(task, semaphore);
2204: }
2205:
2206: /*
2207: * Destroy owned lock sets
2208: */
2209:
2210: while (!queue_empty(&task->lock_set_list)) {
2211: lock_set = (lock_set_t) queue_first(&task->lock_set_list);
2212: (void) lock_set_destroy(task, lock_set);
2213: }
2214: }
2215:
2216: void
2217: task_subsystem_destroy_all(task_t task)
2218: {
2219: subsystem_t subsystem;
2220:
2221: /*
2222: * Destroy owned subsystems
2223: */
2224:
2225: while (!queue_empty(&task->subsystem_list)) {
2226: subsystem = (subsystem_t) queue_first(&task->subsystem_list);
2227: subsystem_deallocate(subsystem);
2228: }
2229: }
2230:
2231: /*
2232: * task_set_port_space:
2233: *
2234: * Set port name space of task to specified size.
2235: */
2236:
2237: kern_return_t
2238: task_set_port_space(
2239: task_t task,
2240: int table_entries)
2241: {
2242: kern_return_t kr;
2243:
2244: is_write_lock(task->itk_space);
2245: kr = ipc_entry_grow_table(task->itk_space, table_entries);
2246: if (kr == KERN_SUCCESS)
2247: is_write_unlock(task->itk_space);
2248: return kr;
2249: }
2250:
2251: /*
2252: * We need to export some functions to other components that
2253: * are currently implemented in macros within the osfmk
2254: * component. Just export them as functions of the same name.
2255: */
2256: boolean_t is_kerneltask(task_t t)
2257: {
2258: if (t == kernel_task)
2259: return(TRUE);
2260: else
2261: return((t->kernel_loaded));
2262: }
2263:
2264: #undef current_task
2265: task_t current_task()
2266: {
2267: return (current_task_fast());
2268: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.