|
|
1.1.1.2 root 1: /*
1.1 root 2: * Mach Operating System
3: * Copyright (c) 1993-1988 Carnegie Mellon University
4: * All Rights Reserved.
1.1.1.2 root 5: *
1.1 root 6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
1.1.1.2 root 11: *
1.1 root 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1.1.1.2 root 15: *
1.1 root 16: * Carnegie Mellon requests users of this software to return to
1.1.1.2 root 17: *
1.1 root 18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
1.1.1.2 root 22: *
1.1 root 23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * File: kern/task.c
28: * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub,
29: * David Black
30: *
31: * Task management primitives implementation.
32: */
33:
1.1.1.3 root 34: #include <string.h>
1.1 root 35:
36: #include <mach/machine/vm_types.h>
37: #include <mach/vm_param.h>
38: #include <mach/task_info.h>
39: #include <mach/task_special_ports.h>
1.1.1.4 root 40: #include <mach_debug/mach_debug_types.h>
1.1 root 41: #include <ipc/ipc_space.h>
42: #include <ipc/ipc_types.h>
1.1.1.3 root 43: #include <kern/debug.h>
1.1 root 44: #include <kern/task.h>
45: #include <kern/thread.h>
1.1.1.3 root 46: #include <kern/slab.h>
1.1 root 47: #include <kern/kalloc.h>
48: #include <kern/processor.h>
1.1.1.4 root 49: #include <kern/printf.h>
1.1 root 50: #include <kern/sched_prim.h> /* for thread_wakeup */
51: #include <kern/ipc_tt.h>
1.1.1.4 root 52: #include <kern/syscall_emulation.h>
53: #include <kern/task_notify.user.h>
1.1 root 54: #include <vm/vm_kern.h> /* for kernel_map, ipc_kernel_map */
55: #include <machine/machspl.h> /* for splsched */
56:
57: task_t kernel_task = TASK_NULL;
1.1.1.3 root 58: struct kmem_cache task_cache;
1.1 root 59:
1.1.1.4 root 60: /* Where to send notifications about newly created tasks. */
61: ipc_port_t new_task_notification = NULL;
1.1 root 62:
63: void task_init(void)
64: {
1.1.1.3 root 65: kmem_cache_init(&task_cache, "task", sizeof(struct task), 0,
1.1.1.6 root 66: NULL, 0);
1.1 root 67:
68: eml_init();
1.1.1.3 root 69: machine_task_module_init ();
1.1 root 70:
71: /*
72: * Create the kernel task as the first task.
73: * Task_create must assign to kernel_task as a side effect,
74: * for other initialization. (:-()
75: */
76: (void) task_create(TASK_NULL, FALSE, &kernel_task);
1.1.1.4 root 77: (void) task_set_name(kernel_task, "gnumach");
1.1.1.7 ! root 78: vm_map_set_name(kernel_map, kernel_task->name);
1.1 root 79: }
80:
81: kern_return_t task_create(
82: task_t parent_task,
83: boolean_t inherit_memory,
84: task_t *child_task) /* OUT */
85: {
1.1.1.4 root 86: task_t new_task;
87: processor_set_t pset;
1.1.1.3 root 88: #if FAST_TAS
1.1 root 89: int i;
1.1.1.3 root 90: #endif
1.1 root 91:
1.1.1.3 root 92: new_task = (task_t) kmem_cache_alloc(&task_cache);
1.1.1.5 root 93: if (new_task == TASK_NULL)
94: return KERN_RESOURCE_SHORTAGE;
1.1 root 95:
96: /* one ref for just being alive; one for our caller */
97: new_task->ref_count = 2;
98:
99: if (child_task == &kernel_task) {
1.1.1.2 root 100: new_task->map = kernel_map;
1.1 root 101: } else if (inherit_memory) {
102: new_task->map = vm_map_fork(parent_task->map);
103: } else {
1.1.1.7 ! root 104: pmap_t new_pmap = pmap_create((vm_size_t) 0);
! 105: if (new_pmap == PMAP_NULL)
! 106: new_task->map = VM_MAP_NULL;
! 107: else {
! 108: new_task->map = vm_map_create(new_pmap,
1.1 root 109: round_page(VM_MIN_ADDRESS),
1.1.1.7 ! root 110: trunc_page(VM_MAX_ADDRESS));
! 111: if (new_task->map == VM_MAP_NULL)
! 112: pmap_destroy(new_pmap);
! 113: }
! 114: }
! 115: if (new_task->map == VM_MAP_NULL) {
! 116: kmem_cache_free(&task_cache, (vm_address_t) new_task);
! 117: return KERN_RESOURCE_SHORTAGE;
1.1 root 118: }
1.1.1.7 ! root 119: if (child_task != &kernel_task)
! 120: vm_map_set_name(new_task->map, new_task->name);
1.1 root 121:
122: simple_lock_init(&new_task->lock);
123: queue_init(&new_task->thread_list);
124: new_task->suspend_count = 0;
125: new_task->active = TRUE;
126: new_task->user_stop_count = 0;
127: new_task->thread_count = 0;
1.1.1.3 root 128: new_task->faults = 0;
129: new_task->zero_fills = 0;
130: new_task->reactivations = 0;
131: new_task->pageins = 0;
132: new_task->cow_faults = 0;
133: new_task->messages_sent = 0;
134: new_task->messages_received = 0;
1.1 root 135:
136: eml_task_reference(new_task, parent_task);
137:
138: ipc_task_init(new_task, parent_task);
1.1.1.3 root 139: machine_task_init (new_task);
1.1 root 140:
141: new_task->total_user_time.seconds = 0;
142: new_task->total_user_time.microseconds = 0;
143: new_task->total_system_time.seconds = 0;
144: new_task->total_system_time.microseconds = 0;
145:
1.1.1.2 root 146: record_time_stamp (&new_task->creation_time);
147:
1.1 root 148: if (parent_task != TASK_NULL) {
149: task_lock(parent_task);
150: pset = parent_task->processor_set;
151: if (!pset->active)
152: pset = &default_pset;
153: pset_reference(pset);
154: new_task->priority = parent_task->priority;
155: task_unlock(parent_task);
156: }
157: else {
158: pset = &default_pset;
159: pset_reference(pset);
160: new_task->priority = BASEPRI_USER;
161: }
162: pset_lock(pset);
163: pset_add_task(pset, new_task);
164: pset_unlock(pset);
165:
166: new_task->may_assign = TRUE;
167: new_task->assign_active = FALSE;
168:
169: #if MACH_PCSAMPLE
170: new_task->pc_sample.buffer = 0;
171: new_task->pc_sample.seqno = 0;
172: new_task->pc_sample.sampletypes = 0;
173: #endif /* MACH_PCSAMPLE */
174:
175: #if FAST_TAS
176: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
177: if (inherit_memory) {
178: new_task->fast_tas_base[i] = parent_task->fast_tas_base[i];
179: new_task->fast_tas_end[i] = parent_task->fast_tas_end[i];
180: } else {
181: new_task->fast_tas_base[i] = (vm_offset_t)0;
182: new_task->fast_tas_end[i] = (vm_offset_t)0;
183: }
184: }
185: #endif /* FAST_TAS */
1.1.1.2 root 186:
1.1.1.4 root 187: if (parent_task == TASK_NULL)
188: snprintf (new_task->name, sizeof new_task->name, "%p",
189: new_task);
190: else
191: snprintf (new_task->name, sizeof new_task->name, "(%.*s)",
192: sizeof new_task->name - 3, parent_task->name);
193:
194: if (new_task_notification != NULL) {
195: task_reference (new_task);
196: task_reference (parent_task);
197: mach_notify_new_task (new_task_notification,
198: convert_task_to_port (new_task),
199: convert_task_to_port (parent_task));
200: }
201:
1.1 root 202: ipc_task_enable(new_task);
203:
204: *child_task = new_task;
205: return KERN_SUCCESS;
206: }
207:
208: /*
209: * task_deallocate:
210: *
211: * Give up a reference to the specified task and destroy it if there
212: * are no other references left. It is assumed that the current thread
213: * is never in this task.
214: */
215: void task_deallocate(
1.1.1.4 root 216: task_t task)
1.1 root 217: {
1.1.1.4 root 218: int c;
219: processor_set_t pset;
1.1 root 220:
221: if (task == TASK_NULL)
222: return;
223:
224: task_lock(task);
225: c = --(task->ref_count);
226: task_unlock(task);
227: if (c != 0)
228: return;
229:
1.1.1.3 root 230: machine_task_terminate (task);
1.1 root 231:
232: eml_task_deallocate(task);
233:
234: pset = task->processor_set;
235: pset_lock(pset);
236: pset_remove_task(pset,task);
237: pset_unlock(pset);
238: pset_deallocate(pset);
239: vm_map_deallocate(task->map);
240: is_release(task->itk_space);
1.1.1.3 root 241: kmem_cache_free(&task_cache, (vm_offset_t) task);
1.1 root 242: }
243:
244: void task_reference(
1.1.1.4 root 245: task_t task)
1.1 root 246: {
247: if (task == TASK_NULL)
248: return;
249:
250: task_lock(task);
251: task->ref_count++;
252: task_unlock(task);
253: }
254:
255: /*
256: * task_terminate:
257: *
258: * Terminate the specified task. See comments on thread_terminate
259: * (kern/thread.c) about problems with terminating the "current task."
260: */
261: kern_return_t task_terminate(
1.1.1.4 root 262: task_t task)
1.1 root 263: {
1.1.1.4 root 264: thread_t thread, cur_thread;
265: queue_head_t *list;
266: task_t cur_task;
1.1 root 267: spl_t s;
268:
269: if (task == TASK_NULL)
270: return KERN_INVALID_ARGUMENT;
271:
272: list = &task->thread_list;
273: cur_task = current_task();
274: cur_thread = current_thread();
275:
276: /*
277: * Deactivate task so that it can't be terminated again,
278: * and so lengthy operations in progress will abort.
279: *
280: * If the current thread is in this task, remove it from
281: * the task's thread list to keep the thread-termination
282: * loop simple.
283: */
284: if (task == cur_task) {
285: task_lock(task);
286: if (!task->active) {
287: /*
288: * Task is already being terminated.
289: */
290: task_unlock(task);
291: return KERN_FAILURE;
292: }
293: /*
294: * Make sure current thread is not being terminated.
295: */
296: s = splsched();
297: thread_lock(cur_thread);
298: if (!cur_thread->active) {
299: thread_unlock(cur_thread);
300: (void) splx(s);
301: task_unlock(task);
302: thread_terminate(cur_thread);
303: return KERN_FAILURE;
304: }
1.1.1.4 root 305: task_hold_locked(task);
1.1 root 306: task->active = FALSE;
307: queue_remove(list, cur_thread, thread_t, thread_list);
308: thread_unlock(cur_thread);
309: (void) splx(s);
310: task_unlock(task);
311:
312: /*
313: * Shut down this thread's ipc now because it must
314: * be left alone to terminate the task.
315: */
316: ipc_thread_disable(cur_thread);
317: ipc_thread_terminate(cur_thread);
318: }
319: else {
320: /*
321: * Lock both current and victim task to check for
322: * potential deadlock.
323: */
324: if ((vm_offset_t)task < (vm_offset_t)cur_task) {
325: task_lock(task);
326: task_lock(cur_task);
327: }
328: else {
329: task_lock(cur_task);
330: task_lock(task);
331: }
332: /*
333: * Check if current thread or task is being terminated.
334: */
335: s = splsched();
336: thread_lock(cur_thread);
337: if ((!cur_task->active) ||(!cur_thread->active)) {
338: /*
339: * Current task or thread is being terminated.
340: */
341: thread_unlock(cur_thread);
342: (void) splx(s);
343: task_unlock(task);
344: task_unlock(cur_task);
345: thread_terminate(cur_thread);
346: return KERN_FAILURE;
347: }
348: thread_unlock(cur_thread);
349: (void) splx(s);
350: task_unlock(cur_task);
351:
352: if (!task->active) {
353: /*
354: * Task is already being terminated.
355: */
356: task_unlock(task);
357: return KERN_FAILURE;
358: }
1.1.1.4 root 359: task_hold_locked(task);
1.1 root 360: task->active = FALSE;
361: task_unlock(task);
362: }
363:
364: /*
365: * Prevent further execution of the task. ipc_task_disable
366: * prevents further task operations via the task port.
367: * If this is the current task, the current thread will
368: * be left running.
369: */
370: (void) task_dowait(task,TRUE); /* may block */
1.1.1.4 root 371: ipc_task_disable(task);
1.1 root 372:
373: /*
374: * Terminate each thread in the task.
375: *
376: * The task_port is closed down, so no more thread_create
377: * operations can be done. Thread_force_terminate closes the
378: * thread port for each thread; when that is done, the
379: * thread will eventually disappear. Thus the loop will
380: * terminate. Call thread_force_terminate instead of
381: * thread_terminate to avoid deadlock checks. Need
382: * to call thread_block() inside loop because some other
383: * thread (e.g., the reaper) may have to run to get rid
384: * of all references to the thread; it won't vanish from
385: * the task's thread list until the last one is gone.
386: */
387: task_lock(task);
388: while (!queue_empty(list)) {
389: thread = (thread_t) queue_first(list);
390: thread_reference(thread);
391: task_unlock(task);
392: thread_force_terminate(thread);
393: thread_deallocate(thread);
1.1.1.5 root 394: thread_block(thread_no_continuation);
1.1 root 395: task_lock(task);
396: }
397: task_unlock(task);
398:
399: /*
400: * Shut down IPC.
401: */
402: ipc_task_terminate(task);
403:
404:
405: /*
406: * Deallocate the task's reference to itself.
407: */
408: task_deallocate(task);
409:
410: /*
411: * If the current thread is in this task, it has not yet
412: * been terminated (since it was removed from the task's
413: * thread-list). Put it back in the thread list (for
414: * completeness), and terminate it. Since it holds the
415: * last reference to the task, terminating it will deallocate
416: * the task.
417: */
418: if (cur_thread->task == task) {
419: task_lock(task);
420: s = splsched();
421: queue_enter(list, cur_thread, thread_t, thread_list);
422: (void) splx(s);
423: task_unlock(task);
424: (void) thread_terminate(cur_thread);
425: }
426:
427: return KERN_SUCCESS;
428: }
429:
430: /*
431: * task_hold:
432: *
433: * Suspend execution of the specified task.
434: * This is a recursive-style suspension of the task, a count of
435: * suspends is maintained.
1.1.1.4 root 436: *
437: * CONDITIONS: the task is locked and active.
1.1 root 438: */
1.1.1.4 root 439: void task_hold_locked(
440: task_t task)
1.1 root 441: {
1.1.1.4 root 442: queue_head_t *list;
443: thread_t thread, cur_thread;
1.1 root 444:
1.1.1.4 root 445: assert(task->active);
1.1 root 446:
1.1.1.4 root 447: cur_thread = current_thread();
1.1 root 448:
449: task->suspend_count++;
450:
451: /*
452: * Iterate through all the threads and hold them.
453: * Do not hold the current thread if it is within the
454: * task.
455: */
456: list = &task->thread_list;
457: queue_iterate(list, thread, thread_t, thread_list) {
458: if (thread != cur_thread)
459: thread_hold(thread);
460: }
1.1.1.4 root 461: }
462:
463: /*
464: * task_hold:
465: *
466: * Suspend execution of the specified task.
467: * This is a recursive-style suspension of the task, a count of
468: * suspends is maintained.
469: */
470: kern_return_t task_hold(
471: task_t task)
472: {
473: task_lock(task);
474: if (!task->active) {
475: task_unlock(task);
476: return KERN_FAILURE;
477: }
478:
479: task_hold_locked(task);
480:
1.1 root 481: task_unlock(task);
482: return KERN_SUCCESS;
483: }
484:
485: /*
486: * task_dowait:
487: *
488: * Wait until the task has really been suspended (all of the threads
489: * are stopped). Skip the current thread if it is within the task.
490: *
491: * If task is deactivated while waiting, return a failure code unless
492: * must_wait is true.
493: */
494: kern_return_t task_dowait(
1.1.1.4 root 495: task_t task,
1.1 root 496: boolean_t must_wait)
497: {
1.1.1.4 root 498: queue_head_t *list;
499: thread_t thread, cur_thread, prev_thread;
500: kern_return_t ret = KERN_SUCCESS;
1.1 root 501:
502: /*
503: * Iterate through all the threads.
504: * While waiting for each thread, we gain a reference to it
505: * to prevent it from going away on us. This guarantees
506: * that the "next" thread in the list will be a valid thread.
507: *
508: * We depend on the fact that if threads are created while
509: * we are looping through the threads, they will be held
510: * automatically. We don't care about threads that get
511: * deallocated along the way (the reference prevents it
512: * from happening to the thread we are working with).
513: *
514: * If the current thread is in the affected task, it is skipped.
515: *
516: * If the task is deactivated before we're done, and we don't
517: * have to wait for it (must_wait is FALSE), just bail out.
518: */
519: cur_thread = current_thread();
520:
521: list = &task->thread_list;
522: prev_thread = THREAD_NULL;
523: task_lock(task);
524: queue_iterate(list, thread, thread_t, thread_list) {
525: if (!(task->active) && !(must_wait)) {
526: ret = KERN_FAILURE;
527: break;
528: }
529: if (thread != cur_thread) {
530: thread_reference(thread);
531: task_unlock(task);
532: if (prev_thread != THREAD_NULL)
533: thread_deallocate(prev_thread);
534: /* may block */
535: (void) thread_dowait(thread, TRUE); /* may block */
536: prev_thread = thread;
537: task_lock(task);
538: }
539: }
540: task_unlock(task);
541: if (prev_thread != THREAD_NULL)
542: thread_deallocate(prev_thread); /* may block */
543: return ret;
544: }
545:
546: kern_return_t task_release(
1.1.1.4 root 547: task_t task)
1.1 root 548: {
1.1.1.4 root 549: queue_head_t *list;
550: thread_t thread, next;
1.1 root 551:
552: task_lock(task);
553: if (!task->active) {
554: task_unlock(task);
555: return KERN_FAILURE;
556: }
557:
558: task->suspend_count--;
559:
560: /*
561: * Iterate through all the threads and release them
562: */
563: list = &task->thread_list;
564: thread = (thread_t) queue_first(list);
565: while (!queue_end(list, (queue_entry_t) thread)) {
566: next = (thread_t) queue_next(&thread->thread_list);
567: thread_release(thread);
568: thread = next;
569: }
570: task_unlock(task);
571: return KERN_SUCCESS;
572: }
573:
574: kern_return_t task_threads(
575: task_t task,
576: thread_array_t *thread_list,
577: natural_t *count)
578: {
579: unsigned int actual; /* this many threads */
580: thread_t thread;
581: thread_t *threads;
1.1.1.6 root 582: unsigned i;
1.1 root 583:
584: vm_size_t size, size_needed;
585: vm_offset_t addr;
586:
587: if (task == TASK_NULL)
588: return KERN_INVALID_ARGUMENT;
589:
590: size = 0; addr = 0;
591:
592: for (;;) {
593: task_lock(task);
594: if (!task->active) {
595: task_unlock(task);
596: return KERN_FAILURE;
597: }
598:
599: actual = task->thread_count;
600:
601: /* do we have the memory we need? */
602:
603: size_needed = actual * sizeof(mach_port_t);
604: if (size_needed <= size)
605: break;
606:
607: /* unlock the task and allocate more memory */
608: task_unlock(task);
609:
610: if (size != 0)
611: kfree(addr, size);
612:
613: assert(size_needed > 0);
614: size = size_needed;
615:
616: addr = kalloc(size);
617: if (addr == 0)
618: return KERN_RESOURCE_SHORTAGE;
619: }
620:
621: /* OK, have memory and the task is locked & active */
622:
623: threads = (thread_t *) addr;
624:
625: for (i = 0, thread = (thread_t) queue_first(&task->thread_list);
626: i < actual;
627: i++, thread = (thread_t) queue_next(&thread->thread_list)) {
628: /* take ref for convert_thread_to_port */
629: thread_reference(thread);
630: threads[i] = thread;
631: }
632: assert(queue_end(&task->thread_list, (queue_entry_t) thread));
633:
634: /* can unlock task now that we've got the thread refs */
635: task_unlock(task);
636:
637: if (actual == 0) {
638: /* no threads, so return null pointer and deallocate memory */
639:
640: *thread_list = 0;
641: *count = 0;
642:
643: if (size != 0)
644: kfree(addr, size);
645: } else {
646: /* if we allocated too much, must copy */
647:
648: if (size_needed < size) {
649: vm_offset_t newaddr;
650:
651: newaddr = kalloc(size_needed);
652: if (newaddr == 0) {
653: for (i = 0; i < actual; i++)
654: thread_deallocate(threads[i]);
655: kfree(addr, size);
656: return KERN_RESOURCE_SHORTAGE;
657: }
658:
1.1.1.3 root 659: memcpy((void *) newaddr, (void *) addr, size_needed);
1.1 root 660: kfree(addr, size);
661: threads = (thread_t *) newaddr;
662: }
663:
664: *thread_list = (mach_port_t *) threads;
665: *count = actual;
666:
667: /* do the conversion that Mig should handle */
668:
669: for (i = 0; i < actual; i++)
670: ((ipc_port_t *) threads)[i] =
671: convert_thread_to_port(threads[i]);
672: }
673:
674: return KERN_SUCCESS;
675: }
676:
677: kern_return_t task_suspend(
1.1.1.4 root 678: task_t task)
1.1 root 679: {
1.1.1.4 root 680: boolean_t hold;
1.1 root 681:
682: if (task == TASK_NULL)
683: return KERN_INVALID_ARGUMENT;
684:
685: hold = FALSE;
686: task_lock(task);
687: if ((task->user_stop_count)++ == 0)
688: hold = TRUE;
689: task_unlock(task);
690:
691: /*
692: * If the stop count was positive, the task is
693: * already stopped and we can exit.
694: */
695: if (!hold) {
696: return KERN_SUCCESS;
697: }
698:
699: /*
700: * Hold all of the threads in the task, and wait for
701: * them to stop. If the current thread is within
702: * this task, hold it separately so that all of the
703: * other threads can stop first.
704: */
705:
706: if (task_hold(task) != KERN_SUCCESS)
707: return KERN_FAILURE;
708:
709: if (task_dowait(task, FALSE) != KERN_SUCCESS)
710: return KERN_FAILURE;
711:
712: if (current_task() == task) {
713: spl_t s;
714:
715: thread_hold(current_thread());
716: /*
717: * We want to call thread_block on our way out,
718: * to stop running.
719: */
720: s = splsched();
721: ast_on(cpu_number(), AST_BLOCK);
722: (void) splx(s);
723: }
724:
725: return KERN_SUCCESS;
726: }
727:
728: kern_return_t task_resume(
1.1.1.4 root 729: task_t task)
1.1 root 730: {
1.1.1.4 root 731: boolean_t release;
1.1 root 732:
733: if (task == TASK_NULL)
734: return KERN_INVALID_ARGUMENT;
735:
736: release = FALSE;
737: task_lock(task);
738: if (task->user_stop_count > 0) {
739: if (--(task->user_stop_count) == 0)
740: release = TRUE;
741: }
742: else {
743: task_unlock(task);
744: return KERN_FAILURE;
745: }
746: task_unlock(task);
747:
748: /*
749: * Release the task if necessary.
750: */
751: if (release)
752: return task_release(task);
753:
754: return KERN_SUCCESS;
755: }
756:
757: kern_return_t task_info(
758: task_t task,
759: int flavor,
760: task_info_t task_info_out, /* pointer to OUT array */
761: natural_t *task_info_count) /* IN/OUT */
762: {
763: vm_map_t map;
764:
765: if (task == TASK_NULL)
766: return KERN_INVALID_ARGUMENT;
767:
768: switch (flavor) {
769: case TASK_BASIC_INFO:
770: {
1.1.1.4 root 771: task_basic_info_t basic_info;
1.1 root 772:
1.1.1.2 root 773: /* Allow *task_info_count to be two words smaller than
774: the usual amount, because creation_time is a new member
775: that some callers might not know about. */
776:
777: if (*task_info_count < TASK_BASIC_INFO_COUNT - 2) {
1.1 root 778: return KERN_INVALID_ARGUMENT;
779: }
780:
781: basic_info = (task_basic_info_t) task_info_out;
782:
783: map = (task == kernel_task) ? kernel_map : task->map;
784:
785: basic_info->virtual_size = map->size;
786: basic_info->resident_size = pmap_resident_count(map->pmap)
787: * PAGE_SIZE;
788:
789: task_lock(task);
790: basic_info->base_priority = task->priority;
791: basic_info->suspend_count = task->user_stop_count;
792: basic_info->user_time.seconds
793: = task->total_user_time.seconds;
794: basic_info->user_time.microseconds
795: = task->total_user_time.microseconds;
796: basic_info->system_time.seconds
797: = task->total_system_time.seconds;
1.1.1.2 root 798: basic_info->system_time.microseconds
1.1 root 799: = task->total_system_time.microseconds;
1.1.1.5 root 800: read_time_stamp(&task->creation_time,
801: &basic_info->creation_time);
1.1 root 802: task_unlock(task);
803:
1.1.1.2 root 804: if (*task_info_count > TASK_BASIC_INFO_COUNT)
805: *task_info_count = TASK_BASIC_INFO_COUNT;
1.1 root 806: break;
807: }
808:
1.1.1.3 root 809: case TASK_EVENTS_INFO:
810: {
1.1.1.4 root 811: task_events_info_t event_info;
1.1.1.3 root 812:
813: if (*task_info_count < TASK_EVENTS_INFO_COUNT) {
814: return KERN_INVALID_ARGUMENT;
815: }
816:
817: event_info = (task_events_info_t) task_info_out;
818:
1.1.1.4 root 819: task_lock(task);
1.1.1.3 root 820: event_info->faults = task->faults;
821: event_info->zero_fills = task->zero_fills;
822: event_info->reactivations = task->reactivations;
823: event_info->pageins = task->pageins;
824: event_info->cow_faults = task->cow_faults;
825: event_info->messages_sent = task->messages_sent;
826: event_info->messages_received = task->messages_received;
1.1.1.4 root 827: task_unlock(task);
1.1.1.3 root 828:
829: *task_info_count = TASK_EVENTS_INFO_COUNT;
830: break;
831: }
832:
1.1 root 833: case TASK_THREAD_TIMES_INFO:
834: {
1.1.1.4 root 835: task_thread_times_info_t times_info;
836: thread_t thread;
1.1 root 837:
838: if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
839: return KERN_INVALID_ARGUMENT;
840: }
841:
842: times_info = (task_thread_times_info_t) task_info_out;
843: times_info->user_time.seconds = 0;
844: times_info->user_time.microseconds = 0;
845: times_info->system_time.seconds = 0;
846: times_info->system_time.microseconds = 0;
847:
848: task_lock(task);
849: queue_iterate(&task->thread_list, thread,
850: thread_t, thread_list)
851: {
852: time_value_t user_time, system_time;
853: spl_t s;
854:
855: s = splsched();
856: thread_lock(thread);
857:
858: thread_read_times(thread, &user_time, &system_time);
859:
860: thread_unlock(thread);
861: splx(s);
862:
863: time_value_add(×_info->user_time, &user_time);
864: time_value_add(×_info->system_time, &system_time);
865: }
866: task_unlock(task);
867:
868: *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
869: break;
870: }
871:
872: default:
873: return KERN_INVALID_ARGUMENT;
874: }
875:
876: return KERN_SUCCESS;
877: }
878:
879: #if MACH_HOST
880: /*
881: * task_assign:
882: *
883: * Change the assigned processor set for the task
884: */
885: kern_return_t
886: task_assign(
887: task_t task,
888: processor_set_t new_pset,
889: boolean_t assign_threads)
890: {
891: kern_return_t ret = KERN_SUCCESS;
1.1.1.4 root 892: thread_t thread, prev_thread;
893: queue_head_t *list;
894: processor_set_t pset;
1.1 root 895:
896: if (task == TASK_NULL || new_pset == PROCESSOR_SET_NULL) {
897: return KERN_INVALID_ARGUMENT;
898: }
899:
900: /*
901: * Freeze task`s assignment. Prelude to assigning
902: * task. Only one freeze may be held per task.
903: */
904:
905: task_lock(task);
906: while (task->may_assign == FALSE) {
907: task->assign_active = TRUE;
908: assert_wait((event_t)&task->assign_active, TRUE);
909: task_unlock(task);
1.1.1.5 root 910: thread_block(thread_no_continuation);
1.1 root 911: task_lock(task);
912: }
913:
914: /*
915: * Avoid work if task already in this processor set.
916: */
917: if (task->processor_set == new_pset) {
918: /*
919: * No need for task->assign_active wakeup:
920: * task->may_assign is still TRUE.
921: */
922: task_unlock(task);
923: return KERN_SUCCESS;
924: }
925:
926: task->may_assign = FALSE;
927: task_unlock(task);
928:
929: /*
930: * Safe to get the task`s pset: it cannot change while
931: * task is frozen.
932: */
933: pset = task->processor_set;
934:
935: /*
936: * Lock both psets now. Use ordering to avoid deadlock.
937: */
938: Restart:
939: if ((vm_offset_t) pset < (vm_offset_t) new_pset) {
940: pset_lock(pset);
941: pset_lock(new_pset);
942: }
943: else {
944: pset_lock(new_pset);
945: pset_lock(pset);
946: }
947:
948: /*
949: * Check if new_pset is ok to assign to. If not,
950: * reassign to default_pset.
951: */
952: if (!new_pset->active) {
953: pset_unlock(pset);
954: pset_unlock(new_pset);
955: new_pset = &default_pset;
956: goto Restart;
957: }
958:
959: pset_reference(new_pset);
960:
961: /*
962: * Now grab the task lock and move the task.
963: */
964:
965: task_lock(task);
966: pset_remove_task(pset, task);
967: pset_add_task(new_pset, task);
968:
969: pset_unlock(pset);
970: pset_unlock(new_pset);
971:
972: if (assign_threads == FALSE) {
973: /*
974: * We leave existing threads at their
975: * old assignments. Unfreeze task`s
976: * assignment.
977: */
978: task->may_assign = TRUE;
979: if (task->assign_active) {
980: task->assign_active = FALSE;
981: thread_wakeup((event_t) &task->assign_active);
982: }
983: task_unlock(task);
984: pset_deallocate(pset);
985: return KERN_SUCCESS;
986: }
987:
988: /*
989: * If current thread is in task, freeze its assignment.
990: */
991: if (current_thread()->task == task) {
992: task_unlock(task);
993: thread_freeze(current_thread());
994: task_lock(task);
995: }
996:
997: /*
998: * Iterate down the thread list reassigning all the threads.
999: * New threads pick up task's new processor set automatically.
1000: * Do current thread last because new pset may be empty.
1001: */
1002: list = &task->thread_list;
1003: prev_thread = THREAD_NULL;
1004: queue_iterate(list, thread, thread_t, thread_list) {
1005: if (!(task->active)) {
1006: ret = KERN_FAILURE;
1007: break;
1008: }
1009: if (thread != current_thread()) {
1010: thread_reference(thread);
1011: task_unlock(task);
1012: if (prev_thread != THREAD_NULL)
1013: thread_deallocate(prev_thread); /* may block */
1014: thread_assign(thread,new_pset); /* may block */
1015: prev_thread = thread;
1016: task_lock(task);
1017: }
1018: }
1019:
1020: /*
1021: * Done, wakeup anyone waiting for us.
1022: */
1023: task->may_assign = TRUE;
1024: if (task->assign_active) {
1025: task->assign_active = FALSE;
1026: thread_wakeup((event_t)&task->assign_active);
1027: }
1028: task_unlock(task);
1029: if (prev_thread != THREAD_NULL)
1030: thread_deallocate(prev_thread); /* may block */
1031:
1032: /*
1033: * Finish assignment of current thread.
1034: */
1035: if (current_thread()->task == task)
1036: thread_doassign(current_thread(), new_pset, TRUE);
1037:
1038: pset_deallocate(pset);
1039:
1040: return ret;
1041: }
1042: #else /* MACH_HOST */
1043: /*
1044: * task_assign:
1045: *
1046: * Change the assigned processor set for the task
1047: */
1048: kern_return_t
1049: task_assign(
1050: task_t task,
1051: processor_set_t new_pset,
1052: boolean_t assign_threads)
1053: {
1054: return KERN_FAILURE;
1055: }
1056: #endif /* MACH_HOST */
1.1.1.2 root 1057:
1.1 root 1058:
1059: /*
1060: * task_assign_default:
1061: *
1062: * Version of task_assign to assign to default processor set.
1063: */
1064: kern_return_t
1065: task_assign_default(
1066: task_t task,
1067: boolean_t assign_threads)
1068: {
1069: return task_assign(task, &default_pset, assign_threads);
1070: }
1071:
1072: /*
1073: * task_get_assignment
1074: *
1075: * Return name of processor set that task is assigned to.
1076: */
1077: kern_return_t task_get_assignment(
1078: task_t task,
1079: processor_set_t *pset)
1080: {
1.1.1.5 root 1081: if (task == TASK_NULL)
1082: return KERN_INVALID_ARGUMENT;
1083:
1.1 root 1084: if (!task->active)
1085: return KERN_FAILURE;
1086:
1087: *pset = task->processor_set;
1088: pset_reference(*pset);
1089: return KERN_SUCCESS;
1090: }
1091:
1092: /*
1093: * task_priority
1094: *
1095: * Set priority of task; used only for newly created threads.
1096: * Optionally change priorities of threads.
1097: */
1098: kern_return_t
1099: task_priority(
1100: task_t task,
1101: int priority,
1102: boolean_t change_threads)
1103: {
1104: kern_return_t ret = KERN_SUCCESS;
1105:
1106: if (task == TASK_NULL || invalid_pri(priority))
1107: return KERN_INVALID_ARGUMENT;
1108:
1109: task_lock(task);
1110: task->priority = priority;
1111:
1112: if (change_threads) {
1.1.1.4 root 1113: thread_t thread;
1114: queue_head_t *list;
1.1 root 1115:
1116: list = &task->thread_list;
1117: queue_iterate(list, thread, thread_t, thread_list) {
1118: if (thread_priority(thread, priority, FALSE)
1119: != KERN_SUCCESS)
1120: ret = KERN_FAILURE;
1121: }
1122: }
1123:
1124: task_unlock(task);
1125: return ret;
1126: }
1127:
1128: /*
1.1.1.4 root 1129: * task_set_name
1130: *
1131: * Set the name of task TASK to NAME. This is a debugging aid.
1132: * NAME will be used in error messages printed by the kernel.
1133: */
1134: kern_return_t
1135: task_set_name(
1136: task_t task,
1137: kernel_debug_name_t name)
1138: {
1139: strncpy(task->name, name, sizeof task->name - 1);
1140: task->name[sizeof task->name - 1] = '\0';
1141: return KERN_SUCCESS;
1142: }
1143:
1144: /*
1.1 root 1145: * task_collect_scan:
1146: *
1147: * Attempt to free resources owned by tasks.
1148: */
1149:
1150: void task_collect_scan(void)
1151: {
1.1.1.4 root 1152: task_t task, prev_task;
1.1 root 1153: processor_set_t pset, prev_pset;
1154:
1155: prev_task = TASK_NULL;
1156: prev_pset = PROCESSOR_SET_NULL;
1157:
1158: simple_lock(&all_psets_lock);
1159: queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
1160: pset_lock(pset);
1161: queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
1162: task_reference(task);
1163: pset_reference(pset);
1164: pset_unlock(pset);
1165: simple_unlock(&all_psets_lock);
1166:
1.1.1.3 root 1167: machine_task_collect (task);
1.1 root 1168: pmap_collect(task->map->pmap);
1169:
1170: if (prev_task != TASK_NULL)
1171: task_deallocate(prev_task);
1172: prev_task = task;
1173:
1174: if (prev_pset != PROCESSOR_SET_NULL)
1175: pset_deallocate(prev_pset);
1176: prev_pset = pset;
1177:
1178: simple_lock(&all_psets_lock);
1179: pset_lock(pset);
1180: }
1181: pset_unlock(pset);
1182: }
1183: simple_unlock(&all_psets_lock);
1184:
1185: if (prev_task != TASK_NULL)
1186: task_deallocate(prev_task);
1187: if (prev_pset != PROCESSOR_SET_NULL)
1188: pset_deallocate(prev_pset);
1189: }
1190:
1191: boolean_t task_collect_allowed = TRUE;
1192: unsigned task_collect_last_tick = 0;
1193: unsigned task_collect_max_rate = 0; /* in ticks */
1194:
1195: /*
1196: * consider_task_collect:
1197: *
1198: * Called by the pageout daemon when the system needs more free pages.
1199: */
1200:
1201: void consider_task_collect(void)
1202: {
1203: /*
1204: * By default, don't attempt task collection more frequently
1205: * than once a second.
1206: */
1207:
1208: if (task_collect_max_rate == 0)
1209: task_collect_max_rate = hz;
1210:
1211: if (task_collect_allowed &&
1212: (sched_tick > (task_collect_last_tick + task_collect_max_rate))) {
1213: task_collect_last_tick = sched_tick;
1214: task_collect_scan();
1215: }
1216: }
1217:
1218: kern_return_t
1219: task_ras_control(
1220: task_t task,
1221: vm_offset_t pc,
1222: vm_offset_t endpc,
1223: int flavor)
1224: {
1225: kern_return_t ret = KERN_FAILURE;
1.1.1.2 root 1226:
1.1 root 1227: #if FAST_TAS
1228: int i;
1229:
1230: ret = KERN_SUCCESS;
1231: task_lock(task);
1232: switch (flavor) {
1233: case TASK_RAS_CONTROL_PURGE_ALL: /* remove all RAS */
1234: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
1235: task->fast_tas_base[i] = task->fast_tas_end[i] = 0;
1236: }
1237: break;
1238: case TASK_RAS_CONTROL_PURGE_ONE: /* remove this RAS, collapse remaining */
1239: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
1240: if ( (task->fast_tas_base[i] == pc)
1241: && (task->fast_tas_end[i] == endpc)) {
1242: while (i < TASK_FAST_TAS_NRAS-1) {
1243: task->fast_tas_base[i] = task->fast_tas_base[i+1];
1244: task->fast_tas_end[i] = task->fast_tas_end[i+1];
1245: i++;
1246: }
1247: task->fast_tas_base[TASK_FAST_TAS_NRAS-1] = 0;
1248: task->fast_tas_end[TASK_FAST_TAS_NRAS-1] = 0;
1249: break;
1250: }
1251: }
1252: if (i == TASK_FAST_TAS_NRAS) {
1253: ret = KERN_INVALID_ADDRESS;
1254: }
1255: break;
1.1.1.2 root 1256: case TASK_RAS_CONTROL_PURGE_ALL_AND_INSTALL_ONE:
1.1 root 1257: /* remove all RAS an install this RAS */
1258: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
1259: task->fast_tas_base[i] = task->fast_tas_end[i] = 0;
1260: }
1261: /* FALL THROUGH */
1262: case TASK_RAS_CONTROL_INSTALL_ONE: /* install this RAS */
1263: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
1264: if ( (task->fast_tas_base[i] == pc)
1265: && (task->fast_tas_end[i] == endpc)) {
1266: /* already installed */
1267: break;
1268: }
1269: if ((task->fast_tas_base[i] == 0) && (task->fast_tas_end[i] == 0)){
1270: task->fast_tas_base[i] = pc;
1271: task->fast_tas_end[i] = endpc;
1272: break;
1273: }
1274: }
1275: if (i == TASK_FAST_TAS_NRAS) {
1276: ret = KERN_RESOURCE_SHORTAGE;
1.1.1.2 root 1277: }
1.1 root 1278: break;
1279: default: ret = KERN_INVALID_VALUE;
1280: break;
1281: }
1282: task_unlock(task);
1.1.1.4 root 1283: #endif /* FAST_TAS */
1.1 root 1284: return ret;
1285: }
1.1.1.4 root 1286:
1287: /*
1288: * register_new_task_notification
1289: *
1290: * Register a port to which a notification about newly created
1291: * tasks are sent.
1292: */
1293: kern_return_t
1294: register_new_task_notification(
1295: const host_t host,
1296: ipc_port_t notification)
1297: {
1298: if (host == HOST_NULL)
1299: return KERN_INVALID_HOST;
1300:
1301: if (new_task_notification != NULL)
1302: return KERN_NO_ACCESS;
1303:
1304: new_task_notification = notification;
1305: return KERN_SUCCESS;
1306: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.