|
|
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.1.5 ! root 92: if (new_task == TASK_NULL)
! 93: return KERN_RESOURCE_SHORTAGE;
1.1 root 94:
95: /* one ref for just being alive; one for our caller */
96: new_task->ref_count = 2;
97:
98: if (child_task == &kernel_task) {
1.1.1.2 root 99: new_task->map = kernel_map;
1.1 root 100: } else if (inherit_memory) {
101: new_task->map = vm_map_fork(parent_task->map);
102: } else {
103: new_task->map = vm_map_create(pmap_create(0),
104: round_page(VM_MIN_ADDRESS),
105: trunc_page(VM_MAX_ADDRESS), TRUE);
106: }
107:
108: simple_lock_init(&new_task->lock);
109: queue_init(&new_task->thread_list);
110: new_task->suspend_count = 0;
111: new_task->active = TRUE;
112: new_task->user_stop_count = 0;
113: new_task->thread_count = 0;
1.1.1.3 root 114: new_task->faults = 0;
115: new_task->zero_fills = 0;
116: new_task->reactivations = 0;
117: new_task->pageins = 0;
118: new_task->cow_faults = 0;
119: new_task->messages_sent = 0;
120: new_task->messages_received = 0;
1.1 root 121:
122: eml_task_reference(new_task, parent_task);
123:
124: ipc_task_init(new_task, parent_task);
1.1.1.3 root 125: machine_task_init (new_task);
1.1 root 126:
127: new_task->total_user_time.seconds = 0;
128: new_task->total_user_time.microseconds = 0;
129: new_task->total_system_time.seconds = 0;
130: new_task->total_system_time.microseconds = 0;
131:
1.1.1.2 root 132: record_time_stamp (&new_task->creation_time);
133:
1.1 root 134: if (parent_task != TASK_NULL) {
135: task_lock(parent_task);
136: pset = parent_task->processor_set;
137: if (!pset->active)
138: pset = &default_pset;
139: pset_reference(pset);
140: new_task->priority = parent_task->priority;
141: task_unlock(parent_task);
142: }
143: else {
144: pset = &default_pset;
145: pset_reference(pset);
146: new_task->priority = BASEPRI_USER;
147: }
148: pset_lock(pset);
149: pset_add_task(pset, new_task);
150: pset_unlock(pset);
151:
152: new_task->may_assign = TRUE;
153: new_task->assign_active = FALSE;
154:
155: #if MACH_PCSAMPLE
156: new_task->pc_sample.buffer = 0;
157: new_task->pc_sample.seqno = 0;
158: new_task->pc_sample.sampletypes = 0;
159: #endif /* MACH_PCSAMPLE */
160:
161: #if FAST_TAS
162: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
163: if (inherit_memory) {
164: new_task->fast_tas_base[i] = parent_task->fast_tas_base[i];
165: new_task->fast_tas_end[i] = parent_task->fast_tas_end[i];
166: } else {
167: new_task->fast_tas_base[i] = (vm_offset_t)0;
168: new_task->fast_tas_end[i] = (vm_offset_t)0;
169: }
170: }
171: #endif /* FAST_TAS */
1.1.1.2 root 172:
1.1.1.4 root 173: if (parent_task == TASK_NULL)
174: snprintf (new_task->name, sizeof new_task->name, "%p",
175: new_task);
176: else
177: snprintf (new_task->name, sizeof new_task->name, "(%.*s)",
178: sizeof new_task->name - 3, parent_task->name);
179:
180: if (new_task_notification != NULL) {
181: task_reference (new_task);
182: task_reference (parent_task);
183: mach_notify_new_task (new_task_notification,
184: convert_task_to_port (new_task),
185: convert_task_to_port (parent_task));
186: }
187:
1.1 root 188: ipc_task_enable(new_task);
189:
190: *child_task = new_task;
191: return KERN_SUCCESS;
192: }
193:
194: /*
195: * task_deallocate:
196: *
197: * Give up a reference to the specified task and destroy it if there
198: * are no other references left. It is assumed that the current thread
199: * is never in this task.
200: */
201: void task_deallocate(
1.1.1.4 root 202: task_t task)
1.1 root 203: {
1.1.1.4 root 204: int c;
205: processor_set_t pset;
1.1 root 206:
207: if (task == TASK_NULL)
208: return;
209:
210: task_lock(task);
211: c = --(task->ref_count);
212: task_unlock(task);
213: if (c != 0)
214: return;
215:
1.1.1.3 root 216: machine_task_terminate (task);
1.1 root 217:
218: eml_task_deallocate(task);
219:
220: pset = task->processor_set;
221: pset_lock(pset);
222: pset_remove_task(pset,task);
223: pset_unlock(pset);
224: pset_deallocate(pset);
225: vm_map_deallocate(task->map);
226: is_release(task->itk_space);
1.1.1.3 root 227: kmem_cache_free(&task_cache, (vm_offset_t) task);
1.1 root 228: }
229:
230: void task_reference(
1.1.1.4 root 231: task_t task)
1.1 root 232: {
233: if (task == TASK_NULL)
234: return;
235:
236: task_lock(task);
237: task->ref_count++;
238: task_unlock(task);
239: }
240:
241: /*
242: * task_terminate:
243: *
244: * Terminate the specified task. See comments on thread_terminate
245: * (kern/thread.c) about problems with terminating the "current task."
246: */
247: kern_return_t task_terminate(
1.1.1.4 root 248: task_t task)
1.1 root 249: {
1.1.1.4 root 250: thread_t thread, cur_thread;
251: queue_head_t *list;
252: task_t cur_task;
1.1 root 253: spl_t s;
254:
255: if (task == TASK_NULL)
256: return KERN_INVALID_ARGUMENT;
257:
258: list = &task->thread_list;
259: cur_task = current_task();
260: cur_thread = current_thread();
261:
262: /*
263: * Deactivate task so that it can't be terminated again,
264: * and so lengthy operations in progress will abort.
265: *
266: * If the current thread is in this task, remove it from
267: * the task's thread list to keep the thread-termination
268: * loop simple.
269: */
270: if (task == cur_task) {
271: task_lock(task);
272: if (!task->active) {
273: /*
274: * Task is already being terminated.
275: */
276: task_unlock(task);
277: return KERN_FAILURE;
278: }
279: /*
280: * Make sure current thread is not being terminated.
281: */
282: s = splsched();
283: thread_lock(cur_thread);
284: if (!cur_thread->active) {
285: thread_unlock(cur_thread);
286: (void) splx(s);
287: task_unlock(task);
288: thread_terminate(cur_thread);
289: return KERN_FAILURE;
290: }
1.1.1.4 root 291: task_hold_locked(task);
1.1 root 292: task->active = FALSE;
293: queue_remove(list, cur_thread, thread_t, thread_list);
294: thread_unlock(cur_thread);
295: (void) splx(s);
296: task_unlock(task);
297:
298: /*
299: * Shut down this thread's ipc now because it must
300: * be left alone to terminate the task.
301: */
302: ipc_thread_disable(cur_thread);
303: ipc_thread_terminate(cur_thread);
304: }
305: else {
306: /*
307: * Lock both current and victim task to check for
308: * potential deadlock.
309: */
310: if ((vm_offset_t)task < (vm_offset_t)cur_task) {
311: task_lock(task);
312: task_lock(cur_task);
313: }
314: else {
315: task_lock(cur_task);
316: task_lock(task);
317: }
318: /*
319: * Check if current thread or task is being terminated.
320: */
321: s = splsched();
322: thread_lock(cur_thread);
323: if ((!cur_task->active) ||(!cur_thread->active)) {
324: /*
325: * Current task or thread is being terminated.
326: */
327: thread_unlock(cur_thread);
328: (void) splx(s);
329: task_unlock(task);
330: task_unlock(cur_task);
331: thread_terminate(cur_thread);
332: return KERN_FAILURE;
333: }
334: thread_unlock(cur_thread);
335: (void) splx(s);
336: task_unlock(cur_task);
337:
338: if (!task->active) {
339: /*
340: * Task is already being terminated.
341: */
342: task_unlock(task);
343: return KERN_FAILURE;
344: }
1.1.1.4 root 345: task_hold_locked(task);
1.1 root 346: task->active = FALSE;
347: task_unlock(task);
348: }
349:
350: /*
351: * Prevent further execution of the task. ipc_task_disable
352: * prevents further task operations via the task port.
353: * If this is the current task, the current thread will
354: * be left running.
355: */
356: (void) task_dowait(task,TRUE); /* may block */
1.1.1.4 root 357: ipc_task_disable(task);
1.1 root 358:
359: /*
360: * Terminate each thread in the task.
361: *
362: * The task_port is closed down, so no more thread_create
363: * operations can be done. Thread_force_terminate closes the
364: * thread port for each thread; when that is done, the
365: * thread will eventually disappear. Thus the loop will
366: * terminate. Call thread_force_terminate instead of
367: * thread_terminate to avoid deadlock checks. Need
368: * to call thread_block() inside loop because some other
369: * thread (e.g., the reaper) may have to run to get rid
370: * of all references to the thread; it won't vanish from
371: * the task's thread list until the last one is gone.
372: */
373: task_lock(task);
374: while (!queue_empty(list)) {
375: thread = (thread_t) queue_first(list);
376: thread_reference(thread);
377: task_unlock(task);
378: thread_force_terminate(thread);
379: thread_deallocate(thread);
1.1.1.5 ! root 380: thread_block(thread_no_continuation);
1.1 root 381: task_lock(task);
382: }
383: task_unlock(task);
384:
385: /*
386: * Shut down IPC.
387: */
388: ipc_task_terminate(task);
389:
390:
391: /*
392: * Deallocate the task's reference to itself.
393: */
394: task_deallocate(task);
395:
396: /*
397: * If the current thread is in this task, it has not yet
398: * been terminated (since it was removed from the task's
399: * thread-list). Put it back in the thread list (for
400: * completeness), and terminate it. Since it holds the
401: * last reference to the task, terminating it will deallocate
402: * the task.
403: */
404: if (cur_thread->task == task) {
405: task_lock(task);
406: s = splsched();
407: queue_enter(list, cur_thread, thread_t, thread_list);
408: (void) splx(s);
409: task_unlock(task);
410: (void) thread_terminate(cur_thread);
411: }
412:
413: return KERN_SUCCESS;
414: }
415:
416: /*
417: * task_hold:
418: *
419: * Suspend execution of the specified task.
420: * This is a recursive-style suspension of the task, a count of
421: * suspends is maintained.
1.1.1.4 root 422: *
423: * CONDITIONS: the task is locked and active.
1.1 root 424: */
1.1.1.4 root 425: void task_hold_locked(
426: task_t task)
1.1 root 427: {
1.1.1.4 root 428: queue_head_t *list;
429: thread_t thread, cur_thread;
1.1 root 430:
1.1.1.4 root 431: assert(task->active);
1.1 root 432:
1.1.1.4 root 433: cur_thread = current_thread();
1.1 root 434:
435: task->suspend_count++;
436:
437: /*
438: * Iterate through all the threads and hold them.
439: * Do not hold the current thread if it is within the
440: * task.
441: */
442: list = &task->thread_list;
443: queue_iterate(list, thread, thread_t, thread_list) {
444: if (thread != cur_thread)
445: thread_hold(thread);
446: }
1.1.1.4 root 447: }
448:
449: /*
450: * task_hold:
451: *
452: * Suspend execution of the specified task.
453: * This is a recursive-style suspension of the task, a count of
454: * suspends is maintained.
455: */
456: kern_return_t task_hold(
457: task_t task)
458: {
459: task_lock(task);
460: if (!task->active) {
461: task_unlock(task);
462: return KERN_FAILURE;
463: }
464:
465: task_hold_locked(task);
466:
1.1 root 467: task_unlock(task);
468: return KERN_SUCCESS;
469: }
470:
471: /*
472: * task_dowait:
473: *
474: * Wait until the task has really been suspended (all of the threads
475: * are stopped). Skip the current thread if it is within the task.
476: *
477: * If task is deactivated while waiting, return a failure code unless
478: * must_wait is true.
479: */
480: kern_return_t task_dowait(
1.1.1.4 root 481: task_t task,
1.1 root 482: boolean_t must_wait)
483: {
1.1.1.4 root 484: queue_head_t *list;
485: thread_t thread, cur_thread, prev_thread;
486: kern_return_t ret = KERN_SUCCESS;
1.1 root 487:
488: /*
489: * Iterate through all the threads.
490: * While waiting for each thread, we gain a reference to it
491: * to prevent it from going away on us. This guarantees
492: * that the "next" thread in the list will be a valid thread.
493: *
494: * We depend on the fact that if threads are created while
495: * we are looping through the threads, they will be held
496: * automatically. We don't care about threads that get
497: * deallocated along the way (the reference prevents it
498: * from happening to the thread we are working with).
499: *
500: * If the current thread is in the affected task, it is skipped.
501: *
502: * If the task is deactivated before we're done, and we don't
503: * have to wait for it (must_wait is FALSE), just bail out.
504: */
505: cur_thread = current_thread();
506:
507: list = &task->thread_list;
508: prev_thread = THREAD_NULL;
509: task_lock(task);
510: queue_iterate(list, thread, thread_t, thread_list) {
511: if (!(task->active) && !(must_wait)) {
512: ret = KERN_FAILURE;
513: break;
514: }
515: if (thread != cur_thread) {
516: thread_reference(thread);
517: task_unlock(task);
518: if (prev_thread != THREAD_NULL)
519: thread_deallocate(prev_thread);
520: /* may block */
521: (void) thread_dowait(thread, TRUE); /* may block */
522: prev_thread = thread;
523: task_lock(task);
524: }
525: }
526: task_unlock(task);
527: if (prev_thread != THREAD_NULL)
528: thread_deallocate(prev_thread); /* may block */
529: return ret;
530: }
531:
532: kern_return_t task_release(
1.1.1.4 root 533: task_t task)
1.1 root 534: {
1.1.1.4 root 535: queue_head_t *list;
536: thread_t thread, next;
1.1 root 537:
538: task_lock(task);
539: if (!task->active) {
540: task_unlock(task);
541: return KERN_FAILURE;
542: }
543:
544: task->suspend_count--;
545:
546: /*
547: * Iterate through all the threads and release them
548: */
549: list = &task->thread_list;
550: thread = (thread_t) queue_first(list);
551: while (!queue_end(list, (queue_entry_t) thread)) {
552: next = (thread_t) queue_next(&thread->thread_list);
553: thread_release(thread);
554: thread = next;
555: }
556: task_unlock(task);
557: return KERN_SUCCESS;
558: }
559:
560: kern_return_t task_threads(
561: task_t task,
562: thread_array_t *thread_list,
563: natural_t *count)
564: {
565: unsigned int actual; /* this many threads */
566: thread_t thread;
567: thread_t *threads;
568: int i;
569:
570: vm_size_t size, size_needed;
571: vm_offset_t addr;
572:
573: if (task == TASK_NULL)
574: return KERN_INVALID_ARGUMENT;
575:
576: size = 0; addr = 0;
577:
578: for (;;) {
579: task_lock(task);
580: if (!task->active) {
581: task_unlock(task);
582: return KERN_FAILURE;
583: }
584:
585: actual = task->thread_count;
586:
587: /* do we have the memory we need? */
588:
589: size_needed = actual * sizeof(mach_port_t);
590: if (size_needed <= size)
591: break;
592:
593: /* unlock the task and allocate more memory */
594: task_unlock(task);
595:
596: if (size != 0)
597: kfree(addr, size);
598:
599: assert(size_needed > 0);
600: size = size_needed;
601:
602: addr = kalloc(size);
603: if (addr == 0)
604: return KERN_RESOURCE_SHORTAGE;
605: }
606:
607: /* OK, have memory and the task is locked & active */
608:
609: threads = (thread_t *) addr;
610:
611: for (i = 0, thread = (thread_t) queue_first(&task->thread_list);
612: i < actual;
613: i++, thread = (thread_t) queue_next(&thread->thread_list)) {
614: /* take ref for convert_thread_to_port */
615: thread_reference(thread);
616: threads[i] = thread;
617: }
618: assert(queue_end(&task->thread_list, (queue_entry_t) thread));
619:
620: /* can unlock task now that we've got the thread refs */
621: task_unlock(task);
622:
623: if (actual == 0) {
624: /* no threads, so return null pointer and deallocate memory */
625:
626: *thread_list = 0;
627: *count = 0;
628:
629: if (size != 0)
630: kfree(addr, size);
631: } else {
632: /* if we allocated too much, must copy */
633:
634: if (size_needed < size) {
635: vm_offset_t newaddr;
636:
637: newaddr = kalloc(size_needed);
638: if (newaddr == 0) {
639: for (i = 0; i < actual; i++)
640: thread_deallocate(threads[i]);
641: kfree(addr, size);
642: return KERN_RESOURCE_SHORTAGE;
643: }
644:
1.1.1.3 root 645: memcpy((void *) newaddr, (void *) addr, size_needed);
1.1 root 646: kfree(addr, size);
647: threads = (thread_t *) newaddr;
648: }
649:
650: *thread_list = (mach_port_t *) threads;
651: *count = actual;
652:
653: /* do the conversion that Mig should handle */
654:
655: for (i = 0; i < actual; i++)
656: ((ipc_port_t *) threads)[i] =
657: convert_thread_to_port(threads[i]);
658: }
659:
660: return KERN_SUCCESS;
661: }
662:
663: kern_return_t task_suspend(
1.1.1.4 root 664: task_t task)
1.1 root 665: {
1.1.1.4 root 666: boolean_t hold;
1.1 root 667:
668: if (task == TASK_NULL)
669: return KERN_INVALID_ARGUMENT;
670:
671: hold = FALSE;
672: task_lock(task);
673: if ((task->user_stop_count)++ == 0)
674: hold = TRUE;
675: task_unlock(task);
676:
677: /*
678: * If the stop count was positive, the task is
679: * already stopped and we can exit.
680: */
681: if (!hold) {
682: return KERN_SUCCESS;
683: }
684:
685: /*
686: * Hold all of the threads in the task, and wait for
687: * them to stop. If the current thread is within
688: * this task, hold it separately so that all of the
689: * other threads can stop first.
690: */
691:
692: if (task_hold(task) != KERN_SUCCESS)
693: return KERN_FAILURE;
694:
695: if (task_dowait(task, FALSE) != KERN_SUCCESS)
696: return KERN_FAILURE;
697:
698: if (current_task() == task) {
699: spl_t s;
700:
701: thread_hold(current_thread());
702: /*
703: * We want to call thread_block on our way out,
704: * to stop running.
705: */
706: s = splsched();
707: ast_on(cpu_number(), AST_BLOCK);
708: (void) splx(s);
709: }
710:
711: return KERN_SUCCESS;
712: }
713:
714: kern_return_t task_resume(
1.1.1.4 root 715: task_t task)
1.1 root 716: {
1.1.1.4 root 717: boolean_t release;
1.1 root 718:
719: if (task == TASK_NULL)
720: return KERN_INVALID_ARGUMENT;
721:
722: release = FALSE;
723: task_lock(task);
724: if (task->user_stop_count > 0) {
725: if (--(task->user_stop_count) == 0)
726: release = TRUE;
727: }
728: else {
729: task_unlock(task);
730: return KERN_FAILURE;
731: }
732: task_unlock(task);
733:
734: /*
735: * Release the task if necessary.
736: */
737: if (release)
738: return task_release(task);
739:
740: return KERN_SUCCESS;
741: }
742:
743: kern_return_t task_info(
744: task_t task,
745: int flavor,
746: task_info_t task_info_out, /* pointer to OUT array */
747: natural_t *task_info_count) /* IN/OUT */
748: {
749: vm_map_t map;
750:
751: if (task == TASK_NULL)
752: return KERN_INVALID_ARGUMENT;
753:
754: switch (flavor) {
755: case TASK_BASIC_INFO:
756: {
1.1.1.4 root 757: task_basic_info_t basic_info;
1.1 root 758:
1.1.1.2 root 759: /* Allow *task_info_count to be two words smaller than
760: the usual amount, because creation_time is a new member
761: that some callers might not know about. */
762:
763: if (*task_info_count < TASK_BASIC_INFO_COUNT - 2) {
1.1 root 764: return KERN_INVALID_ARGUMENT;
765: }
766:
767: basic_info = (task_basic_info_t) task_info_out;
768:
769: map = (task == kernel_task) ? kernel_map : task->map;
770:
771: basic_info->virtual_size = map->size;
772: basic_info->resident_size = pmap_resident_count(map->pmap)
773: * PAGE_SIZE;
774:
775: task_lock(task);
776: basic_info->base_priority = task->priority;
777: basic_info->suspend_count = task->user_stop_count;
778: basic_info->user_time.seconds
779: = task->total_user_time.seconds;
780: basic_info->user_time.microseconds
781: = task->total_user_time.microseconds;
782: basic_info->system_time.seconds
783: = task->total_system_time.seconds;
1.1.1.2 root 784: basic_info->system_time.microseconds
1.1 root 785: = task->total_system_time.microseconds;
1.1.1.5 ! root 786: read_time_stamp(&task->creation_time,
! 787: &basic_info->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);
1.1.1.5 ! root 896: thread_block(thread_no_continuation);
1.1 root 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: {
1.1.1.5 ! root 1067: if (task == TASK_NULL)
! 1068: return KERN_INVALID_ARGUMENT;
! 1069:
1.1 root 1070: if (!task->active)
1071: return KERN_FAILURE;
1072:
1073: *pset = task->processor_set;
1074: pset_reference(*pset);
1075: return KERN_SUCCESS;
1076: }
1077:
1078: /*
1079: * task_priority
1080: *
1081: * Set priority of task; used only for newly created threads.
1082: * Optionally change priorities of threads.
1083: */
1084: kern_return_t
1085: task_priority(
1086: task_t task,
1087: int priority,
1088: boolean_t change_threads)
1089: {
1090: kern_return_t ret = KERN_SUCCESS;
1091:
1092: if (task == TASK_NULL || invalid_pri(priority))
1093: return KERN_INVALID_ARGUMENT;
1094:
1095: task_lock(task);
1096: task->priority = priority;
1097:
1098: if (change_threads) {
1.1.1.4 root 1099: thread_t thread;
1100: queue_head_t *list;
1.1 root 1101:
1102: list = &task->thread_list;
1103: queue_iterate(list, thread, thread_t, thread_list) {
1104: if (thread_priority(thread, priority, FALSE)
1105: != KERN_SUCCESS)
1106: ret = KERN_FAILURE;
1107: }
1108: }
1109:
1110: task_unlock(task);
1111: return ret;
1112: }
1113:
1114: /*
1.1.1.4 root 1115: * task_set_name
1116: *
1117: * Set the name of task TASK to NAME. This is a debugging aid.
1118: * NAME will be used in error messages printed by the kernel.
1119: */
1120: kern_return_t
1121: task_set_name(
1122: task_t task,
1123: kernel_debug_name_t name)
1124: {
1125: strncpy(task->name, name, sizeof task->name - 1);
1126: task->name[sizeof task->name - 1] = '\0';
1127: return KERN_SUCCESS;
1128: }
1129:
1130: /*
1.1 root 1131: * task_collect_scan:
1132: *
1133: * Attempt to free resources owned by tasks.
1134: */
1135:
1136: void task_collect_scan(void)
1137: {
1.1.1.4 root 1138: task_t task, prev_task;
1.1 root 1139: processor_set_t pset, prev_pset;
1140:
1141: prev_task = TASK_NULL;
1142: prev_pset = PROCESSOR_SET_NULL;
1143:
1144: simple_lock(&all_psets_lock);
1145: queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
1146: pset_lock(pset);
1147: queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
1148: task_reference(task);
1149: pset_reference(pset);
1150: pset_unlock(pset);
1151: simple_unlock(&all_psets_lock);
1152:
1.1.1.3 root 1153: machine_task_collect (task);
1.1 root 1154: pmap_collect(task->map->pmap);
1155:
1156: if (prev_task != TASK_NULL)
1157: task_deallocate(prev_task);
1158: prev_task = task;
1159:
1160: if (prev_pset != PROCESSOR_SET_NULL)
1161: pset_deallocate(prev_pset);
1162: prev_pset = pset;
1163:
1164: simple_lock(&all_psets_lock);
1165: pset_lock(pset);
1166: }
1167: pset_unlock(pset);
1168: }
1169: simple_unlock(&all_psets_lock);
1170:
1171: if (prev_task != TASK_NULL)
1172: task_deallocate(prev_task);
1173: if (prev_pset != PROCESSOR_SET_NULL)
1174: pset_deallocate(prev_pset);
1175: }
1176:
1177: boolean_t task_collect_allowed = TRUE;
1178: unsigned task_collect_last_tick = 0;
1179: unsigned task_collect_max_rate = 0; /* in ticks */
1180:
1181: /*
1182: * consider_task_collect:
1183: *
1184: * Called by the pageout daemon when the system needs more free pages.
1185: */
1186:
1187: void consider_task_collect(void)
1188: {
1189: /*
1190: * By default, don't attempt task collection more frequently
1191: * than once a second.
1192: */
1193:
1194: if (task_collect_max_rate == 0)
1195: task_collect_max_rate = hz;
1196:
1197: if (task_collect_allowed &&
1198: (sched_tick > (task_collect_last_tick + task_collect_max_rate))) {
1199: task_collect_last_tick = sched_tick;
1200: task_collect_scan();
1201: }
1202: }
1203:
1204: kern_return_t
1205: task_ras_control(
1206: task_t task,
1207: vm_offset_t pc,
1208: vm_offset_t endpc,
1209: int flavor)
1210: {
1211: kern_return_t ret = KERN_FAILURE;
1.1.1.2 root 1212:
1.1 root 1213: #if FAST_TAS
1214: int i;
1215:
1216: ret = KERN_SUCCESS;
1217: task_lock(task);
1218: switch (flavor) {
1219: case TASK_RAS_CONTROL_PURGE_ALL: /* remove all RAS */
1220: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
1221: task->fast_tas_base[i] = task->fast_tas_end[i] = 0;
1222: }
1223: break;
1224: case TASK_RAS_CONTROL_PURGE_ONE: /* remove this RAS, collapse remaining */
1225: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
1226: if ( (task->fast_tas_base[i] == pc)
1227: && (task->fast_tas_end[i] == endpc)) {
1228: while (i < TASK_FAST_TAS_NRAS-1) {
1229: task->fast_tas_base[i] = task->fast_tas_base[i+1];
1230: task->fast_tas_end[i] = task->fast_tas_end[i+1];
1231: i++;
1232: }
1233: task->fast_tas_base[TASK_FAST_TAS_NRAS-1] = 0;
1234: task->fast_tas_end[TASK_FAST_TAS_NRAS-1] = 0;
1235: break;
1236: }
1237: }
1238: if (i == TASK_FAST_TAS_NRAS) {
1239: ret = KERN_INVALID_ADDRESS;
1240: }
1241: break;
1.1.1.2 root 1242: case TASK_RAS_CONTROL_PURGE_ALL_AND_INSTALL_ONE:
1.1 root 1243: /* remove all RAS an install this RAS */
1244: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
1245: task->fast_tas_base[i] = task->fast_tas_end[i] = 0;
1246: }
1247: /* FALL THROUGH */
1248: case TASK_RAS_CONTROL_INSTALL_ONE: /* install this RAS */
1249: for (i = 0; i < TASK_FAST_TAS_NRAS; i++) {
1250: if ( (task->fast_tas_base[i] == pc)
1251: && (task->fast_tas_end[i] == endpc)) {
1252: /* already installed */
1253: break;
1254: }
1255: if ((task->fast_tas_base[i] == 0) && (task->fast_tas_end[i] == 0)){
1256: task->fast_tas_base[i] = pc;
1257: task->fast_tas_end[i] = endpc;
1258: break;
1259: }
1260: }
1261: if (i == TASK_FAST_TAS_NRAS) {
1262: ret = KERN_RESOURCE_SHORTAGE;
1.1.1.2 root 1263: }
1.1 root 1264: break;
1265: default: ret = KERN_INVALID_VALUE;
1266: break;
1267: }
1268: task_unlock(task);
1.1.1.4 root 1269: #endif /* FAST_TAS */
1.1 root 1270: return ret;
1271: }
1.1.1.4 root 1272:
1273: /*
1274: * register_new_task_notification
1275: *
1276: * Register a port to which a notification about newly created
1277: * tasks are sent.
1278: */
1279: kern_return_t
1280: register_new_task_notification(
1281: const host_t host,
1282: ipc_port_t notification)
1283: {
1284: if (host == HOST_NULL)
1285: return KERN_INVALID_HOST;
1286:
1287: if (new_task_notification != NULL)
1288: return KERN_NO_ACCESS;
1289:
1290: new_task_notification = notification;
1291: return KERN_SUCCESS;
1292: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.