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