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