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