|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1993-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: #include <mach_host.h>
59: #include <norma_task.h>
60:
61: #include <mach/machine/vm_types.h>
62: #include <mach/vm_param.h>
63: #include <mach/task_info.h>
64: #include <mach/task_special_ports.h>
65: #include <ipc/ipc_space.h>
66: #include <kern/mach_param.h>
67: #include <kern/task.h>
68: #include <kern/thread.h>
69: #include <kern/zalloc.h>
70: #include <kern/kalloc.h>
71: #include <kern/processor.h>
72: #include <kern/sched_prim.h> /* for thread_wakeup */
73: #include <kern/ipc_tt.h>
74: #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */
75:
76: #if NORMA_TASK
77: #define task_create task_create_local
78: #endif /* NORMA_TASK */
79:
80: task_t kernel_task = TASK_NULL;
81: zone_t task_zone;
82:
83: extern zone_t u_task_zone; /* UNIX */
84:
85: void task_init(void)
86: {
87: task_zone = zinit(
88: sizeof(struct task),
89: TASK_MAX * sizeof(struct task),
90: TASK_CHUNK * sizeof(struct task),
91: FALSE, "tasks");
92:
93: /*
94: * Create the kernel task as the first task.
95: * Task_create must assign to kernel_task as a side effect,
96: * for other initialization. (:-()
97: */
98: (void) task_create(TASK_NULL, FALSE, &kernel_task);
99:
100: kernel_task->kernel_privilege = TRUE;
101: kernel_task->kernel_vm_space = TRUE;
102: }
103:
104: /*
105: * Create a task running in the kernel address space. It may
106: * have its own map of size mem_size (if 0, it uses the kernel map),
107: * and may have ipc privileges.
108: */
109: task_t kernel_task_create(
110: task_t parent_task,
111: vm_size_t map_size)
112: {
113: task_t new_task;
114: vm_offset_t min, max;
115:
116: /*
117: * Create the task.
118: */
119: (void) task_create(parent_task, FALSE, &new_task);
120: task_deallocate(new_task); // extra ref for convert_task_to_port()
121:
122: /*
123: * Task_create creates the task with a user-space map.
124: * Remove the map and replace it with the kernel map
125: * or a submap of the kernel map.
126: */
127: vm_map_deallocate(new_task->map);
128: if (map_size == 0)
129: new_task->map = kernel_map;
130: else
131: new_task->map = kmem_suballoc(kernel_map, &min, &max,
132: map_size, FALSE);
133:
134: new_task->kernel_vm_space = TRUE;
135:
136: return new_task;
137: }
138:
139: kern_return_t task_create(
140: task_t parent_task,
141: boolean_t inherit_memory,
142: task_t *child_task) /* OUT */
143: {
144: register task_t new_task;
145: register processor_set_t pset;
146: int i;
147:
148: new_task = (task_t) zalloc(task_zone);
149: if (new_task == TASK_NULL) {
150: panic("task_create: no memory for task structure");
151: }
152:
153: /* one ref for just being alive; one for our caller */
154: new_task->ref_count = 2;
155:
156: if (child_task == &kernel_task) {
157: new_task->map = kernel_map;
158: } else if (inherit_memory) {
159: new_task->map = vm_map_fork(parent_task->map);
160: } else {
161: new_task->map = vm_map_create(pmap_create(0),
162: round_page(VM_MIN_ADDRESS),
163: trunc_page(VM_MAX_ADDRESS), TRUE);
164: }
165:
166: simple_lock_init(&new_task->lock);
167: queue_init(&new_task->thread_list);
168: simple_lock_init(&new_task->thread_list_lock);
169: new_task->suspend_count = 0;
170: new_task->active = TRUE;
171: new_task->user_stop_count = 0;
172: new_task->thread_count = 0;
173:
174: new_task->pcb_common = 0;
175: pcb_common_init(new_task);
176:
177: new_task->proc = 0;
178:
179: new_task->kernel_vm_space = FALSE;
180:
181: ipc_task_init(new_task, parent_task);
182:
183: new_task->total_user_time.seconds = 0;
184: new_task->total_user_time.microseconds = 0;
185: new_task->total_system_time.seconds = 0;
186: new_task->total_system_time.microseconds = 0;
187:
188: if (parent_task != TASK_NULL) {
189: new_task->kernel_privilege = parent_task->kernel_privilege;
190: task_lock(parent_task);
191: pset = parent_task->processor_set;
192: if (!pset->active)
193: pset = &default_pset;
194: pset_reference(pset);
195: new_task->priority = parent_task->priority;
196: task_unlock(parent_task);
197: }
198: else {
199: new_task->kernel_privilege = FALSE;
200: pset = &default_pset;
201: pset_reference(pset);
202: new_task->priority = BASEPRI_USER;
203: }
204: pset_lock(pset);
205: pset_add_task(pset, new_task);
206: pset_unlock(pset);
207:
208: new_task->may_assign = TRUE;
209: new_task->assign_active = FALSE;
210:
211: ipc_task_enable(new_task);
212:
213: #if NORMA_TASK
214: new_task->child_node = -1;
215: #endif /* NORMA_TASK */
216:
217: *child_task = new_task;
218: return KERN_SUCCESS;
219: }
220:
221: /*
222: * task_deallocate:
223: *
224: * Give up a reference to the specified task and destroy it if there
225: * are no other references left. It is assumed that the current thread
226: * is never in this task.
227: */
228: void task_deallocate(
229: register task_t task)
230: {
231: register int c;
232: register processor_set_t pset;
233:
234: if (task == TASK_NULL)
235: return;
236:
237: task_lock(task);
238: c = --(task->ref_count);
239: task_unlock(task);
240: if (c != 0)
241: return;
242:
243: #if NORMA_TASK
244: if (task->map == VM_MAP_NULL) {
245: /* norma placeholder task */
246: zfree(task_zone, (vm_offset_t) task);
247: return;
248: }
249: #endif /* NORMA_TASK */
250:
251: pset = task->processor_set;
252: pset_lock(pset);
253: pset_remove_task(pset,task);
254: pset_unlock(pset);
255: pset_deallocate(pset);
256: vm_map_deallocate(task->map);
257: is_release(task->itk_space);
258: pcb_common_terminate(task);
259: zfree(task_zone, (vm_offset_t) task);
260: }
261:
262: void task_reference(
263: register task_t task)
264: {
265: if (task == TASK_NULL)
266: return;
267:
268: task_lock(task);
269: task->ref_count++;
270: task_unlock(task);
271: }
272:
273: /*
274: * task_terminate:
275: *
276: * Terminate the specified task. See comments on thread_terminate
277: * (kern/thread.c) about problems with terminating the "current task."
278: */
279: kern_return_t task_terminate(
280: register task_t task)
281: {
282: register thread_t thread, cur_thread;
283: register queue_head_t *list;
284: register task_t cur_task;
285: int s;
286:
287: if (task == TASK_NULL)
288: return KERN_INVALID_ARGUMENT;
289:
290: /* Disallow termination of U**X proc tasks */
291: if (task->proc)
292: return KERN_FAILURE;
293:
294: list = &task->thread_list;
295: cur_task = current_task();
296: cur_thread = current_thread();
297:
298: /*
299: * Deactivate task so that it can't be terminated again,
300: * and so lengthy operations in progress will abort.
301: *
302: * If the current thread is in this task, remove it from
303: * the task's thread list to keep the thread-termination
304: * loop simple.
305: */
306: if (task == cur_task) {
307: task_lock(task);
308: if (!task->active) {
309: /*
310: * Task is already being terminated.
311: */
312: task_unlock(task);
313: return KERN_FAILURE;
314: }
315: /*
316: * Make sure current thread is not being terminated.
317: */
318: s = splsched();
319: simple_lock(&task->thread_list_lock);
320: thread_lock(cur_thread);
321: if (!cur_thread->active) {
322: thread_unlock(cur_thread);
323: simple_unlock(&task->thread_list_lock);
324: (void) splx(s);
325: task_unlock(task);
326: thread_terminate(cur_thread);
327: return KERN_FAILURE;
328: }
329: task->active = FALSE;
330: queue_remove(list, cur_thread, thread_t, thread_list);
331: thread_unlock(cur_thread);
332: simple_unlock(&task->thread_list_lock);
333: (void) splx(s);
334: task_unlock(task);
335:
336: /*
337: * Shut down this thread's ipc now because it must
338: * be left alone to terminate the task.
339: */
340: ipc_thread_disable(cur_thread);
341: ipc_thread_terminate(cur_thread);
342: }
343: else {
344: /*
345: * Lock both current and victim task to check for
346: * potential deadlock.
347: */
348: if ((vm_offset_t)task < (vm_offset_t)cur_task) {
349: task_lock(task);
350: task_lock(cur_task);
351: }
352: else {
353: task_lock(cur_task);
354: task_lock(task);
355: }
356: /*
357: * Check if current thread or task is being terminated.
358: */
359: s = splsched();
360: thread_lock(cur_thread);
361: if ((!cur_task->active) ||(!cur_thread->active)) {
362: /*
363: * Current task or thread is being terminated.
364: */
365: thread_unlock(cur_thread);
366: (void) splx(s);
367: task_unlock(task);
368: task_unlock(cur_task);
369: thread_terminate(cur_thread);
370: return KERN_FAILURE;
371: }
372: thread_unlock(cur_thread);
373: (void) splx(s);
374: task_unlock(cur_task);
375:
376: if (!task->active) {
377: /*
378: * Task is already being terminated.
379: */
380: task_unlock(task);
381: return KERN_FAILURE;
382: }
383: task->active = FALSE;
384: task_unlock(task);
385: }
386:
387: /*
388: * Prevent further execution of the task. ipc_task_disable
389: * prevents further task operations via the task port.
390: * If this is the current task, the current thread will
391: * be left running.
392: */
393: ipc_task_disable(task);
394: (void) task_hold(task);
395: (void) task_dowait(task,TRUE); /* may block */
396:
397: /*
398: * Terminate each thread in the task.
399: *
400: * The task_port is closed down, so no more thread_create
401: * operations can be done. Thread_force_terminate closes the
402: * thread port for each thread; when that is done, the
403: * thread will eventually disappear. Thus the loop will
404: * terminate. Call thread_force_terminate instead of
405: * thread_terminate to avoid deadlock checks. Need
406: * to call thread_block() inside loop because some other
407: * thread (e.g., the reaper) may have to run to get rid
408: * of all references to the thread; it won't vanish from
409: * the task's thread list until the last one is gone.
410: */
411: task_lock(task);
412: while (!queue_empty(list)) {
413: thread = (thread_t) queue_first(list);
414: thread_reference(thread);
415: task_unlock(task);
416: thread_force_terminate(thread);
417: thread_deallocate(thread);
418: thread_block_with_continuation((void (*)()) 0);
419: task_lock(task);
420: }
421: task_unlock(task);
422:
423: /*
424: * Shut down IPC.
425: */
426: ipc_task_terminate(task);
427:
428:
429: /*
430: * Deallocate the task's reference to itself.
431: */
432: task_deallocate(task);
433:
434: /*
435: * If the current thread is in this task, it has not yet
436: * been terminated (since it was removed from the task's
437: * thread-list). Put it back in the thread list (for
438: * completeness), and terminate it. Since it holds the
439: * last reference to the task, terminating it will deallocate
440: * the task.
441: */
442: if (cur_thread->task == task) {
443: task_lock(task);
444: s = splsched();
445: simple_lock(&task->thread_list_lock);
446: queue_enter(list, cur_thread, thread_t, thread_list);
447: simple_unlock(&task->thread_list_lock);
448: (void) splx(s);
449: task_unlock(task);
450: (void) thread_terminate(cur_thread);
451: }
452:
453: return KERN_SUCCESS;
454: }
455:
456: /*
457: * task_hold:
458: *
459: * Suspend execution of the specified task.
460: * This is a recursive-style suspension of the task, a count of
461: * suspends is maintained.
462: */
463: kern_return_t task_hold(
464: register task_t task)
465: {
466: register queue_head_t *list;
467: register thread_t thread, cur_thread;
468:
469: cur_thread = current_thread();
470:
471: task_lock(task);
472: if (!task->active) {
473: task_unlock(task);
474: return KERN_FAILURE;
475: }
476:
477: task->suspend_count++;
478:
479: /*
480: * Iterate through all the threads and hold them.
481: * Do not hold the current thread if it is within the
482: * task.
483: */
484: list = &task->thread_list;
485: queue_iterate(list, thread, thread_t, thread_list) {
486: if (thread != cur_thread)
487: thread_hold(thread);
488: }
489: task_unlock(task);
490: return KERN_SUCCESS;
491: }
492:
493: /*
494: * task_dowait:
495: *
496: * Wait until the task has really been suspended (all of the threads
497: * are stopped). Skip the current thread if it is within the task.
498: *
499: * If task is deactivated while waiting, return a failure code unless
500: * must_wait is true.
501: */
502: kern_return_t task_dowait(
503: register task_t task,
504: boolean_t must_wait)
505: {
506: register queue_head_t *list;
507: register thread_t thread, cur_thread, prev_thread;
508: register kern_return_t ret = KERN_SUCCESS;
509:
510: /*
511: * Iterate through all the threads.
512: * While waiting for each thread, we gain a reference to it
513: * to prevent it from going away on us. This guarantees
514: * that the "next" thread in the list will be a valid thread.
515: *
516: * We depend on the fact that if threads are created while
517: * we are looping through the threads, they will be held
518: * automatically. We don't care about threads that get
519: * deallocated along the way (the reference prevents it
520: * from happening to the thread we are working with).
521: *
522: * If the current thread is in the affected task, it is skipped.
523: *
524: * If the task is deactivated before we're done, and we don't
525: * have to wait for it (must_wait is FALSE), just bail out.
526: */
527: cur_thread = current_thread();
528:
529: list = &task->thread_list;
530: prev_thread = THREAD_NULL;
531: task_lock(task);
532: queue_iterate(list, thread, thread_t, thread_list) {
533: if (!(task->active) && !(must_wait)) {
534: ret = KERN_FAILURE;
535: break;
536: }
537: if (thread != cur_thread) {
538: thread_reference(thread);
539: task_unlock(task);
540: if (prev_thread != THREAD_NULL)
541: thread_deallocate(prev_thread);
542: /* may block */
543: (void) thread_dowait(thread, TRUE); /* may block */
544: prev_thread = thread;
545: task_lock(task);
546: }
547: }
548: task_unlock(task);
549: if (prev_thread != THREAD_NULL)
550: thread_deallocate(prev_thread); /* may block */
551: return ret;
552: }
553:
554: kern_return_t task_release(
555: register task_t task)
556: {
557: register queue_head_t *list;
558: register thread_t thread, next;
559:
560: task_lock(task);
561: if (!task->active) {
562: task_unlock(task);
563: return KERN_FAILURE;
564: }
565:
566: task->suspend_count--;
567:
568: /*
569: * Iterate through all the threads and release them
570: */
571: list = &task->thread_list;
572: thread = (thread_t) queue_first(list);
573: while (!queue_end(list, (queue_entry_t) thread)) {
574: next = (thread_t) queue_next(&thread->thread_list);
575: thread_release(thread);
576: thread = next;
577: }
578: task_unlock(task);
579: return KERN_SUCCESS;
580: }
581:
582: /*
583: * task_halt:
584: *
585: * Halt all threads in the task. Do not halt the current thread if
586: * it is within the task.
587: *
588: * Only called from exit().
589: */
590: kern_return_t task_halt(task)
591: register task_t task;
592: {
593: register queue_head_t *list;
594: register thread_t thread, cur_thread, prev_thread;
595: register kern_return_t ret = KERN_SUCCESS;
596:
597: /*
598: * Iterate through all the threads.
599: * While waiting for each thread, we gain a reference to it
600: * to prevent it from going away on us. This guarantees
601: * that the "next" thread in the list will be a valid thread.
602: *
603: * If the current thread is in the affected task, it is skipped.
604: */
605: cur_thread = current_thread();
606:
607: list = &task->thread_list;
608: prev_thread = THREAD_NULL;
609: task_lock(task);
610: thread = (thread_t) queue_first(list);
611: while (!queue_end(list, (queue_entry_t) thread)) {
612: if (thread != cur_thread) {
613: thread_reference(thread);
614: task_unlock(task);
615: if (prev_thread != THREAD_NULL)
616: thread_deallocate(prev_thread); /* may block */
617: #if MACH_HOST
618: thread_freeze(thread);
619: if (thread->processor_set != &default_pset)
620: thread_doassign(thread, &default_pset, FALSE);
621: #endif MACH_HOST
622: thread_halt(thread, TRUE); /* may block */
623: #if MACH_HOST
624: thread_unfreeze(thread);
625: #endif MACH_HOST
626: prev_thread = thread;
627: task_lock(task);
628: }
629: thread = (thread_t) queue_next(&thread->thread_list);
630: }
631: task_unlock(task);
632: if (prev_thread != THREAD_NULL)
633: thread_deallocate(prev_thread); /* may block */
634: return(ret);
635: }
636:
637: kern_return_t task_threads(
638: task_t task,
639: thread_array_t *thread_list,
640: natural_t *count)
641: {
642: unsigned int actual; /* this many threads */
643: thread_t thread;
644: thread_t *threads;
645: int i;
646:
647: vm_size_t size, size_needed;
648: vm_offset_t addr;
649:
650: if (task == TASK_NULL)
651: return KERN_INVALID_ARGUMENT;
652:
653: size = 0; addr = 0;
654:
655: for (;;) {
656: task_lock(task);
657: if (!task->active) {
658: task_unlock(task);
659: return KERN_FAILURE;
660: }
661:
662: actual = task->thread_count;
663:
664: /* do we have the memory we need? */
665:
666: size_needed = actual * sizeof(mach_port_t);
667: if (size_needed <= size)
668: break;
669:
670: /* unlock the task and allocate more memory */
671: task_unlock(task);
672:
673: if (size != 0)
674: kfree(addr, size);
675:
676: assert(size_needed > 0);
677: size = size_needed;
678:
679: addr = kalloc(size);
680: if (addr == 0)
681: return KERN_RESOURCE_SHORTAGE;
682: }
683:
684: /* OK, have memory and the task is locked & active */
685:
686: threads = (thread_t *) addr;
687:
688: for (i = 0, thread = (thread_t) queue_first(&task->thread_list);
689: i < actual;
690: i++, thread = (thread_t) queue_next(&thread->thread_list)) {
691: /* take ref for convert_thread_to_port */
692: thread_reference(thread);
693: threads[i] = thread;
694: }
695: assert(queue_end(&task->thread_list, (queue_entry_t) thread));
696:
697: /* can unlock task now that we've got the thread refs */
698: task_unlock(task);
699:
700: if (actual == 0) {
701: /* no threads, so return null pointer and deallocate memory */
702:
703: *thread_list = 0;
704: *count = 0;
705:
706: if (size != 0)
707: kfree(addr, size);
708: } else {
709: /* if we allocated too much, must copy */
710:
711: if (size_needed < size) {
712: vm_offset_t newaddr;
713:
714: newaddr = kalloc(size_needed);
715: if (newaddr == 0) {
716: for (i = 0; i < actual; i++)
717: thread_deallocate(threads[i]);
718: kfree(addr, size);
719: return KERN_RESOURCE_SHORTAGE;
720: }
721:
722: bcopy((char *) addr, (char *) newaddr, size_needed);
723: kfree(addr, size);
724: threads = (thread_t *) newaddr;
725: }
726:
727: *thread_list = (mach_port_t *) threads;
728: *count = actual;
729:
730: /* do the conversion that Mig should handle */
731:
732: for (i = 0; i < actual; i++)
733: ((ipc_port_t *) threads)[i] =
734: convert_thread_to_port(threads[i]);
735: }
736:
737: return KERN_SUCCESS;
738: }
739:
740: kern_return_t task_suspend(
741: register task_t task)
742: {
743: register boolean_t hold;
744:
745: if (task == TASK_NULL)
746: return KERN_INVALID_ARGUMENT;
747:
748: hold = FALSE;
749: task_lock(task);
750: if ((task->user_stop_count)++ == 0)
751: hold = TRUE;
752: task_unlock(task);
753:
754: /*
755: * If the stop count was positive, the task is
756: * already stopped and we can exit.
757: */
758: if (!hold) {
759: return KERN_SUCCESS;
760: }
761:
762: /*
763: * Hold all of the threads in the task, and wait for
764: * them to stop. If the current thread is within
765: * this task, hold it separately so that all of the
766: * other threads can stop first.
767: */
768:
769: if (task_hold(task) != KERN_SUCCESS)
770: return KERN_FAILURE;
771:
772: if (task_dowait(task, FALSE) != KERN_SUCCESS)
773: return KERN_FAILURE;
774:
775: if (current_task() == task) {
776: int s;
777:
778: thread_hold(current_thread());
779: /*
780: * We want to call thread_block on our way out,
781: * to stop running.
782: */
783: s = splsched();
784: ast_on(cpu_number(), AST_BLOCK);
785: (void) splx(s);
786: }
787:
788: return KERN_SUCCESS;
789: }
790:
791: kern_return_t task_resume(
792: register task_t task)
793: {
794: register boolean_t release;
795:
796: if (task == TASK_NULL)
797: return KERN_INVALID_ARGUMENT;
798:
799: release = FALSE;
800: task_lock(task);
801: if (task->user_stop_count > 0) {
802: if (--(task->user_stop_count) == 0)
803: release = TRUE;
804: }
805: else {
806: task_unlock(task);
807: return KERN_FAILURE;
808: }
809: task_unlock(task);
810:
811: /*
812: * Release the task if necessary.
813: */
814: if (release)
815: return task_release(task);
816:
817: return KERN_SUCCESS;
818: }
819:
820: kern_return_t task_info(
821: task_t task,
822: int flavor,
823: task_info_t task_info_out, /* pointer to OUT array */
824: natural_t *task_info_count) /* IN/OUT */
825: {
826: vm_map_t map;
827:
828: if (task == TASK_NULL)
829: return KERN_INVALID_ARGUMENT;
830:
831: switch (flavor) {
832: case TASK_BASIC_INFO:
833: {
834: register task_basic_info_t basic_info;
835:
836: if (*task_info_count < TASK_BASIC_INFO_COUNT) {
837: return KERN_INVALID_ARGUMENT;
838: }
839:
840: basic_info = (task_basic_info_t) task_info_out;
841:
842: map = (task == kernel_task) ? kernel_map : task->map;
843:
844: basic_info->virtual_size = map->size;
845: basic_info->resident_size = pmap_resident_count(map->pmap)
846: * PAGE_SIZE;
847:
848: task_lock(task);
849: basic_info->base_priority = task->priority;
850: basic_info->suspend_count = task->user_stop_count;
851: basic_info->user_time.seconds
852: = task->total_user_time.seconds;
853: basic_info->user_time.microseconds
854: = task->total_user_time.microseconds;
855: basic_info->system_time.seconds
856: = task->total_system_time.seconds;
857: basic_info->system_time.microseconds
858: = task->total_system_time.microseconds;
859: task_unlock(task);
860:
861: *task_info_count = TASK_BASIC_INFO_COUNT;
862: break;
863: }
864:
865: case TASK_THREAD_TIMES_INFO:
866: {
867: register task_thread_times_info_t times_info;
868: register thread_t thread;
869:
870: if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
871: return KERN_INVALID_ARGUMENT;
872: }
873:
874: times_info = (task_thread_times_info_t) task_info_out;
875: times_info->user_time.seconds = 0;
876: times_info->user_time.microseconds = 0;
877: times_info->system_time.seconds = 0;
878: times_info->system_time.microseconds = 0;
879:
880: task_lock(task);
881: queue_iterate(&task->thread_list, thread,
882: thread_t, thread_list)
883: {
884: time_value_t user_time, system_time;
885: int s;
886:
887: s = splsched();
888: thread_lock(thread);
889:
890: thread_read_times(thread, &user_time, &system_time);
891:
892: thread_unlock(thread);
893: splx(s);
894:
895: time_value_add(×_info->user_time, &user_time);
896: time_value_add(×_info->system_time, &system_time);
897: }
898: task_unlock(task);
899:
900: *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
901: break;
902: }
903:
904: default:
905: return KERN_INVALID_ARGUMENT;
906: }
907:
908: return KERN_SUCCESS;
909: }
910:
911: /*
912: * Special version of task_suspend that doesn't wait.
913: * Called only from interrupt level (U*X psignal).
914: * Will go away when signal code becomes sane.
915: */
916: kern_return_t task_suspend_nowait(task)
917: register task_t task;
918: {
919: register boolean_t hold;
920:
921: if (task == TASK_NULL)
922: return(KERN_INVALID_ARGUMENT);
923:
924: hold = FALSE;
925: task_lock(task);
926: if ((task->user_stop_count)++ == 0)
927: hold = TRUE;
928: task_unlock(task);
929:
930: /*
931: * If the stop count was positive, the task is
932: * already stopped and we can exit.
933: */
934: if (!hold) {
935: return (KERN_SUCCESS);
936: }
937:
938: /*
939: * Hold all of the threads in the task.
940: * If the current thread is within
941: * this task, hold it separately so that all of the
942: * other threads can stop first.
943: */
944:
945: if (task_hold(task) != KERN_SUCCESS)
946: return(KERN_FAILURE);
947:
948: if (current_task() == task) {
949: thread_hold(current_thread());
950: }
951:
952: return(KERN_SUCCESS);
953: }
954:
955: #if MACH_HOST
956: /*
957: * task_assign:
958: *
959: * Change the assigned processor set for the task
960: */
961: kern_return_t
962: task_assign(
963: task_t task,
964: processor_set_t new_pset,
965: boolean_t assign_threads)
966: {
967: kern_return_t ret = KERN_SUCCESS;
968: register thread_t thread, prev_thread;
969: register queue_head_t *list;
970: register processor_set_t pset;
971:
972: if (task == TASK_NULL || new_pset == PROCESSOR_SET_NULL) {
973: return KERN_INVALID_ARGUMENT;
974: }
975:
976: /*
977: * Freeze task`s assignment. Prelude to assigning
978: * task. Only one freeze may be held per task.
979: */
980:
981: task_lock(task);
982: while (task->may_assign == FALSE) {
983: task->assign_active = TRUE;
984: assert_wait((event_t)&task->assign_active, TRUE);
985: task_unlock(task);
986: thread_block((void (*)()) 0);
987: task_lock(task);
988: }
989:
990: /*
991: * Avoid work if task already in this processor set.
992: */
993: if (task->processor_set == new_pset) {
994: /*
995: * No need for task->assign_active wakeup:
996: * task->may_assign is still TRUE.
997: */
998: task_unlock(task);
999: return KERN_SUCCESS;
1000: }
1001:
1002: task->may_assign = FALSE;
1003: task_unlock(task);
1004:
1005: /*
1006: * Safe to get the task`s pset: it cannot change while
1007: * task is frozen.
1008: */
1009: pset = task->processor_set;
1010:
1011: /*
1012: * Lock both psets now. Use ordering to avoid deadlock.
1013: */
1014: Restart:
1015: if ((vm_offset_t) pset < (vm_offset_t) new_pset) {
1016: pset_lock(pset);
1017: pset_lock(new_pset);
1018: }
1019: else {
1020: pset_lock(new_pset);
1021: pset_lock(pset);
1022: }
1023:
1024: /*
1025: * Check if new_pset is ok to assign to. If not,
1026: * reassign to default_pset.
1027: */
1028: if (!new_pset->active) {
1029: pset_unlock(pset);
1030: pset_unlock(new_pset);
1031: new_pset = &default_pset;
1032: goto Restart;
1033: }
1034:
1035: pset_reference(new_pset);
1036:
1037: /*
1038: * Now grab the task lock and move the task.
1039: */
1040:
1041: task_lock(task);
1042: pset_remove_task(pset, task);
1043: pset_add_task(new_pset, task);
1044:
1045: pset_unlock(pset);
1046: pset_unlock(new_pset);
1047:
1048: if (assign_threads == FALSE) {
1049: /*
1050: * We leave existing threads at their
1051: * old assignments. Unfreeze task`s
1052: * assignment.
1053: */
1054: task->may_assign = TRUE;
1055: if (task->assign_active) {
1056: task->assign_active = FALSE;
1057: thread_wakeup((event_t) &task->assign_active);
1058: }
1059: task_unlock(task);
1060: pset_deallocate(pset);
1061: return KERN_SUCCESS;
1062: }
1063:
1064: /*
1065: * If current thread is in task, freeze its assignment.
1066: */
1067: if (current_thread()->task == task) {
1068: task_unlock(task);
1069: thread_freeze(current_thread());
1070: task_lock(task);
1071: }
1072:
1073: /*
1074: * Iterate down the thread list reassigning all the threads.
1075: * New threads pick up task's new processor set automatically.
1076: * Do current thread last because new pset may be empty.
1077: */
1078: list = &task->thread_list;
1079: prev_thread = THREAD_NULL;
1080: queue_iterate(list, thread, thread_t, thread_list) {
1081: if (!(task->active)) {
1082: ret = KERN_FAILURE;
1083: break;
1084: }
1085: if (thread != current_thread()) {
1086: thread_reference(thread);
1087: task_unlock(task);
1088: if (prev_thread != THREAD_NULL)
1089: thread_deallocate(prev_thread); /* may block */
1090: thread_assign(thread,new_pset); /* may block */
1091: prev_thread = thread;
1092: task_lock(task);
1093: }
1094: }
1095:
1096: /*
1097: * Done, wakeup anyone waiting for us.
1098: */
1099: task->may_assign = TRUE;
1100: if (task->assign_active) {
1101: task->assign_active = FALSE;
1102: thread_wakeup((event_t)&task->assign_active);
1103: }
1104: task_unlock(task);
1105: if (prev_thread != THREAD_NULL)
1106: thread_deallocate(prev_thread); /* may block */
1107:
1108: /*
1109: * Finish assignment of current thread.
1110: */
1111: if (current_thread()->task == task)
1112: thread_doassign(current_thread(), new_pset, TRUE);
1113:
1114: pset_deallocate(pset);
1115:
1116: return ret;
1117: }
1118: #else /* MACH_HOST */
1119: /*
1120: * task_assign:
1121: *
1122: * Change the assigned processor set for the task
1123: */
1124: kern_return_t
1125: task_assign(
1126: task_t task,
1127: processor_set_t new_pset,
1128: boolean_t assign_threads)
1129: {
1130: return KERN_FAILURE;
1131: }
1132: #endif /* MACH_HOST */
1133:
1134:
1135: /*
1136: * task_assign_default:
1137: *
1138: * Version of task_assign to assign to default processor set.
1139: */
1140: kern_return_t
1141: task_assign_default(
1142: task_t task,
1143: boolean_t assign_threads)
1144: {
1145: return task_assign(task, &default_pset, assign_threads);
1146: }
1147:
1148: /*
1149: * task_get_assignment
1150: *
1151: * Return name of processor set that task is assigned to.
1152: */
1153: kern_return_t task_get_assignment(
1154: task_t task,
1155: processor_set_t *pset)
1156: {
1157: if (!task->active)
1158: return KERN_FAILURE;
1159:
1160: *pset = task->processor_set;
1161: pset_reference(*pset);
1162: return KERN_SUCCESS;
1163: }
1164:
1165: /*
1166: * task_priority
1167: *
1168: * Set priority of task; used only for newly created threads.
1169: * Optionally change priorities of threads.
1170: */
1171: kern_return_t
1172: task_priority(
1173: task_t task,
1174: int priority,
1175: boolean_t change_threads)
1176: {
1177: kern_return_t ret = KERN_SUCCESS;
1178:
1179: if (task == TASK_NULL || invalid_pri(priority))
1180: return KERN_INVALID_ARGUMENT;
1181:
1182: task_lock(task);
1183: task->priority = priority;
1184:
1185: if (change_threads) {
1186: register thread_t thread;
1187: register queue_head_t *list;
1188:
1189: list = &task->thread_list;
1190: queue_iterate(list, thread, thread_t, thread_list) {
1191: if (thread_priority(thread, priority, FALSE)
1192: != KERN_SUCCESS)
1193: ret = KERN_FAILURE;
1194: }
1195: }
1196:
1197: task_unlock(task);
1198: return ret;
1199: }
1200:
1201: task_t current_task_EXTERNAL()
1202: {
1203: return current_task();
1204: }
1205:
1206: /*
1207: * Loadable servers need to be able to find their task map.
1208: */
1209: vm_map_t current_map_EXTERNAL()
1210: {
1211: return current_task()->map;
1212: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.