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