|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1994-1987 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/thread.c
28: * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub
29: * Date: 1986
30: *
31: * Thread management primitives implementation.
32: */
33:
1.1.1.4 root 34: #include <kern/printf.h>
1.1 root 35: #include <mach/std_types.h>
36: #include <mach/policy.h>
37: #include <mach/thread_info.h>
38: #include <mach/thread_special_ports.h>
39: #include <mach/thread_status.h>
40: #include <mach/time_value.h>
1.1.1.4 root 41: #include <machine/vm_param.h>
1.1 root 42: #include <kern/ast.h>
43: #include <kern/counters.h>
1.1.1.4 root 44: #include <kern/debug.h>
45: #include <kern/eventcount.h>
46: #include <kern/ipc_mig.h>
1.1 root 47: #include <kern/ipc_tt.h>
48: #include <kern/processor.h>
49: #include <kern/queue.h>
50: #include <kern/sched.h>
51: #include <kern/sched_prim.h>
1.1.1.4 root 52: #include <kern/syscall_subr.h>
1.1 root 53: #include <kern/thread.h>
54: #include <kern/thread_swap.h>
55: #include <kern/host.h>
1.1.1.4 root 56: #include <kern/kalloc.h>
57: #include <kern/slab.h>
58: #include <kern/mach_clock.h>
1.1 root 59: #include <vm/vm_kern.h>
1.1.1.5 ! root 60: #include <vm/vm_user.h>
1.1 root 61: #include <ipc/ipc_kmsg.h>
62: #include <ipc/ipc_port.h>
63: #include <ipc/mach_msg.h>
1.1.1.5 ! root 64: #include <ipc/mach_port.h>
1.1 root 65: #include <machine/machspl.h> /* for splsched */
1.1.1.4 root 66: #include <machine/pcb.h>
1.1 root 67: #include <machine/thread.h> /* for MACHINE_STACK */
68:
69: thread_t active_threads[NCPUS];
70: vm_offset_t active_stacks[NCPUS];
71:
1.1.1.4 root 72: struct kmem_cache thread_cache;
1.1 root 73:
74: queue_head_t reaper_queue;
75: decl_simple_lock_data(, reaper_lock)
76:
77: /* private */
78: struct thread thread_template;
79:
80: #if MACH_DEBUG
81: #define STACK_MARKER 0xdeadbeefU
82: boolean_t stack_check_usage = FALSE;
83: decl_simple_lock_data(, stack_usage_lock)
84: vm_size_t stack_max_usage = 0;
85: #endif /* MACH_DEBUG */
86:
87: /*
88: * Machine-dependent code must define:
89: * pcb_init
90: * pcb_terminate
91: * pcb_collect
92: *
93: * The thread->pcb field is reserved for machine-dependent code.
94: */
95:
96: #ifdef MACHINE_STACK
97: /*
98: * Machine-dependent code must define:
99: * stack_alloc_try
100: * stack_alloc
101: * stack_free
102: * stack_handoff
103: * stack_collect
104: * and if MACH_DEBUG:
105: * stack_statistics
106: */
107: #else /* MACHINE_STACK */
108: /*
109: * We allocate stacks from generic kernel VM.
110: * Machine-dependent code must define:
111: * stack_attach
112: * stack_detach
113: * stack_handoff
114: *
115: * The stack_free_list can only be accessed at splsched,
116: * because stack_alloc_try/thread_invoke operate at splsched.
117: */
118:
119: decl_simple_lock_data(, stack_lock_data)/* splsched only */
120: #define stack_lock() simple_lock(&stack_lock_data)
121: #define stack_unlock() simple_unlock(&stack_lock_data)
122:
123: vm_offset_t stack_free_list; /* splsched only */
124: unsigned int stack_free_count = 0; /* splsched only */
125: unsigned int stack_free_limit = 1; /* patchable */
126:
127: unsigned int stack_alloc_hits = 0; /* debugging */
128: unsigned int stack_alloc_misses = 0; /* debugging */
129: unsigned int stack_alloc_max = 0; /* debugging */
130:
131: /*
132: * The next field is at the base of the stack,
133: * so the low end is left unsullied.
134: */
135:
136: #define stack_next(stack) (*((vm_offset_t *)((stack) + KERNEL_STACK_SIZE) - 1))
137:
138: /*
139: * stack_alloc_try:
140: *
141: * Non-blocking attempt to allocate a kernel stack.
142: * Called at splsched with the thread locked.
143: */
144:
145: boolean_t stack_alloc_try(
146: thread_t thread,
147: void (*resume)(thread_t))
148: {
1.1.1.5 ! root 149: vm_offset_t stack;
1.1 root 150:
151: stack_lock();
152: stack = stack_free_list;
153: if (stack != 0) {
154: stack_free_list = stack_next(stack);
155: stack_free_count--;
156: } else {
157: stack = thread->stack_privilege;
158: }
159: stack_unlock();
160:
161: if (stack != 0) {
162: stack_attach(thread, stack, resume);
163: stack_alloc_hits++;
164: return TRUE;
165: } else {
166: stack_alloc_misses++;
167: return FALSE;
168: }
169: }
170:
171: /*
172: * stack_alloc:
173: *
174: * Allocate a kernel stack for a thread.
175: * May block.
176: */
177:
178: void stack_alloc(
179: thread_t thread,
180: void (*resume)(thread_t))
181: {
182: vm_offset_t stack;
183: spl_t s;
184:
185: /*
186: * We first try the free list. It is probably empty,
187: * or stack_alloc_try would have succeeded, but possibly
188: * a stack was freed before the swapin thread got to us.
189: */
190:
191: s = splsched();
192: stack_lock();
193: stack = stack_free_list;
194: if (stack != 0) {
195: stack_free_list = stack_next(stack);
196: stack_free_count--;
197: }
198: stack_unlock();
199: (void) splx(s);
200:
201: if (stack == 0) {
202: /*
203: * Kernel stacks should be naturally aligned,
204: * so that it is easy to find the starting/ending
205: * addresses of a stack given an address in the middle.
206: */
207:
1.1.1.4 root 208: if (kmem_alloc_aligned(kmem_map, &stack, KERNEL_STACK_SIZE)
1.1 root 209: != KERN_SUCCESS)
210: panic("stack_alloc");
211:
212: #if MACH_DEBUG
213: stack_init(stack);
214: #endif /* MACH_DEBUG */
215: }
216:
217: stack_attach(thread, stack, resume);
218: }
219:
220: /*
221: * stack_free:
222: *
223: * Free a thread's kernel stack.
224: * Called at splsched with the thread locked.
225: */
226:
227: void stack_free(
228: thread_t thread)
229: {
1.1.1.5 ! root 230: vm_offset_t stack;
1.1 root 231:
232: stack = stack_detach(thread);
233:
234: if (stack != thread->stack_privilege) {
235: stack_lock();
236: stack_next(stack) = stack_free_list;
237: stack_free_list = stack;
238: if (++stack_free_count > stack_alloc_max)
239: stack_alloc_max = stack_free_count;
240: stack_unlock();
241: }
242: }
243:
244: /*
245: * stack_collect:
246: *
247: * Free excess kernel stacks.
248: * May block.
249: */
250:
251: void stack_collect(void)
252: {
1.1.1.5 ! root 253: vm_offset_t stack;
1.1 root 254: spl_t s;
255:
256: s = splsched();
257: stack_lock();
258: while (stack_free_count > stack_free_limit) {
259: stack = stack_free_list;
260: stack_free_list = stack_next(stack);
261: stack_free_count--;
262: stack_unlock();
263: (void) splx(s);
264:
265: #if MACH_DEBUG
266: stack_finalize(stack);
267: #endif /* MACH_DEBUG */
1.1.1.4 root 268: kmem_free(kmem_map, stack, KERNEL_STACK_SIZE);
1.1 root 269:
270: s = splsched();
271: stack_lock();
272: }
273: stack_unlock();
274: (void) splx(s);
275: }
276: #endif /* MACHINE_STACK */
277:
278: /*
279: * stack_privilege:
280: *
281: * stack_alloc_try on this thread must always succeed.
282: */
283:
284: void stack_privilege(
1.1.1.5 ! root 285: thread_t thread)
1.1 root 286: {
287: /*
288: * This implementation only works for the current thread.
289: */
290:
291: if (thread != current_thread())
292: panic("stack_privilege");
293:
294: if (thread->stack_privilege == 0)
295: thread->stack_privilege = current_stack();
296: }
297:
298: void thread_init(void)
299: {
1.1.1.4 root 300: kmem_cache_init(&thread_cache, "thread", sizeof(struct thread), 0,
301: NULL, NULL, NULL, 0);
1.1 root 302:
303: /*
304: * Fill in a template thread for fast initialization.
305: * [Fields that must be (or are typically) reset at
306: * time of creation are so noted.]
307: */
308:
309: /* thread_template.links (none) */
310: thread_template.runq = RUN_QUEUE_NULL;
311:
312: /* thread_template.task (later) */
313: /* thread_template.thread_list (later) */
314: /* thread_template.pset_threads (later) */
315:
316: /* thread_template.lock (later) */
317: /* one ref for being alive; one for the guy who creates the thread */
318: thread_template.ref_count = 2;
319:
320: thread_template.pcb = (pcb_t) 0; /* (reset) */
321: thread_template.kernel_stack = (vm_offset_t) 0;
322: thread_template.stack_privilege = (vm_offset_t) 0;
323:
324: thread_template.wait_event = 0;
325: /* thread_template.suspend_count (later) */
326: thread_template.wait_result = KERN_SUCCESS;
327: thread_template.wake_active = FALSE;
328: thread_template.state = TH_SUSP | TH_SWAPPED;
329: thread_template.swap_func = thread_bootstrap_return;
330:
331: /* thread_template.priority (later) */
332: thread_template.max_priority = BASEPRI_USER;
333: /* thread_template.sched_pri (later - compute_priority) */
334: #if MACH_FIXPRI
335: thread_template.sched_data = 0;
336: thread_template.policy = POLICY_TIMESHARE;
337: #endif /* MACH_FIXPRI */
338: thread_template.depress_priority = -1;
339: thread_template.cpu_usage = 0;
340: thread_template.sched_usage = 0;
341: /* thread_template.sched_stamp (later) */
342:
343: thread_template.recover = (vm_offset_t) 0;
344: thread_template.vm_privilege = FALSE;
345:
346: thread_template.user_stop_count = 1;
347:
348: /* thread_template.<IPC structures> (later) */
349:
350: timer_init(&(thread_template.user_timer));
351: timer_init(&(thread_template.system_timer));
352: thread_template.user_timer_save.low = 0;
353: thread_template.user_timer_save.high = 0;
354: thread_template.system_timer_save.low = 0;
355: thread_template.system_timer_save.high = 0;
356: thread_template.cpu_delta = 0;
357: thread_template.sched_delta = 0;
358:
359: thread_template.active = FALSE; /* reset */
360: thread_template.ast = AST_ZILCH;
361:
362: /* thread_template.processor_set (later) */
363: thread_template.bound_processor = PROCESSOR_NULL;
364: #if MACH_HOST
365: thread_template.may_assign = TRUE;
366: thread_template.assign_active = FALSE;
367: #endif /* MACH_HOST */
368:
369: #if NCPUS > 1
370: /* thread_template.last_processor (later) */
371: #endif /* NCPUS > 1 */
372:
373: /*
374: * Initialize other data structures used in
375: * this module.
376: */
377:
378: queue_init(&reaper_queue);
379: simple_lock_init(&reaper_lock);
380:
381: #ifndef MACHINE_STACK
382: simple_lock_init(&stack_lock_data);
383: #endif /* MACHINE_STACK */
384:
385: #if MACH_DEBUG
386: simple_lock_init(&stack_usage_lock);
387: #endif /* MACH_DEBUG */
388:
389: /*
390: * Initialize any machine-dependent
391: * per-thread structures necessary.
392: */
393:
394: pcb_module_init();
395: }
396:
397: kern_return_t thread_create(
1.1.1.5 ! root 398: task_t parent_task,
1.1 root 399: thread_t *child_thread) /* OUT */
400: {
1.1.1.5 ! root 401: thread_t new_thread;
! 402: processor_set_t pset;
1.1 root 403:
404: if (parent_task == TASK_NULL)
405: return KERN_INVALID_ARGUMENT;
406:
407: /*
408: * Allocate a thread and initialize static fields
409: */
410:
1.1.1.4 root 411: new_thread = (thread_t) kmem_cache_alloc(&thread_cache);
1.1 root 412:
413: if (new_thread == THREAD_NULL)
414: return KERN_RESOURCE_SHORTAGE;
415:
416: *new_thread = thread_template;
417:
1.1.1.3 root 418: record_time_stamp (&new_thread->creation_time);
419:
1.1 root 420: /*
421: * Initialize runtime-dependent fields
422: */
423:
424: new_thread->task = parent_task;
425: simple_lock_init(&new_thread->lock);
426: new_thread->sched_stamp = sched_tick;
427: thread_timeout_setup(new_thread);
428:
429: /*
430: * Create a pcb. The kernel stack is created later,
431: * when the thread is swapped-in.
432: */
433: pcb_init(new_thread);
434:
435: ipc_thread_init(new_thread);
436:
437: /*
438: * Find the processor set for the parent task.
439: */
440: task_lock(parent_task);
441: pset = parent_task->processor_set;
442: pset_reference(pset);
443: task_unlock(parent_task);
444:
445: /*
446: * Lock both the processor set and the task,
447: * so that the thread can be added to both
448: * simultaneously. Processor set must be
449: * locked first.
450: */
451:
452: Restart:
453: pset_lock(pset);
454: task_lock(parent_task);
455:
456: /*
457: * If the task has changed processor sets,
458: * catch up (involves lots of lock juggling).
459: */
460: {
461: processor_set_t cur_pset;
462:
463: cur_pset = parent_task->processor_set;
464: if (!cur_pset->active)
465: cur_pset = &default_pset;
466:
467: if (cur_pset != pset) {
468: pset_reference(cur_pset);
469: task_unlock(parent_task);
470: pset_unlock(pset);
471: pset_deallocate(pset);
472: pset = cur_pset;
473: goto Restart;
474: }
475: }
476:
477: /*
478: * Set the thread`s priority from the pset and task.
479: */
480:
481: new_thread->priority = parent_task->priority;
482: if (pset->max_priority > new_thread->max_priority)
483: new_thread->max_priority = pset->max_priority;
484: if (new_thread->max_priority > new_thread->priority)
485: new_thread->priority = new_thread->max_priority;
486: /*
487: * Don't need to lock thread here because it can't
488: * possibly execute and no one else knows about it.
489: */
490: compute_priority(new_thread, TRUE);
491:
492: /*
493: * Thread is suspended if the task is. Add 1 to
494: * suspend count since thread is created in suspended
495: * state.
496: */
497: new_thread->suspend_count = parent_task->suspend_count + 1;
498:
499: /*
500: * Add the thread to the processor set.
501: * If the pset is empty, suspend the thread again.
502: */
503:
504: pset_add_thread(pset, new_thread);
505: if (pset->empty)
506: new_thread->suspend_count++;
507:
508: #if HW_FOOTPRINT
509: /*
510: * Need to set last_processor, idle processor would be best, but
511: * that requires extra locking nonsense. Go for tail of
512: * processors queue to avoid master.
513: */
514: if (!pset->empty) {
515: new_thread->last_processor =
516: (processor_t)queue_first(&pset->processors);
517: }
518: else {
519: /*
520: * Thread created in empty processor set. Pick
521: * master processor as an acceptable legal value.
522: */
523: new_thread->last_processor = master_processor;
524: }
525: #else /* HW_FOOTPRINT */
526: /*
527: * Don't need to initialize because the context switch
528: * code will set it before it can be used.
529: */
530: #endif /* HW_FOOTPRINT */
531:
532: #if MACH_PCSAMPLE
533: new_thread->pc_sample.seqno = 0;
534: new_thread->pc_sample.sampletypes = 0;
535: #endif /* MACH_PCSAMPLE */
536:
537: new_thread->pc_sample.buffer = 0;
538: /*
539: * Add the thread to the task`s list of threads.
540: * The new thread holds another reference to the task.
541: */
542:
543: parent_task->ref_count++;
544:
545: parent_task->thread_count++;
546: queue_enter(&parent_task->thread_list, new_thread, thread_t,
547: thread_list);
548:
549: /*
550: * Finally, mark the thread active.
551: */
552:
553: new_thread->active = TRUE;
554:
555: if (!parent_task->active) {
556: task_unlock(parent_task);
557: pset_unlock(pset);
558: (void) thread_terminate(new_thread);
559: /* release ref we would have given our caller */
560: thread_deallocate(new_thread);
561: return KERN_FAILURE;
562: }
563: task_unlock(parent_task);
564: pset_unlock(pset);
565:
566: ipc_thread_enable(new_thread);
567:
568: *child_thread = new_thread;
569: return KERN_SUCCESS;
570: }
571:
572: unsigned int thread_deallocate_stack = 0;
573:
574: void thread_deallocate(
1.1.1.5 ! root 575: thread_t thread)
1.1 root 576: {
577: spl_t s;
1.1.1.5 ! root 578: task_t task;
! 579: processor_set_t pset;
1.1 root 580:
581: time_value_t user_time, system_time;
582:
583: if (thread == THREAD_NULL)
584: return;
585:
586: /*
587: * First, check for new count > 0 (the common case).
588: * Only the thread needs to be locked.
589: */
590: s = splsched();
591: thread_lock(thread);
592: if (--thread->ref_count > 0) {
593: thread_unlock(thread);
594: (void) splx(s);
595: return;
596: }
597:
598: /*
599: * Count is zero. However, the task's and processor set's
600: * thread lists have implicit references to
601: * the thread, and may make new ones. Their locks also
602: * dominate the thread lock. To check for this, we
603: * temporarily restore the one thread reference, unlock
604: * the thread, and then lock the other structures in
605: * the proper order.
606: */
607: thread->ref_count = 1;
608: thread_unlock(thread);
609: (void) splx(s);
610:
611: pset = thread->processor_set;
612: pset_lock(pset);
613:
614: #if MACH_HOST
615: /*
616: * The thread might have moved.
617: */
618: while (pset != thread->processor_set) {
619: pset_unlock(pset);
620: pset = thread->processor_set;
621: pset_lock(pset);
622: }
623: #endif /* MACH_HOST */
624:
625: task = thread->task;
626: task_lock(task);
627:
628: s = splsched();
629: thread_lock(thread);
630:
631: if (--thread->ref_count > 0) {
632: /*
633: * Task or processor_set made extra reference.
634: */
635: thread_unlock(thread);
636: (void) splx(s);
637: task_unlock(task);
638: pset_unlock(pset);
639: return;
640: }
641:
642: /*
643: * Thread has no references - we can remove it.
644: */
645:
646: /*
647: * Remove pending timeouts.
648: */
649: reset_timeout_check(&thread->timer);
650:
651: reset_timeout_check(&thread->depress_timer);
652: thread->depress_priority = -1;
653:
654: /*
655: * Accumulate times for dead threads in task.
656: */
657: thread_read_times(thread, &user_time, &system_time);
658: time_value_add(&task->total_user_time, &user_time);
659: time_value_add(&task->total_system_time, &system_time);
660:
661: /*
662: * Remove thread from task list and processor_set threads list.
663: */
664: task->thread_count--;
665: queue_remove(&task->thread_list, thread, thread_t, thread_list);
666:
667: pset_remove_thread(pset, thread);
668:
669: thread_unlock(thread); /* no more references - safe */
670: (void) splx(s);
671: task_unlock(task);
672: pset_unlock(pset);
673: pset_deallocate(pset);
674:
675: /*
676: * A couple of quick sanity checks
677: */
678:
679: if (thread == current_thread()) {
680: panic("thread deallocating itself");
681: }
682: if ((thread->state & ~(TH_RUN | TH_HALTED | TH_SWAPPED)) != TH_SUSP)
683: panic("unstopped thread destroyed!");
684:
685: /*
686: * Deallocate the task reference, since we know the thread
687: * is not running.
688: */
689: task_deallocate(thread->task); /* may block */
690:
691: /*
692: * Clean up any machine-dependent resources.
693: */
694: if ((thread->state & TH_SWAPPED) == 0) {
1.1.1.4 root 695: splsched();
1.1 root 696: stack_free(thread);
697: (void) splx(s);
698: thread_deallocate_stack++;
699: }
700: /*
701: * Rattle the event count machinery (gag)
702: */
703: evc_notify_abort(thread);
704:
705: pcb_terminate(thread);
1.1.1.4 root 706: kmem_cache_free(&thread_cache, (vm_offset_t) thread);
1.1 root 707: }
708:
709: void thread_reference(
1.1.1.5 ! root 710: thread_t thread)
1.1 root 711: {
712: spl_t s;
713:
714: if (thread == THREAD_NULL)
715: return;
716:
717: s = splsched();
718: thread_lock(thread);
719: thread->ref_count++;
720: thread_unlock(thread);
721: (void) splx(s);
722: }
723:
724: /*
725: * thread_terminate:
726: *
727: * Permanently stop execution of the specified thread.
728: *
729: * A thread to be terminated must be allowed to clean up any state
730: * that it has before it exits. The thread is broken out of any
731: * wait condition that it is in, and signalled to exit. It then
732: * cleans up its state and calls thread_halt_self on its way out of
733: * the kernel. The caller waits for the thread to halt, terminates
734: * its IPC state, and then deallocates it.
735: *
736: * If the caller is the current thread, it must still exit the kernel
737: * to clean up any state (thread and port references, messages, etc).
738: * When it exits the kernel, it then terminates its IPC state and
739: * queues itself for the reaper thread, which will wait for the thread
740: * to stop and then deallocate it. (A thread cannot deallocate itself,
741: * since it needs a kernel stack to execute.)
742: */
743: kern_return_t thread_terminate(
1.1.1.5 ! root 744: thread_t thread)
1.1 root 745: {
1.1.1.5 ! root 746: thread_t cur_thread = current_thread();
! 747: task_t cur_task;
1.1 root 748: spl_t s;
749:
750: if (thread == THREAD_NULL)
751: return KERN_INVALID_ARGUMENT;
752:
753: /*
754: * Break IPC control over the thread.
755: */
756: ipc_thread_disable(thread);
757:
758: if (thread == cur_thread) {
759:
760: /*
761: * Current thread will queue itself for reaper when
762: * exiting kernel.
763: */
764: s = splsched();
765: thread_lock(thread);
766: if (thread->active) {
767: thread->active = FALSE;
768: thread_ast_set(thread, AST_TERMINATE);
769: }
770: thread_unlock(thread);
771: ast_on(cpu_number(), AST_TERMINATE);
772: splx(s);
773: return KERN_SUCCESS;
774: }
775:
776: /*
777: * Lock both threads and the current task
778: * to check termination races and prevent deadlocks.
779: */
780: cur_task = current_task();
781: task_lock(cur_task);
782: s = splsched();
783: if ((vm_offset_t)thread < (vm_offset_t)cur_thread) {
784: thread_lock(thread);
785: thread_lock(cur_thread);
786: }
787: else {
788: thread_lock(cur_thread);
789: thread_lock(thread);
790: }
791:
792: /*
793: * If the current thread is being terminated, help out.
794: */
795: if ((!cur_task->active) || (!cur_thread->active)) {
796: thread_unlock(cur_thread);
797: thread_unlock(thread);
798: (void) splx(s);
799: task_unlock(cur_task);
800: thread_terminate(cur_thread);
801: return KERN_FAILURE;
802: }
803:
804: thread_unlock(cur_thread);
805: task_unlock(cur_task);
806:
807: /*
808: * Terminate victim thread.
809: */
810: if (!thread->active) {
811: /*
812: * Someone else got there first.
813: */
814: thread_unlock(thread);
815: (void) splx(s);
816: return KERN_FAILURE;
817: }
818:
819: thread->active = FALSE;
820:
821: thread_unlock(thread);
822: (void) splx(s);
823:
824: #if MACH_HOST
825: /*
826: * Reassign thread to default pset if needed.
827: */
828: thread_freeze(thread);
829: if (thread->processor_set != &default_pset) {
830: thread_doassign(thread, &default_pset, FALSE);
831: }
832: #endif /* MACH_HOST */
833:
834: /*
835: * Halt the victim at the clean point.
836: */
837: (void) thread_halt(thread, TRUE);
838: #if MACH_HOST
839: thread_unfreeze(thread);
840: #endif /* MACH_HOST */
841: /*
842: * Shut down the victims IPC and deallocate its
843: * reference to itself.
844: */
845: ipc_thread_terminate(thread);
846: thread_deallocate(thread);
847: return KERN_SUCCESS;
848: }
849:
1.1.1.5 ! root 850: kern_return_t thread_terminate_release(
! 851: thread_t thread,
! 852: task_t task,
! 853: mach_port_t thread_name,
! 854: mach_port_t reply_port,
! 855: vm_offset_t address,
! 856: vm_size_t size)
! 857: {
! 858: if (task == NULL)
! 859: return KERN_INVALID_ARGUMENT;
! 860:
! 861: mach_port_deallocate(task->itk_space, thread_name);
! 862:
! 863: if (reply_port != MACH_PORT_NULL)
! 864: mach_port_destroy(task->itk_space, reply_port);
! 865:
! 866: if ((address != 0) || (size != 0))
! 867: vm_deallocate(task->map, address, size);
! 868:
! 869: return thread_terminate(thread);
! 870: }
! 871:
1.1 root 872: /*
873: * thread_force_terminate:
874: *
875: * Version of thread_terminate called by task_terminate. thread is
876: * not the current thread. task_terminate is the dominant operation,
877: * so we can force this thread to stop.
878: */
879: void
880: thread_force_terminate(
1.1.1.5 ! root 881: thread_t thread)
1.1 root 882: {
1.1.1.4 root 883: boolean_t deallocate_here;
1.1 root 884: spl_t s;
885:
886: ipc_thread_disable(thread);
887:
888: #if MACH_HOST
889: /*
890: * Reassign thread to default pset if needed.
891: */
892: thread_freeze(thread);
893: if (thread->processor_set != &default_pset)
894: thread_doassign(thread, &default_pset, FALSE);
895: #endif /* MACH_HOST */
896:
897: s = splsched();
898: thread_lock(thread);
899: deallocate_here = thread->active;
900: thread->active = FALSE;
901: thread_unlock(thread);
902: (void) splx(s);
903:
904: (void) thread_halt(thread, TRUE);
905: ipc_thread_terminate(thread);
906:
907: #if MACH_HOST
908: thread_unfreeze(thread);
909: #endif /* MACH_HOST */
910:
911: if (deallocate_here)
912: thread_deallocate(thread);
913: }
914:
915:
916: /*
917: * Halt a thread at a clean point, leaving it suspended.
918: *
919: * must_halt indicates whether thread must halt.
920: *
921: */
922: kern_return_t thread_halt(
1.1.1.5 ! root 923: thread_t thread,
1.1 root 924: boolean_t must_halt)
925: {
1.1.1.5 ! root 926: thread_t cur_thread = current_thread();
! 927: kern_return_t ret;
1.1 root 928: spl_t s;
929:
930: if (thread == cur_thread)
931: panic("thread_halt: trying to halt current thread.");
932: /*
933: * If must_halt is FALSE, then a check must be made for
934: * a cycle of halt operations.
935: */
936: if (!must_halt) {
937: /*
938: * Grab both thread locks.
939: */
940: s = splsched();
941: if ((vm_offset_t)thread < (vm_offset_t)cur_thread) {
942: thread_lock(thread);
943: thread_lock(cur_thread);
944: }
945: else {
946: thread_lock(cur_thread);
947: thread_lock(thread);
948: }
949:
950: /*
951: * If target thread is already halted, grab a hold
952: * on it and return.
953: */
954: if (thread->state & TH_HALTED) {
955: thread->suspend_count++;
956: thread_unlock(cur_thread);
957: thread_unlock(thread);
958: (void) splx(s);
959: return KERN_SUCCESS;
960: }
961:
962: /*
963: * If someone is trying to halt us, we have a potential
964: * halt cycle. Break the cycle by interrupting anyone
965: * who is trying to halt us, and causing this operation
966: * to fail; retry logic will only retry operations
967: * that cannot deadlock. (If must_halt is TRUE, this
968: * operation can never cause a deadlock.)
969: */
970: if (cur_thread->ast & AST_HALT) {
1.1.1.5 ! root 971: thread_wakeup_with_result(TH_EV_WAKE_ACTIVE(cur_thread),
1.1 root 972: THREAD_INTERRUPTED);
973: thread_unlock(thread);
974: thread_unlock(cur_thread);
975: (void) splx(s);
976: return KERN_FAILURE;
977: }
978:
979: thread_unlock(cur_thread);
980:
981: }
982: else {
983: /*
984: * Lock thread and check whether it is already halted.
985: */
986: s = splsched();
987: thread_lock(thread);
988: if (thread->state & TH_HALTED) {
989: thread->suspend_count++;
990: thread_unlock(thread);
991: (void) splx(s);
992: return KERN_SUCCESS;
993: }
994: }
995:
996: /*
997: * Suspend thread - inline version of thread_hold() because
998: * thread is already locked.
999: */
1000: thread->suspend_count++;
1001: thread->state |= TH_SUSP;
1002:
1003: /*
1004: * If someone else is halting it, wait for that to complete.
1005: * Fail if wait interrupted and must_halt is false.
1006: */
1007: while ((thread->ast & AST_HALT) && (!(thread->state & TH_HALTED))) {
1008: thread->wake_active = TRUE;
1.1.1.5 ! root 1009: thread_sleep(TH_EV_WAKE_ACTIVE(thread),
1.1 root 1010: simple_lock_addr(thread->lock), TRUE);
1011:
1012: if (thread->state & TH_HALTED) {
1013: (void) splx(s);
1014: return KERN_SUCCESS;
1015: }
1016: if ((current_thread()->wait_result != THREAD_AWAKENED)
1017: && !(must_halt)) {
1018: (void) splx(s);
1019: thread_release(thread);
1020: return KERN_FAILURE;
1021: }
1022: thread_lock(thread);
1023: }
1024:
1025: /*
1026: * Otherwise, have to do it ourselves.
1027: */
1028:
1029: thread_ast_set(thread, AST_HALT);
1030:
1031: while (TRUE) {
1032: /*
1033: * Wait for thread to stop.
1034: */
1035: thread_unlock(thread);
1036: (void) splx(s);
1037:
1038: ret = thread_dowait(thread, must_halt);
1039:
1040: /*
1041: * If the dowait failed, so do we. Drop AST_HALT, and
1042: * wake up anyone else who might be waiting for it.
1043: */
1044: if (ret != KERN_SUCCESS) {
1045: s = splsched();
1046: thread_lock(thread);
1047: thread_ast_clear(thread, AST_HALT);
1.1.1.5 ! root 1048: thread_wakeup_with_result(TH_EV_WAKE_ACTIVE(thread),
1.1 root 1049: THREAD_INTERRUPTED);
1050: thread_unlock(thread);
1051: (void) splx(s);
1052:
1053: thread_release(thread);
1054: return ret;
1055: }
1056:
1057: /*
1058: * Clear any interruptible wait.
1059: */
1060: clear_wait(thread, THREAD_INTERRUPTED, TRUE);
1061:
1062: /*
1063: * If the thread's at a clean point, we're done.
1064: * Don't need a lock because it really is stopped.
1065: */
1066: if (thread->state & TH_HALTED) {
1067: return KERN_SUCCESS;
1068: }
1069:
1070: /*
1071: * If the thread is at a nice continuation,
1072: * or a continuation with a cleanup routine,
1073: * call the cleanup routine.
1074: */
1075: if ((((thread->swap_func == mach_msg_continue) ||
1076: (thread->swap_func == mach_msg_receive_continue)) &&
1077: mach_msg_interrupt(thread)) ||
1078: (thread->swap_func == thread_exception_return) ||
1079: (thread->swap_func == thread_bootstrap_return)) {
1080: s = splsched();
1081: thread_lock(thread);
1082: thread->state |= TH_HALTED;
1083: thread_ast_clear(thread, AST_HALT);
1084: thread_unlock(thread);
1085: splx(s);
1086:
1087: return KERN_SUCCESS;
1088: }
1089:
1090: /*
1091: * Force the thread to stop at a clean
1092: * point, and arrange to wait for it.
1093: *
1094: * Set it running, so it can notice. Override
1095: * the suspend count. We know that the thread
1096: * is suspended and not waiting.
1097: *
1098: * Since the thread may hit an interruptible wait
1099: * before it reaches a clean point, we must force it
1100: * to wake us up when it does so. This involves some
1101: * trickery:
1102: * We mark the thread SUSPENDED so that thread_block
1103: * will suspend it and wake us up.
1104: * We mark the thread RUNNING so that it will run.
1105: * We mark the thread UN-INTERRUPTIBLE (!) so that
1106: * some other thread trying to halt or suspend it won't
1107: * take it off the run queue before it runs. Since
1108: * dispatching a thread (the tail of thread_invoke) marks
1109: * the thread interruptible, it will stop at the next
1110: * context switch or interruptible wait.
1111: */
1112:
1113: s = splsched();
1114: thread_lock(thread);
1115: if ((thread->state & TH_SCHED_STATE) != TH_SUSP)
1116: panic("thread_halt");
1117: thread->state |= TH_RUN | TH_UNINT;
1118: thread_setrun(thread, FALSE);
1119:
1120: /*
1121: * Continue loop and wait for thread to stop.
1122: */
1123: }
1124: }
1125:
1.1.1.5 ! root 1126: void __attribute__((noreturn)) walking_zombie(void)
1.1 root 1127: {
1128: panic("the zombie walks!");
1129: }
1130:
1131: /*
1132: * Thread calls this routine on exit from the kernel when it
1133: * notices a halt request.
1134: */
1135: void thread_halt_self(void)
1136: {
1.1.1.5 ! root 1137: thread_t thread = current_thread();
1.1 root 1138: spl_t s;
1139:
1140: if (thread->ast & AST_TERMINATE) {
1141: /*
1142: * Thread is terminating itself. Shut
1143: * down IPC, then queue it up for the
1144: * reaper thread.
1145: */
1146: ipc_thread_terminate(thread);
1147:
1148: thread_hold(thread);
1149:
1150: s = splsched();
1151: simple_lock(&reaper_lock);
1.1.1.5 ! root 1152: enqueue_tail(&reaper_queue, &(thread->links));
1.1 root 1153: simple_unlock(&reaper_lock);
1154:
1155: thread_lock(thread);
1156: thread->state |= TH_HALTED;
1157: thread_unlock(thread);
1158: (void) splx(s);
1159:
1160: thread_wakeup((event_t)&reaper_queue);
1161: counter(c_thread_halt_self_block++);
1162: thread_block(walking_zombie);
1163: /*NOTREACHED*/
1164: } else {
1165: /*
1166: * Thread was asked to halt - show that it
1167: * has done so.
1168: */
1169: s = splsched();
1170: thread_lock(thread);
1171: thread->state |= TH_HALTED;
1172: thread_ast_clear(thread, AST_HALT);
1173: thread_unlock(thread);
1174: splx(s);
1175: counter(c_thread_halt_self_block++);
1176: thread_block(thread_exception_return);
1177: /*
1178: * thread_release resets TH_HALTED.
1179: */
1180: }
1181: }
1182:
1183: /*
1184: * thread_hold:
1185: *
1186: * Suspend execution of the specified thread.
1187: * This is a recursive-style suspension of the thread, a count of
1188: * suspends is maintained.
1189: */
1190: void thread_hold(
1.1.1.5 ! root 1191: thread_t thread)
1.1 root 1192: {
1193: spl_t s;
1194:
1195: s = splsched();
1196: thread_lock(thread);
1197: thread->suspend_count++;
1198: thread->state |= TH_SUSP;
1199: thread_unlock(thread);
1200: (void) splx(s);
1201: }
1202:
1203: /*
1204: * thread_dowait:
1205: *
1206: * Wait for a thread to actually enter stopped state.
1207: *
1208: * must_halt argument indicates if this may fail on interruption.
1209: * This is FALSE only if called from thread_abort via thread_halt.
1210: */
1211: kern_return_t
1212: thread_dowait(
1.1.1.5 ! root 1213: thread_t thread,
1.1 root 1214: boolean_t must_halt)
1215: {
1.1.1.5 ! root 1216: boolean_t need_wakeup;
! 1217: kern_return_t ret = KERN_SUCCESS;
1.1 root 1218: spl_t s;
1219:
1220: if (thread == current_thread())
1221: panic("thread_dowait");
1222:
1223: /*
1224: * If a thread is not interruptible, it may not be suspended
1225: * until it becomes interruptible. In this case, we wait for
1226: * the thread to stop itself, and indicate that we are waiting
1227: * for it to stop so that it can wake us up when it does stop.
1228: *
1229: * If the thread is interruptible, we may be able to suspend
1230: * it immediately. There are several cases:
1231: *
1232: * 1) The thread is already stopped (trivial)
1233: * 2) The thread is runnable (marked RUN and on a run queue).
1234: * We pull it off the run queue and mark it stopped.
1235: * 3) The thread is running. We wait for it to stop.
1236: */
1237:
1238: need_wakeup = FALSE;
1239: s = splsched();
1240: thread_lock(thread);
1241:
1242: for (;;) {
1243: switch (thread->state & TH_SCHED_STATE) {
1244: case TH_SUSP:
1245: case TH_WAIT | TH_SUSP:
1246: /*
1247: * Thread is already suspended, or sleeping in an
1248: * interruptible wait. We win!
1249: */
1250: break;
1251:
1252: case TH_RUN | TH_SUSP:
1253: /*
1254: * The thread is interruptible. If we can pull
1255: * it off a runq, stop it here.
1256: */
1257: if (rem_runq(thread) != RUN_QUEUE_NULL) {
1258: thread->state &= ~TH_RUN;
1259: need_wakeup = thread->wake_active;
1260: thread->wake_active = FALSE;
1261: break;
1262: }
1263: #if NCPUS > 1
1264: /*
1265: * The thread must be running, so make its
1266: * processor execute ast_check(). This
1267: * should cause the thread to take an ast and
1268: * context switch to suspend for us.
1269: */
1270: cause_ast_check(thread->last_processor);
1271: #endif /* NCPUS > 1 */
1272:
1273: /*
1274: * Fall through to wait for thread to stop.
1275: */
1276:
1277: case TH_RUN | TH_SUSP | TH_UNINT:
1278: case TH_RUN | TH_WAIT | TH_SUSP:
1279: case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
1280: case TH_WAIT | TH_SUSP | TH_UNINT:
1281: /*
1282: * Wait for the thread to stop, or sleep interruptibly
1283: * (thread_block will stop it in the latter case).
1284: * Check for failure if interrupted.
1285: */
1286: thread->wake_active = TRUE;
1.1.1.5 ! root 1287: thread_sleep(TH_EV_WAKE_ACTIVE(thread),
1.1 root 1288: simple_lock_addr(thread->lock), TRUE);
1289: thread_lock(thread);
1290: if ((current_thread()->wait_result != THREAD_AWAKENED) &&
1291: !must_halt) {
1292: ret = KERN_FAILURE;
1293: break;
1294: }
1295:
1296: /*
1297: * Repeat loop to check thread`s state.
1298: */
1299: continue;
1300: }
1301: /*
1302: * Thread is stopped at this point.
1303: */
1304: break;
1305: }
1306:
1307: thread_unlock(thread);
1308: (void) splx(s);
1309:
1310: if (need_wakeup)
1.1.1.5 ! root 1311: thread_wakeup(TH_EV_WAKE_ACTIVE(thread));
1.1 root 1312:
1313: return ret;
1314: }
1315:
1316: void thread_release(
1.1.1.5 ! root 1317: thread_t thread)
1.1 root 1318: {
1319: spl_t s;
1320:
1321: s = splsched();
1322: thread_lock(thread);
1323: if (--thread->suspend_count == 0) {
1324: thread->state &= ~(TH_SUSP | TH_HALTED);
1325: if ((thread->state & (TH_WAIT | TH_RUN)) == 0) {
1326: /* was only suspended */
1327: thread->state |= TH_RUN;
1328: thread_setrun(thread, TRUE);
1329: }
1330: }
1331: thread_unlock(thread);
1332: (void) splx(s);
1333: }
1334:
1335: kern_return_t thread_suspend(
1.1.1.5 ! root 1336: thread_t thread)
1.1 root 1337: {
1.1.1.5 ! root 1338: boolean_t hold;
1.1 root 1339: spl_t spl;
1340:
1341: if (thread == THREAD_NULL)
1342: return KERN_INVALID_ARGUMENT;
1343:
1344: hold = FALSE;
1345: spl = splsched();
1346: thread_lock(thread);
1.1.1.4 root 1347: /* Wait for thread to get interruptible */
1348: while (thread->state & TH_UNINT) {
1.1.1.5 ! root 1349: assert_wait(TH_EV_STATE(thread), TRUE);
1.1.1.4 root 1350: thread_unlock(thread);
1351: thread_block(NULL);
1352: thread_lock(thread);
1353: }
1.1 root 1354: if (thread->user_stop_count++ == 0) {
1355: hold = TRUE;
1356: thread->suspend_count++;
1357: thread->state |= TH_SUSP;
1358: }
1359: thread_unlock(thread);
1360: (void) splx(spl);
1361:
1362: /*
1363: * Now wait for the thread if necessary.
1364: */
1365: if (hold) {
1366: if (thread == current_thread()) {
1367: /*
1368: * We want to call thread_block on our way out,
1369: * to stop running.
1370: */
1371: spl = splsched();
1372: ast_on(cpu_number(), AST_BLOCK);
1373: (void) splx(spl);
1374: } else
1375: (void) thread_dowait(thread, TRUE);
1376: }
1377: return KERN_SUCCESS;
1378: }
1379:
1380:
1381: kern_return_t thread_resume(
1.1.1.5 ! root 1382: thread_t thread)
1.1 root 1383: {
1.1.1.5 ! root 1384: kern_return_t ret;
1.1 root 1385: spl_t s;
1386:
1387: if (thread == THREAD_NULL)
1388: return KERN_INVALID_ARGUMENT;
1389:
1390: ret = KERN_SUCCESS;
1391:
1392: s = splsched();
1393: thread_lock(thread);
1394: if (thread->user_stop_count > 0) {
1395: if (--thread->user_stop_count == 0) {
1396: if (--thread->suspend_count == 0) {
1397: thread->state &= ~(TH_SUSP | TH_HALTED);
1398: if ((thread->state & (TH_WAIT | TH_RUN)) == 0) {
1399: /* was only suspended */
1400: thread->state |= TH_RUN;
1401: thread_setrun(thread, TRUE);
1402: }
1403: }
1404: }
1405: }
1406: else {
1407: ret = KERN_FAILURE;
1408: }
1409:
1410: thread_unlock(thread);
1411: (void) splx(s);
1412:
1413: return ret;
1414: }
1415:
1416: /*
1417: * Return thread's machine-dependent state.
1418: */
1419: kern_return_t thread_get_state(
1.1.1.5 ! root 1420: thread_t thread,
1.1 root 1421: int flavor,
1422: thread_state_t old_state, /* pointer to OUT array */
1423: natural_t *old_state_count) /*IN/OUT*/
1424: {
1425: kern_return_t ret;
1426:
1427: if (thread == THREAD_NULL || thread == current_thread()) {
1428: return KERN_INVALID_ARGUMENT;
1429: }
1430:
1431: thread_hold(thread);
1432: (void) thread_dowait(thread, TRUE);
1433:
1434: ret = thread_getstatus(thread, flavor, old_state, old_state_count);
1435:
1436: thread_release(thread);
1437: return ret;
1438: }
1439:
1440: /*
1441: * Change thread's machine-dependent state.
1442: */
1443: kern_return_t thread_set_state(
1.1.1.5 ! root 1444: thread_t thread,
1.1 root 1445: int flavor,
1446: thread_state_t new_state,
1447: natural_t new_state_count)
1448: {
1449: kern_return_t ret;
1450:
1451: if (thread == THREAD_NULL || thread == current_thread()) {
1452: return KERN_INVALID_ARGUMENT;
1453: }
1454:
1455: thread_hold(thread);
1456: (void) thread_dowait(thread, TRUE);
1457:
1458: ret = thread_setstatus(thread, flavor, new_state, new_state_count);
1459:
1460: thread_release(thread);
1461: return ret;
1462: }
1463:
1464: kern_return_t thread_info(
1.1.1.5 ! root 1465: thread_t thread,
1.1 root 1466: int flavor,
1467: thread_info_t thread_info_out, /* pointer to OUT array */
1468: natural_t *thread_info_count) /*IN/OUT*/
1469: {
1470: int state, flags;
1471: spl_t s;
1472:
1473: if (thread == THREAD_NULL)
1474: return KERN_INVALID_ARGUMENT;
1475:
1476: if (flavor == THREAD_BASIC_INFO) {
1.1.1.5 ! root 1477: thread_basic_info_t basic_info;
1.1 root 1478:
1.1.1.3 root 1479: /* Allow *thread_info_count to be one smaller than the
1480: usual amount, because creation_time is a new member
1481: that some callers might not know about. */
1482:
1483: if (*thread_info_count < THREAD_BASIC_INFO_COUNT - 1) {
1.1 root 1484: return KERN_INVALID_ARGUMENT;
1485: }
1486:
1487: basic_info = (thread_basic_info_t) thread_info_out;
1488:
1489: s = splsched();
1490: thread_lock(thread);
1491:
1492: /*
1493: * Update lazy-evaluated scheduler info because someone wants it.
1494: */
1495: if ((thread->state & TH_RUN) == 0 &&
1496: thread->sched_stamp != sched_tick)
1497: update_priority(thread);
1498:
1499: /* fill in info */
1500:
1501: thread_read_times(thread,
1502: &basic_info->user_time,
1503: &basic_info->system_time);
1504: basic_info->base_priority = thread->priority;
1505: basic_info->cur_priority = thread->sched_pri;
1.1.1.3 root 1506: basic_info->creation_time = thread->creation_time;
1.1 root 1507:
1508: /*
1509: * To calculate cpu_usage, first correct for timer rate,
1510: * then for 5/8 ageing. The correction factor [3/5] is
1511: * (1/(5/8) - 1).
1512: */
1513: basic_info->cpu_usage = thread->cpu_usage /
1514: (TIMER_RATE/TH_USAGE_SCALE);
1515: basic_info->cpu_usage = (basic_info->cpu_usage * 3) / 5;
1516: #if SIMPLE_CLOCK
1517: /*
1518: * Clock drift compensation.
1519: */
1520: basic_info->cpu_usage =
1521: (basic_info->cpu_usage * 1000000)/sched_usec;
1522: #endif /* SIMPLE_CLOCK */
1523:
1.1.1.2 root 1524: flags = 0;
1.1 root 1525: if (thread->state & TH_SWAPPED)
1.1.1.2 root 1526: flags |= TH_FLAGS_SWAPPED;
1527: if (thread->state & TH_IDLE)
1528: flags |= TH_FLAGS_IDLE;
1.1 root 1529:
1530: if (thread->state & TH_HALTED)
1531: state = TH_STATE_HALTED;
1532: else
1533: if (thread->state & TH_RUN)
1534: state = TH_STATE_RUNNING;
1535: else
1536: if (thread->state & TH_UNINT)
1537: state = TH_STATE_UNINTERRUPTIBLE;
1538: else
1539: if (thread->state & TH_SUSP)
1540: state = TH_STATE_STOPPED;
1541: else
1542: if (thread->state & TH_WAIT)
1543: state = TH_STATE_WAITING;
1544: else
1545: state = 0; /* ? */
1546:
1547: basic_info->run_state = state;
1548: basic_info->flags = flags;
1549: basic_info->suspend_count = thread->user_stop_count;
1550: if (state == TH_STATE_RUNNING)
1551: basic_info->sleep_time = 0;
1552: else
1553: basic_info->sleep_time = sched_tick - thread->sched_stamp;
1554:
1555: thread_unlock(thread);
1556: splx(s);
1557:
1.1.1.3 root 1558: if (*thread_info_count > THREAD_BASIC_INFO_COUNT)
1559: *thread_info_count = THREAD_BASIC_INFO_COUNT;
1.1 root 1560: return KERN_SUCCESS;
1561: }
1562: else if (flavor == THREAD_SCHED_INFO) {
1.1.1.5 ! root 1563: thread_sched_info_t sched_info;
1.1 root 1564:
1565: if (*thread_info_count < THREAD_SCHED_INFO_COUNT) {
1566: return KERN_INVALID_ARGUMENT;
1567: }
1568:
1569: sched_info = (thread_sched_info_t) thread_info_out;
1570:
1571: s = splsched();
1572: thread_lock(thread);
1573:
1574: #if MACH_FIXPRI
1575: sched_info->policy = thread->policy;
1576: if (thread->policy == POLICY_FIXEDPRI) {
1577: sched_info->data = (thread->sched_data * tick)/1000;
1578: }
1579: else {
1580: sched_info->data = 0;
1581: }
1582: #else /* MACH_FIXPRI */
1583: sched_info->policy = POLICY_TIMESHARE;
1584: sched_info->data = 0;
1585: #endif /* MACH_FIXPRI */
1586:
1587: sched_info->base_priority = thread->priority;
1588: sched_info->max_priority = thread->max_priority;
1589: sched_info->cur_priority = thread->sched_pri;
1590:
1591: sched_info->depressed = (thread->depress_priority >= 0);
1592: sched_info->depress_priority = thread->depress_priority;
1593:
1594: thread_unlock(thread);
1595: splx(s);
1596:
1597: *thread_info_count = THREAD_SCHED_INFO_COUNT;
1598: return KERN_SUCCESS;
1599: }
1600:
1601: return KERN_INVALID_ARGUMENT;
1602: }
1603:
1604: kern_return_t thread_abort(
1.1.1.5 ! root 1605: thread_t thread)
1.1 root 1606: {
1607: if (thread == THREAD_NULL || thread == current_thread()) {
1608: return KERN_INVALID_ARGUMENT;
1609: }
1610:
1611: /*
1612: *
1613: * clear it of an event wait
1614: */
1615: evc_notify_abort(thread);
1616:
1617: /*
1618: * Try to force the thread to a clean point
1619: * If the halt operation fails return KERN_ABORTED.
1620: * ipc code will convert this to an ipc interrupted error code.
1621: */
1622: if (thread_halt(thread, FALSE) != KERN_SUCCESS)
1623: return KERN_ABORTED;
1624:
1625: /*
1626: * If the thread was in an exception, abort that too.
1627: */
1628: mach_msg_abort_rpc(thread);
1629:
1630: /*
1631: * Then set it going again.
1632: */
1633: thread_release(thread);
1634:
1635: /*
1636: * Also abort any depression.
1637: */
1638: if (thread->depress_priority != -1)
1639: thread_depress_abort(thread);
1640:
1641: return KERN_SUCCESS;
1642: }
1643:
1644: /*
1645: * thread_start:
1646: *
1647: * Start a thread at the specified routine.
1648: * The thread must be in a swapped state.
1649: */
1650:
1651: void
1652: thread_start(
1653: thread_t thread,
1654: continuation_t start)
1655: {
1656: thread->swap_func = start;
1657: }
1658:
1659: /*
1660: * kernel_thread:
1661: *
1662: * Start up a kernel thread in the specified task.
1663: */
1664:
1665: thread_t kernel_thread(
1666: task_t task,
1667: continuation_t start,
1668: void * arg)
1669: {
1670: thread_t thread;
1671:
1672: (void) thread_create(task, &thread);
1673: /* release "extra" ref that thread_create gave us */
1674: thread_deallocate(thread);
1675: thread_start(thread, start);
1676: thread->ith_other = arg;
1677:
1678: /*
1679: * We ensure that the kernel thread starts with a stack.
1680: * The swapin mechanism might not be operational yet.
1681: */
1682: thread_doswapin(thread);
1683: thread->max_priority = BASEPRI_SYSTEM;
1684: thread->priority = BASEPRI_SYSTEM;
1685: thread->sched_pri = BASEPRI_SYSTEM;
1686: (void) thread_resume(thread);
1687: return thread;
1688: }
1689:
1690: /*
1691: * reaper_thread:
1692: *
1693: * This kernel thread runs forever looking for threads to destroy
1694: * (when they request that they be destroyed, of course).
1695: */
1.1.1.5 ! root 1696: void __attribute__((noreturn)) reaper_thread_continue(void)
1.1 root 1697: {
1698: for (;;) {
1.1.1.5 ! root 1699: thread_t thread;
1.1 root 1700: spl_t s;
1701:
1702: s = splsched();
1703: simple_lock(&reaper_lock);
1704:
1705: while ((thread = (thread_t) dequeue_head(&reaper_queue))
1706: != THREAD_NULL) {
1707: simple_unlock(&reaper_lock);
1708: (void) splx(s);
1709:
1710: (void) thread_dowait(thread, TRUE); /* may block */
1711: thread_deallocate(thread); /* may block */
1712:
1713: s = splsched();
1714: simple_lock(&reaper_lock);
1715: }
1716:
1717: assert_wait((event_t) &reaper_queue, FALSE);
1718: simple_unlock(&reaper_lock);
1719: (void) splx(s);
1720: counter(c_reaper_thread_block++);
1721: thread_block(reaper_thread_continue);
1722: }
1723: }
1724:
1725: void reaper_thread(void)
1726: {
1727: reaper_thread_continue();
1728: /*NOTREACHED*/
1729: }
1730:
1731: #if MACH_HOST
1732: /*
1733: * thread_assign:
1734: *
1735: * Change processor set assignment.
1736: * Caller must hold an extra reference to the thread (if this is
1737: * called directly from the ipc interface, this is an operation
1738: * in progress reference). Caller must hold no locks -- this may block.
1739: */
1740:
1741: kern_return_t
1742: thread_assign(
1743: thread_t thread,
1744: processor_set_t new_pset)
1745: {
1746: if (thread == THREAD_NULL || new_pset == PROCESSOR_SET_NULL) {
1747: return KERN_INVALID_ARGUMENT;
1748: }
1749:
1750: thread_freeze(thread);
1751: thread_doassign(thread, new_pset, TRUE);
1752:
1753: return KERN_SUCCESS;
1754: }
1755:
1756: /*
1757: * thread_freeze:
1758: *
1759: * Freeze thread's assignment. Prelude to assigning thread.
1760: * Only one freeze may be held per thread.
1761: */
1762: void
1763: thread_freeze(
1764: thread_t thread)
1765: {
1766: spl_t s;
1767: /*
1768: * Freeze the assignment, deferring to a prior freeze.
1769: */
1770: s = splsched();
1771: thread_lock(thread);
1772: while (thread->may_assign == FALSE) {
1773: thread->assign_active = TRUE;
1774: thread_sleep((event_t) &thread->assign_active,
1775: simple_lock_addr(thread->lock), FALSE);
1776: thread_lock(thread);
1777: }
1778: thread->may_assign = FALSE;
1779: thread_unlock(thread);
1780: (void) splx(s);
1781:
1782: }
1783:
1784: /*
1785: * thread_unfreeze: release freeze on thread's assignment.
1786: */
1787: void
1788: thread_unfreeze(
1789: thread_t thread)
1790: {
1791: spl_t s;
1792:
1793: s = splsched();
1794: thread_lock(thread);
1795: thread->may_assign = TRUE;
1796: if (thread->assign_active) {
1797: thread->assign_active = FALSE;
1798: thread_wakeup((event_t)&thread->assign_active);
1799: }
1800: thread_unlock(thread);
1801: splx(s);
1802: }
1803:
1804: /*
1805: * thread_doassign:
1806: *
1807: * Actually do thread assignment. thread_will_assign must have been
1808: * called on the thread. release_freeze argument indicates whether
1809: * to release freeze on thread.
1810: */
1811:
1812: void
1813: thread_doassign(
1.1.1.5 ! root 1814: thread_t thread,
! 1815: processor_set_t new_pset,
1.1 root 1816: boolean_t release_freeze)
1817: {
1.1.1.5 ! root 1818: processor_set_t pset;
! 1819: boolean_t old_empty, new_empty;
1.1 root 1820: boolean_t recompute_pri = FALSE;
1821: spl_t s;
1822:
1823: /*
1824: * Check for silly no-op.
1825: */
1826: pset = thread->processor_set;
1827: if (pset == new_pset) {
1828: if (release_freeze)
1829: thread_unfreeze(thread);
1830: return;
1831: }
1832: /*
1833: * Suspend the thread and stop it if it's not the current thread.
1834: */
1835: thread_hold(thread);
1836: if (thread != current_thread())
1837: (void) thread_dowait(thread, TRUE);
1838:
1839: /*
1840: * Lock both psets now, use ordering to avoid deadlocks.
1841: */
1842: Restart:
1843: if ((vm_offset_t)pset < (vm_offset_t)new_pset) {
1844: pset_lock(pset);
1845: pset_lock(new_pset);
1846: }
1847: else {
1848: pset_lock(new_pset);
1849: pset_lock(pset);
1850: }
1851:
1852: /*
1853: * Check if new_pset is ok to assign to. If not, reassign
1854: * to default_pset.
1855: */
1856: if (!new_pset->active) {
1857: pset_unlock(pset);
1858: pset_unlock(new_pset);
1859: new_pset = &default_pset;
1860: goto Restart;
1861: }
1862:
1863: pset_reference(new_pset);
1864:
1865: /*
1866: * Grab the thread lock and move the thread.
1867: * Then drop the lock on the old pset and the thread's
1868: * reference to it.
1869: */
1870: s = splsched();
1871: thread_lock(thread);
1872:
1873: thread_change_psets(thread, pset, new_pset);
1874:
1875: old_empty = pset->empty;
1876: new_empty = new_pset->empty;
1877:
1878: pset_unlock(pset);
1879:
1880: /*
1881: * Reset policy and priorities if needed.
1882: */
1883: #if MACH_FIXPRI
1884: if (thread->policy & new_pset->policies == 0) {
1885: thread->policy = POLICY_TIMESHARE;
1886: recompute_pri = TRUE;
1887: }
1888: #endif /* MACH_FIXPRI */
1889:
1890: if (thread->max_priority < new_pset->max_priority) {
1891: thread->max_priority = new_pset->max_priority;
1892: if (thread->priority < thread->max_priority) {
1893: thread->priority = thread->max_priority;
1894: recompute_pri = TRUE;
1895: }
1896: else {
1897: if ((thread->depress_priority >= 0) &&
1898: (thread->depress_priority < thread->max_priority)) {
1899: thread->depress_priority = thread->max_priority;
1900: }
1901: }
1902: }
1903:
1904: pset_unlock(new_pset);
1905:
1906: if (recompute_pri)
1907: compute_priority(thread, TRUE);
1908:
1909: if (release_freeze) {
1910: thread->may_assign = TRUE;
1911: if (thread->assign_active) {
1912: thread->assign_active = FALSE;
1913: thread_wakeup((event_t)&thread->assign_active);
1914: }
1915: }
1916:
1917: thread_unlock(thread);
1918: splx(s);
1919:
1920: pset_deallocate(pset);
1921:
1922: /*
1923: * Figure out hold status of thread. Threads assigned to empty
1924: * psets must be held. Therefore:
1925: * If old pset was empty release its hold.
1926: * Release our hold from above unless new pset is empty.
1927: */
1928:
1929: if (old_empty)
1930: thread_release(thread);
1931: if (!new_empty)
1932: thread_release(thread);
1933:
1934: /*
1935: * If current_thread is assigned, context switch to force
1936: * assignment to happen. This also causes hold to take
1937: * effect if the new pset is empty.
1938: */
1939: if (thread == current_thread()) {
1940: s = splsched();
1941: ast_on(cpu_number(), AST_BLOCK);
1942: (void) splx(s);
1943: }
1944: }
1945: #else /* MACH_HOST */
1946: kern_return_t
1947: thread_assign(
1948: thread_t thread,
1949: processor_set_t new_pset)
1950: {
1951: return KERN_FAILURE;
1952: }
1953: #endif /* MACH_HOST */
1954:
1955: /*
1956: * thread_assign_default:
1957: *
1958: * Special version of thread_assign for assigning threads to default
1959: * processor set.
1960: */
1961: kern_return_t
1962: thread_assign_default(
1963: thread_t thread)
1964: {
1965: return thread_assign(thread, &default_pset);
1966: }
1967:
1968: /*
1969: * thread_get_assignment
1970: *
1971: * Return current assignment for this thread.
1972: */
1973: kern_return_t thread_get_assignment(
1974: thread_t thread,
1975: processor_set_t *pset)
1976: {
1977: *pset = thread->processor_set;
1978: pset_reference(*pset);
1979: return KERN_SUCCESS;
1980: }
1981:
1982: /*
1983: * thread_priority:
1984: *
1985: * Set priority (and possibly max priority) for thread.
1986: */
1987: kern_return_t
1988: thread_priority(
1989: thread_t thread,
1990: int priority,
1991: boolean_t set_max)
1992: {
1993: spl_t s;
1994: kern_return_t ret = KERN_SUCCESS;
1995:
1996: if ((thread == THREAD_NULL) || invalid_pri(priority))
1997: return KERN_INVALID_ARGUMENT;
1998:
1999: s = splsched();
2000: thread_lock(thread);
2001:
2002: /*
2003: * Check for violation of max priority
2004: */
2005: if (priority < thread->max_priority) {
2006: ret = KERN_FAILURE;
2007: }
2008: else {
2009: /*
2010: * Set priorities. If a depression is in progress,
2011: * change the priority to restore.
2012: */
2013: if (thread->depress_priority >= 0) {
2014: thread->depress_priority = priority;
2015: }
2016: else {
2017: thread->priority = priority;
2018: compute_priority(thread, TRUE);
2019: }
2020:
2021: if (set_max)
2022: thread->max_priority = priority;
2023: }
2024: thread_unlock(thread);
2025: (void) splx(s);
2026:
2027: return ret;
2028: }
2029:
2030: /*
2031: * thread_set_own_priority:
2032: *
2033: * Internal use only; sets the priority of the calling thread.
2034: * Will adjust max_priority if necessary.
2035: */
2036: void
2037: thread_set_own_priority(
2038: int priority)
2039: {
2040: spl_t s;
2041: thread_t thread = current_thread();
2042:
2043: s = splsched();
2044: thread_lock(thread);
2045:
2046: if (priority < thread->max_priority)
2047: thread->max_priority = priority;
2048: thread->priority = priority;
2049: compute_priority(thread, TRUE);
2050:
2051: thread_unlock(thread);
2052: (void) splx(s);
2053: }
2054:
2055: /*
2056: * thread_max_priority:
2057: *
2058: * Reset the max priority for a thread.
2059: */
2060: kern_return_t
2061: thread_max_priority(
2062: thread_t thread,
2063: processor_set_t pset,
2064: int max_priority)
2065: {
2066: spl_t s;
2067: kern_return_t ret = KERN_SUCCESS;
2068:
2069: if ((thread == THREAD_NULL) || (pset == PROCESSOR_SET_NULL) ||
2070: invalid_pri(max_priority))
2071: return KERN_INVALID_ARGUMENT;
2072:
2073: s = splsched();
2074: thread_lock(thread);
2075:
2076: #if MACH_HOST
2077: /*
2078: * Check for wrong processor set.
2079: */
2080: if (pset != thread->processor_set) {
2081: ret = KERN_FAILURE;
2082: }
2083: else {
2084: #endif /* MACH_HOST */
2085: thread->max_priority = max_priority;
2086:
2087: /*
2088: * Reset priority if it violates new max priority
2089: */
2090: if (max_priority > thread->priority) {
2091: thread->priority = max_priority;
2092:
2093: compute_priority(thread, TRUE);
2094: }
2095: else {
2096: if (thread->depress_priority >= 0 &&
2097: max_priority > thread->depress_priority)
2098: thread->depress_priority = max_priority;
2099: }
2100: #if MACH_HOST
2101: }
2102: #endif /* MACH_HOST */
2103:
2104: thread_unlock(thread);
2105: (void) splx(s);
2106:
2107: return ret;
2108: }
2109:
2110: /*
2111: * thread_policy:
2112: *
2113: * Set scheduling policy for thread.
2114: */
2115: kern_return_t
2116: thread_policy(
2117: thread_t thread,
2118: int policy,
2119: int data)
2120: {
2121: #if MACH_FIXPRI
1.1.1.5 ! root 2122: kern_return_t ret = KERN_SUCCESS;
! 2123: int temp;
1.1 root 2124: spl_t s;
2125: #endif /* MACH_FIXPRI */
2126:
2127: if ((thread == THREAD_NULL) || invalid_policy(policy))
2128: return KERN_INVALID_ARGUMENT;
2129:
2130: #if MACH_FIXPRI
2131: s = splsched();
2132: thread_lock(thread);
2133:
2134: /*
2135: * Check if changing policy.
2136: */
2137: if (policy == thread->policy) {
2138: /*
2139: * Just changing data. This is meaningless for
2140: * timesharing, quantum for fixed priority (but
2141: * has no effect until current quantum runs out).
2142: */
2143: if (policy == POLICY_FIXEDPRI) {
2144: temp = data * 1000;
2145: if (temp % tick)
2146: temp += tick;
2147: thread->sched_data = temp/tick;
2148: }
2149: }
2150: else {
2151: /*
2152: * Changing policy. Check if new policy is allowed.
2153: */
2154: if ((thread->processor_set->policies & policy) == 0) {
2155: ret = KERN_FAILURE;
2156: }
2157: else {
2158: /*
2159: * Changing policy. Save data and calculate new
2160: * priority.
2161: */
2162: thread->policy = policy;
2163: if (policy == POLICY_FIXEDPRI) {
2164: temp = data * 1000;
2165: if (temp % tick)
2166: temp += tick;
2167: thread->sched_data = temp/tick;
2168: }
2169: compute_priority(thread, TRUE);
2170: }
2171: }
2172: thread_unlock(thread);
2173: (void) splx(s);
2174:
2175: return ret;
2176: #else /* MACH_FIXPRI */
2177: if (policy == POLICY_TIMESHARE)
2178: return KERN_SUCCESS;
2179: else
2180: return KERN_FAILURE;
2181: #endif /* MACH_FIXPRI */
2182: }
2183:
2184: /*
2185: * thread_wire:
2186: *
2187: * Specify that the target thread must always be able
2188: * to run and to allocate memory.
2189: */
2190: kern_return_t
2191: thread_wire(
2192: host_t host,
2193: thread_t thread,
2194: boolean_t wired)
2195: {
2196: spl_t s;
2197:
2198: if (host == HOST_NULL)
2199: return KERN_INVALID_ARGUMENT;
2200:
2201: if (thread == THREAD_NULL)
2202: return KERN_INVALID_ARGUMENT;
2203:
2204: /*
2205: * This implementation only works for the current thread.
2206: * See stack_privilege.
2207: */
2208: if (thread != current_thread())
2209: return KERN_INVALID_ARGUMENT;
2210:
2211: s = splsched();
2212: thread_lock(thread);
2213:
2214: if (wired) {
2215: thread->vm_privilege = TRUE;
2216: stack_privilege(thread);
2217: }
2218: else {
2219: thread->vm_privilege = FALSE;
2220: /*XXX stack_unprivilege(thread); */
2221: thread->stack_privilege = 0;
2222: }
2223:
2224: thread_unlock(thread);
2225: splx(s);
2226:
2227: return KERN_SUCCESS;
2228: }
2229:
2230: /*
2231: * thread_collect_scan:
2232: *
2233: * Attempt to free resources owned by threads.
2234: * pcb_collect doesn't do anything yet.
2235: */
2236:
2237: void thread_collect_scan(void)
2238: {
2239: register thread_t thread, prev_thread;
2240: processor_set_t pset, prev_pset;
2241:
2242: prev_thread = THREAD_NULL;
2243: prev_pset = PROCESSOR_SET_NULL;
2244:
2245: simple_lock(&all_psets_lock);
2246: queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
2247: pset_lock(pset);
2248: queue_iterate(&pset->threads, thread, thread_t, pset_threads) {
2249: spl_t s = splsched();
2250: thread_lock(thread);
2251:
2252: /*
2253: * Only collect threads which are
2254: * not runnable and are swapped.
2255: */
2256:
2257: if ((thread->state & (TH_RUN|TH_SWAPPED))
2258: == TH_SWAPPED) {
2259: thread->ref_count++;
2260: thread_unlock(thread);
2261: (void) splx(s);
2262: pset->ref_count++;
2263: pset_unlock(pset);
2264: simple_unlock(&all_psets_lock);
2265:
2266: pcb_collect(thread);
2267:
2268: if (prev_thread != THREAD_NULL)
2269: thread_deallocate(prev_thread);
2270: prev_thread = thread;
2271:
2272: if (prev_pset != PROCESSOR_SET_NULL)
2273: pset_deallocate(prev_pset);
2274: prev_pset = pset;
2275:
2276: simple_lock(&all_psets_lock);
2277: pset_lock(pset);
2278: } else {
2279: thread_unlock(thread);
2280: (void) splx(s);
2281: }
2282: }
2283: pset_unlock(pset);
2284: }
2285: simple_unlock(&all_psets_lock);
2286:
2287: if (prev_thread != THREAD_NULL)
2288: thread_deallocate(prev_thread);
2289: if (prev_pset != PROCESSOR_SET_NULL)
2290: pset_deallocate(prev_pset);
2291: }
2292:
2293: boolean_t thread_collect_allowed = TRUE;
2294: unsigned thread_collect_last_tick = 0;
2295: unsigned thread_collect_max_rate = 0; /* in ticks */
2296:
2297: /*
2298: * consider_thread_collect:
2299: *
2300: * Called by the pageout daemon when the system needs more free pages.
2301: */
2302:
2303: void consider_thread_collect(void)
2304: {
2305: /*
2306: * By default, don't attempt thread collection more frequently
2307: * than once a second.
2308: */
2309:
2310: if (thread_collect_max_rate == 0)
2311: thread_collect_max_rate = hz;
2312:
2313: if (thread_collect_allowed &&
2314: (sched_tick >
2315: (thread_collect_last_tick + thread_collect_max_rate))) {
2316: thread_collect_last_tick = sched_tick;
2317: thread_collect_scan();
2318: }
2319: }
2320:
2321: #if MACH_DEBUG
2322:
2323: vm_size_t stack_usage(
1.1.1.5 ! root 2324: vm_offset_t stack)
1.1 root 2325: {
2326: int i;
2327:
2328: for (i = 0; i < KERNEL_STACK_SIZE/sizeof(unsigned int); i++)
2329: if (((unsigned int *)stack)[i] != STACK_MARKER)
2330: break;
2331:
2332: return KERNEL_STACK_SIZE - i * sizeof(unsigned int);
2333: }
2334:
2335: /*
2336: * Machine-dependent code should call stack_init
2337: * before doing its own initialization of the stack.
2338: */
2339:
2340: void stack_init(
1.1.1.5 ! root 2341: vm_offset_t stack)
1.1 root 2342: {
2343: if (stack_check_usage) {
2344: int i;
2345:
2346: for (i = 0; i < KERNEL_STACK_SIZE/sizeof(unsigned int); i++)
2347: ((unsigned int *)stack)[i] = STACK_MARKER;
2348: }
2349: }
2350:
2351: /*
2352: * Machine-dependent code should call stack_finalize
2353: * before releasing the stack memory.
2354: */
2355:
2356: void stack_finalize(
1.1.1.5 ! root 2357: vm_offset_t stack)
1.1 root 2358: {
2359: if (stack_check_usage) {
2360: vm_size_t used = stack_usage(stack);
2361:
2362: simple_lock(&stack_usage_lock);
2363: if (used > stack_max_usage)
2364: stack_max_usage = used;
2365: simple_unlock(&stack_usage_lock);
2366: }
2367: }
2368:
2369: #ifndef MACHINE_STACK
2370: /*
2371: * stack_statistics:
2372: *
2373: * Return statistics on cached kernel stacks.
2374: * *maxusagep must be initialized by the caller.
2375: */
2376:
2377: void stack_statistics(
2378: natural_t *totalp,
2379: vm_size_t *maxusagep)
2380: {
2381: spl_t s;
2382:
2383: s = splsched();
2384: stack_lock();
2385: if (stack_check_usage) {
2386: vm_offset_t stack;
2387:
2388: /*
2389: * This is pretty expensive to do at splsched,
2390: * but it only happens when someone makes
2391: * a debugging call, so it should be OK.
2392: */
2393:
2394: for (stack = stack_free_list; stack != 0;
2395: stack = stack_next(stack)) {
2396: vm_size_t usage = stack_usage(stack);
2397:
2398: if (usage > *maxusagep)
2399: *maxusagep = usage;
2400: }
2401: }
2402:
2403: *totalp = stack_free_count;
2404: stack_unlock();
2405: (void) splx(s);
2406: }
2407: #endif /* MACHINE_STACK */
2408:
2409: kern_return_t host_stack_usage(
2410: host_t host,
2411: vm_size_t *reservedp,
2412: unsigned int *totalp,
2413: vm_size_t *spacep,
2414: vm_size_t *residentp,
2415: vm_size_t *maxusagep,
2416: vm_offset_t *maxstackp)
2417: {
1.1.1.4 root 2418: natural_t total;
1.1 root 2419: vm_size_t maxusage;
2420:
2421: if (host == HOST_NULL)
2422: return KERN_INVALID_HOST;
2423:
2424: simple_lock(&stack_usage_lock);
2425: maxusage = stack_max_usage;
2426: simple_unlock(&stack_usage_lock);
2427:
2428: stack_statistics(&total, &maxusage);
2429:
2430: *reservedp = 0;
2431: *totalp = total;
2432: *spacep = *residentp = total * round_page(KERNEL_STACK_SIZE);
2433: *maxusagep = maxusage;
2434: *maxstackp = 0;
2435: return KERN_SUCCESS;
2436: }
2437:
2438: kern_return_t processor_set_stack_usage(
2439: processor_set_t pset,
2440: unsigned int *totalp,
2441: vm_size_t *spacep,
2442: vm_size_t *residentp,
2443: vm_size_t *maxusagep,
2444: vm_offset_t *maxstackp)
2445: {
2446: unsigned int total;
2447: vm_size_t maxusage;
2448: vm_offset_t maxstack;
2449:
1.1.1.5 ! root 2450: thread_t *threads;
! 2451: thread_t tmp_thread;
1.1 root 2452:
2453: unsigned int actual; /* this many things */
2454: unsigned int i;
2455:
2456: vm_size_t size, size_needed;
2457: vm_offset_t addr;
2458:
2459: if (pset == PROCESSOR_SET_NULL)
2460: return KERN_INVALID_ARGUMENT;
2461:
2462: size = 0; addr = 0;
2463:
2464: for (;;) {
2465: pset_lock(pset);
2466: if (!pset->active) {
2467: pset_unlock(pset);
2468: return KERN_INVALID_ARGUMENT;
2469: }
2470:
2471: actual = pset->thread_count;
2472:
2473: /* do we have the memory we need? */
2474:
2475: size_needed = actual * sizeof(thread_t);
2476: if (size_needed <= size)
2477: break;
2478:
2479: /* unlock the pset and allocate more memory */
2480: pset_unlock(pset);
2481:
2482: if (size != 0)
2483: kfree(addr, size);
2484:
2485: assert(size_needed > 0);
2486: size = size_needed;
2487:
2488: addr = kalloc(size);
2489: if (addr == 0)
2490: return KERN_RESOURCE_SHORTAGE;
2491: }
2492:
2493: /* OK, have memory and the processor_set is locked & active */
2494:
2495: threads = (thread_t *) addr;
2496: for (i = 0, tmp_thread = (thread_t) queue_first(&pset->threads);
2497: i < actual;
2498: i++,
2499: tmp_thread = (thread_t) queue_next(&tmp_thread->pset_threads)) {
2500: thread_reference(tmp_thread);
2501: threads[i] = tmp_thread;
2502: }
2503: assert(queue_end(&pset->threads, (queue_entry_t) tmp_thread));
2504:
2505: /* can unlock processor set now that we have the thread refs */
2506: pset_unlock(pset);
2507:
2508: /* calculate maxusage and free thread references */
2509:
2510: total = 0;
2511: maxusage = 0;
2512: maxstack = 0;
2513: for (i = 0; i < actual; i++) {
2514: thread_t thread = threads[i];
2515: vm_offset_t stack = 0;
2516:
2517: /*
2518: * thread->kernel_stack is only accurate if the
2519: * thread isn't swapped and is not executing.
2520: *
2521: * Of course, we don't have the appropriate locks
2522: * for these shenanigans.
2523: */
2524:
2525: if ((thread->state & TH_SWAPPED) == 0) {
2526: int cpu;
2527:
2528: stack = thread->kernel_stack;
2529:
2530: for (cpu = 0; cpu < NCPUS; cpu++)
2531: if (active_threads[cpu] == thread) {
2532: stack = active_stacks[cpu];
2533: break;
2534: }
2535: }
2536:
2537: if (stack != 0) {
2538: total++;
2539:
2540: if (stack_check_usage) {
2541: vm_size_t usage = stack_usage(stack);
2542:
2543: if (usage > maxusage) {
2544: maxusage = usage;
2545: maxstack = (vm_offset_t) thread;
2546: }
2547: }
2548: }
2549:
2550: thread_deallocate(thread);
2551: }
2552:
2553: if (size != 0)
2554: kfree(addr, size);
2555:
2556: *totalp = total;
2557: *residentp = *spacep = total * round_page(KERNEL_STACK_SIZE);
2558: *maxusagep = maxusage;
2559: *maxstackp = maxstack;
2560: return KERN_SUCCESS;
2561: }
2562:
2563: /*
2564: * Useful in the debugger:
2565: */
2566: void
2567: thread_stats(void)
2568: {
1.1.1.5 ! root 2569: thread_t thread;
1.1 root 2570: int total = 0, rpcreply = 0;
2571:
2572: queue_iterate(&default_pset.threads, thread, thread_t, pset_threads) {
2573: total++;
2574: if (thread->ith_rpc_reply != IP_NULL)
2575: rpcreply++;
2576: }
2577:
2578: printf("%d total threads.\n", total);
2579: printf("%d using rpc_reply.\n", rpcreply);
2580: }
2581: #endif /* MACH_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.