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