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