|
|
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;
1.1.1.8 ! root 345: thread_template.vm_privilege = 0;
1.1 root 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:
1.1.1.8 ! root 1428: #if defined(__i386__) || defined(__x86_64__)
! 1429: if (flavor == i386_DEBUG_STATE && thread == current_thread())
! 1430: /* This state can be obtained directly for the curren thread. */
! 1431: return thread_getstatus(thread, flavor, old_state, old_state_count);
! 1432: #endif
! 1433:
1.1 root 1434: if (thread == THREAD_NULL || thread == current_thread()) {
1435: return KERN_INVALID_ARGUMENT;
1436: }
1437:
1438: thread_hold(thread);
1439: (void) thread_dowait(thread, TRUE);
1440:
1441: ret = thread_getstatus(thread, flavor, old_state, old_state_count);
1442:
1443: thread_release(thread);
1444: return ret;
1445: }
1446:
1447: /*
1448: * Change thread's machine-dependent state.
1449: */
1450: kern_return_t thread_set_state(
1.1.1.5 root 1451: thread_t thread,
1.1 root 1452: int flavor,
1453: thread_state_t new_state,
1454: natural_t new_state_count)
1455: {
1456: kern_return_t ret;
1457:
1.1.1.8 ! root 1458: #if defined(__i386__) || defined(__x86_64__)
! 1459: if (flavor == i386_DEBUG_STATE && thread == current_thread())
! 1460: /* This state can be set directly for the curren thread. */
! 1461: return thread_setstatus(thread, flavor, new_state, new_state_count);
! 1462: #endif
! 1463:
1.1 root 1464: if (thread == THREAD_NULL || thread == current_thread()) {
1465: return KERN_INVALID_ARGUMENT;
1466: }
1467:
1468: thread_hold(thread);
1469: (void) thread_dowait(thread, TRUE);
1470:
1471: ret = thread_setstatus(thread, flavor, new_state, new_state_count);
1472:
1473: thread_release(thread);
1474: return ret;
1475: }
1476:
1477: kern_return_t thread_info(
1.1.1.5 root 1478: thread_t thread,
1.1 root 1479: int flavor,
1480: thread_info_t thread_info_out, /* pointer to OUT array */
1481: natural_t *thread_info_count) /*IN/OUT*/
1482: {
1483: int state, flags;
1484: spl_t s;
1485:
1486: if (thread == THREAD_NULL)
1487: return KERN_INVALID_ARGUMENT;
1488:
1489: if (flavor == THREAD_BASIC_INFO) {
1.1.1.5 root 1490: thread_basic_info_t basic_info;
1.1 root 1491:
1.1.1.3 root 1492: /* Allow *thread_info_count to be one smaller than the
1493: usual amount, because creation_time is a new member
1494: that some callers might not know about. */
1495:
1496: if (*thread_info_count < THREAD_BASIC_INFO_COUNT - 1) {
1.1 root 1497: return KERN_INVALID_ARGUMENT;
1498: }
1499:
1500: basic_info = (thread_basic_info_t) thread_info_out;
1501:
1502: s = splsched();
1503: thread_lock(thread);
1504:
1505: /*
1506: * Update lazy-evaluated scheduler info because someone wants it.
1507: */
1508: if ((thread->state & TH_RUN) == 0 &&
1509: thread->sched_stamp != sched_tick)
1510: update_priority(thread);
1511:
1512: /* fill in info */
1513:
1514: thread_read_times(thread,
1515: &basic_info->user_time,
1516: &basic_info->system_time);
1517: basic_info->base_priority = thread->priority;
1518: basic_info->cur_priority = thread->sched_pri;
1.1.1.6 root 1519: read_time_stamp(&thread->creation_time,
1520: &basic_info->creation_time);
1.1 root 1521:
1522: /*
1523: * To calculate cpu_usage, first correct for timer rate,
1524: * then for 5/8 ageing. The correction factor [3/5] is
1525: * (1/(5/8) - 1).
1526: */
1527: basic_info->cpu_usage = thread->cpu_usage /
1528: (TIMER_RATE/TH_USAGE_SCALE);
1529: basic_info->cpu_usage = (basic_info->cpu_usage * 3) / 5;
1530: #if SIMPLE_CLOCK
1531: /*
1532: * Clock drift compensation.
1533: */
1534: basic_info->cpu_usage =
1535: (basic_info->cpu_usage * 1000000)/sched_usec;
1536: #endif /* SIMPLE_CLOCK */
1537:
1.1.1.2 root 1538: flags = 0;
1.1 root 1539: if (thread->state & TH_SWAPPED)
1.1.1.2 root 1540: flags |= TH_FLAGS_SWAPPED;
1541: if (thread->state & TH_IDLE)
1542: flags |= TH_FLAGS_IDLE;
1.1 root 1543:
1544: if (thread->state & TH_HALTED)
1545: state = TH_STATE_HALTED;
1546: else
1547: if (thread->state & TH_RUN)
1548: state = TH_STATE_RUNNING;
1549: else
1550: if (thread->state & TH_UNINT)
1551: state = TH_STATE_UNINTERRUPTIBLE;
1552: else
1553: if (thread->state & TH_SUSP)
1554: state = TH_STATE_STOPPED;
1555: else
1556: if (thread->state & TH_WAIT)
1557: state = TH_STATE_WAITING;
1558: else
1559: state = 0; /* ? */
1560:
1561: basic_info->run_state = state;
1562: basic_info->flags = flags;
1563: basic_info->suspend_count = thread->user_stop_count;
1564: if (state == TH_STATE_RUNNING)
1565: basic_info->sleep_time = 0;
1566: else
1567: basic_info->sleep_time = sched_tick - thread->sched_stamp;
1568:
1569: thread_unlock(thread);
1570: splx(s);
1571:
1.1.1.3 root 1572: if (*thread_info_count > THREAD_BASIC_INFO_COUNT)
1573: *thread_info_count = THREAD_BASIC_INFO_COUNT;
1.1 root 1574: return KERN_SUCCESS;
1575: }
1576: else if (flavor == THREAD_SCHED_INFO) {
1.1.1.5 root 1577: thread_sched_info_t sched_info;
1.1 root 1578:
1579: if (*thread_info_count < THREAD_SCHED_INFO_COUNT) {
1580: return KERN_INVALID_ARGUMENT;
1581: }
1582:
1583: sched_info = (thread_sched_info_t) thread_info_out;
1584:
1585: s = splsched();
1586: thread_lock(thread);
1587:
1588: #if MACH_FIXPRI
1589: sched_info->policy = thread->policy;
1590: if (thread->policy == POLICY_FIXEDPRI) {
1591: sched_info->data = (thread->sched_data * tick)/1000;
1592: }
1593: else {
1594: sched_info->data = 0;
1595: }
1596: #else /* MACH_FIXPRI */
1597: sched_info->policy = POLICY_TIMESHARE;
1598: sched_info->data = 0;
1599: #endif /* MACH_FIXPRI */
1600:
1601: sched_info->base_priority = thread->priority;
1602: sched_info->max_priority = thread->max_priority;
1603: sched_info->cur_priority = thread->sched_pri;
1604:
1605: sched_info->depressed = (thread->depress_priority >= 0);
1606: sched_info->depress_priority = thread->depress_priority;
1607:
1608: thread_unlock(thread);
1609: splx(s);
1610:
1611: *thread_info_count = THREAD_SCHED_INFO_COUNT;
1612: return KERN_SUCCESS;
1613: }
1614:
1615: return KERN_INVALID_ARGUMENT;
1616: }
1617:
1618: kern_return_t thread_abort(
1.1.1.5 root 1619: thread_t thread)
1.1 root 1620: {
1621: if (thread == THREAD_NULL || thread == current_thread()) {
1622: return KERN_INVALID_ARGUMENT;
1623: }
1624:
1625: /*
1626: *
1627: * clear it of an event wait
1628: */
1629: evc_notify_abort(thread);
1630:
1631: /*
1632: * Try to force the thread to a clean point
1633: * If the halt operation fails return KERN_ABORTED.
1634: * ipc code will convert this to an ipc interrupted error code.
1635: */
1636: if (thread_halt(thread, FALSE) != KERN_SUCCESS)
1637: return KERN_ABORTED;
1638:
1639: /*
1640: * If the thread was in an exception, abort that too.
1641: */
1642: mach_msg_abort_rpc(thread);
1643:
1644: /*
1645: * Then set it going again.
1646: */
1647: thread_release(thread);
1648:
1649: /*
1650: * Also abort any depression.
1651: */
1652: if (thread->depress_priority != -1)
1653: thread_depress_abort(thread);
1654:
1655: return KERN_SUCCESS;
1656: }
1657:
1658: /*
1659: * thread_start:
1660: *
1661: * Start a thread at the specified routine.
1662: * The thread must be in a swapped state.
1663: */
1664:
1665: void
1666: thread_start(
1667: thread_t thread,
1668: continuation_t start)
1669: {
1670: thread->swap_func = start;
1671: }
1672:
1673: /*
1674: * kernel_thread:
1675: *
1676: * Start up a kernel thread in the specified task.
1677: */
1678:
1679: thread_t kernel_thread(
1680: task_t task,
1681: continuation_t start,
1682: void * arg)
1683: {
1.1.1.6 root 1684: kern_return_t kr;
1.1 root 1685: thread_t thread;
1686:
1.1.1.6 root 1687: kr = thread_create(task, &thread);
1688: if (kr != KERN_SUCCESS)
1689: return THREAD_NULL;
1690:
1.1 root 1691: /* release "extra" ref that thread_create gave us */
1692: thread_deallocate(thread);
1693: thread_start(thread, start);
1694: thread->ith_other = arg;
1695:
1696: /*
1697: * We ensure that the kernel thread starts with a stack.
1698: * The swapin mechanism might not be operational yet.
1699: */
1700: thread_doswapin(thread);
1701: thread->max_priority = BASEPRI_SYSTEM;
1702: thread->priority = BASEPRI_SYSTEM;
1703: thread->sched_pri = BASEPRI_SYSTEM;
1704: (void) thread_resume(thread);
1705: return thread;
1706: }
1707:
1708: /*
1709: * reaper_thread:
1710: *
1711: * This kernel thread runs forever looking for threads to destroy
1712: * (when they request that they be destroyed, of course).
1713: */
1.1.1.5 root 1714: void __attribute__((noreturn)) reaper_thread_continue(void)
1.1 root 1715: {
1716: for (;;) {
1.1.1.5 root 1717: thread_t thread;
1.1 root 1718: spl_t s;
1719:
1720: s = splsched();
1721: simple_lock(&reaper_lock);
1722:
1723: while ((thread = (thread_t) dequeue_head(&reaper_queue))
1724: != THREAD_NULL) {
1725: simple_unlock(&reaper_lock);
1726: (void) splx(s);
1727:
1728: (void) thread_dowait(thread, TRUE); /* may block */
1729: thread_deallocate(thread); /* may block */
1730:
1731: s = splsched();
1732: simple_lock(&reaper_lock);
1733: }
1734:
1735: assert_wait((event_t) &reaper_queue, FALSE);
1736: simple_unlock(&reaper_lock);
1737: (void) splx(s);
1738: counter(c_reaper_thread_block++);
1739: thread_block(reaper_thread_continue);
1740: }
1741: }
1742:
1743: void reaper_thread(void)
1744: {
1745: reaper_thread_continue();
1746: /*NOTREACHED*/
1747: }
1748:
1749: #if MACH_HOST
1750: /*
1751: * thread_assign:
1752: *
1753: * Change processor set assignment.
1754: * Caller must hold an extra reference to the thread (if this is
1755: * called directly from the ipc interface, this is an operation
1756: * in progress reference). Caller must hold no locks -- this may block.
1757: */
1758:
1759: kern_return_t
1760: thread_assign(
1761: thread_t thread,
1762: processor_set_t new_pset)
1763: {
1764: if (thread == THREAD_NULL || new_pset == PROCESSOR_SET_NULL) {
1765: return KERN_INVALID_ARGUMENT;
1766: }
1767:
1768: thread_freeze(thread);
1769: thread_doassign(thread, new_pset, TRUE);
1770:
1771: return KERN_SUCCESS;
1772: }
1773:
1774: /*
1775: * thread_freeze:
1776: *
1777: * Freeze thread's assignment. Prelude to assigning thread.
1778: * Only one freeze may be held per thread.
1779: */
1780: void
1781: thread_freeze(
1782: thread_t thread)
1783: {
1784: spl_t s;
1785: /*
1786: * Freeze the assignment, deferring to a prior freeze.
1787: */
1788: s = splsched();
1789: thread_lock(thread);
1790: while (thread->may_assign == FALSE) {
1791: thread->assign_active = TRUE;
1792: thread_sleep((event_t) &thread->assign_active,
1793: simple_lock_addr(thread->lock), FALSE);
1794: thread_lock(thread);
1795: }
1796: thread->may_assign = FALSE;
1797: thread_unlock(thread);
1798: (void) splx(s);
1799:
1800: }
1801:
1802: /*
1803: * thread_unfreeze: release freeze on thread's assignment.
1804: */
1805: void
1806: thread_unfreeze(
1807: thread_t thread)
1808: {
1809: spl_t s;
1810:
1811: s = splsched();
1812: thread_lock(thread);
1813: thread->may_assign = TRUE;
1814: if (thread->assign_active) {
1815: thread->assign_active = FALSE;
1816: thread_wakeup((event_t)&thread->assign_active);
1817: }
1818: thread_unlock(thread);
1819: splx(s);
1820: }
1821:
1822: /*
1823: * thread_doassign:
1824: *
1825: * Actually do thread assignment. thread_will_assign must have been
1826: * called on the thread. release_freeze argument indicates whether
1827: * to release freeze on thread.
1828: */
1829:
1830: void
1831: thread_doassign(
1.1.1.5 root 1832: thread_t thread,
1833: processor_set_t new_pset,
1.1 root 1834: boolean_t release_freeze)
1835: {
1.1.1.5 root 1836: processor_set_t pset;
1837: boolean_t old_empty, new_empty;
1.1 root 1838: boolean_t recompute_pri = FALSE;
1839: spl_t s;
1840:
1841: /*
1842: * Check for silly no-op.
1843: */
1844: pset = thread->processor_set;
1845: if (pset == new_pset) {
1846: if (release_freeze)
1847: thread_unfreeze(thread);
1848: return;
1849: }
1850: /*
1851: * Suspend the thread and stop it if it's not the current thread.
1852: */
1853: thread_hold(thread);
1854: if (thread != current_thread())
1855: (void) thread_dowait(thread, TRUE);
1856:
1857: /*
1858: * Lock both psets now, use ordering to avoid deadlocks.
1859: */
1860: Restart:
1861: if ((vm_offset_t)pset < (vm_offset_t)new_pset) {
1862: pset_lock(pset);
1863: pset_lock(new_pset);
1864: }
1865: else {
1866: pset_lock(new_pset);
1867: pset_lock(pset);
1868: }
1869:
1870: /*
1871: * Check if new_pset is ok to assign to. If not, reassign
1872: * to default_pset.
1873: */
1874: if (!new_pset->active) {
1875: pset_unlock(pset);
1876: pset_unlock(new_pset);
1877: new_pset = &default_pset;
1878: goto Restart;
1879: }
1880:
1881: pset_reference(new_pset);
1882:
1883: /*
1884: * Grab the thread lock and move the thread.
1885: * Then drop the lock on the old pset and the thread's
1886: * reference to it.
1887: */
1888: s = splsched();
1889: thread_lock(thread);
1890:
1891: thread_change_psets(thread, pset, new_pset);
1892:
1893: old_empty = pset->empty;
1894: new_empty = new_pset->empty;
1895:
1896: pset_unlock(pset);
1897:
1898: /*
1899: * Reset policy and priorities if needed.
1900: */
1901: #if MACH_FIXPRI
1902: if (thread->policy & new_pset->policies == 0) {
1903: thread->policy = POLICY_TIMESHARE;
1904: recompute_pri = TRUE;
1905: }
1906: #endif /* MACH_FIXPRI */
1907:
1908: if (thread->max_priority < new_pset->max_priority) {
1909: thread->max_priority = new_pset->max_priority;
1910: if (thread->priority < thread->max_priority) {
1911: thread->priority = thread->max_priority;
1912: recompute_pri = TRUE;
1913: }
1914: else {
1915: if ((thread->depress_priority >= 0) &&
1916: (thread->depress_priority < thread->max_priority)) {
1917: thread->depress_priority = thread->max_priority;
1918: }
1919: }
1920: }
1921:
1922: pset_unlock(new_pset);
1923:
1924: if (recompute_pri)
1925: compute_priority(thread, TRUE);
1926:
1927: if (release_freeze) {
1928: thread->may_assign = TRUE;
1929: if (thread->assign_active) {
1930: thread->assign_active = FALSE;
1931: thread_wakeup((event_t)&thread->assign_active);
1932: }
1933: }
1934:
1935: thread_unlock(thread);
1936: splx(s);
1937:
1938: pset_deallocate(pset);
1939:
1940: /*
1941: * Figure out hold status of thread. Threads assigned to empty
1942: * psets must be held. Therefore:
1943: * If old pset was empty release its hold.
1944: * Release our hold from above unless new pset is empty.
1945: */
1946:
1947: if (old_empty)
1948: thread_release(thread);
1949: if (!new_empty)
1950: thread_release(thread);
1951:
1952: /*
1953: * If current_thread is assigned, context switch to force
1954: * assignment to happen. This also causes hold to take
1955: * effect if the new pset is empty.
1956: */
1957: if (thread == current_thread()) {
1958: s = splsched();
1959: ast_on(cpu_number(), AST_BLOCK);
1960: (void) splx(s);
1961: }
1962: }
1963: #else /* MACH_HOST */
1964: kern_return_t
1965: thread_assign(
1966: thread_t thread,
1967: processor_set_t new_pset)
1968: {
1969: return KERN_FAILURE;
1970: }
1971: #endif /* MACH_HOST */
1972:
1973: /*
1974: * thread_assign_default:
1975: *
1976: * Special version of thread_assign for assigning threads to default
1977: * processor set.
1978: */
1979: kern_return_t
1980: thread_assign_default(
1981: thread_t thread)
1982: {
1983: return thread_assign(thread, &default_pset);
1984: }
1985:
1986: /*
1987: * thread_get_assignment
1988: *
1989: * Return current assignment for this thread.
1990: */
1991: kern_return_t thread_get_assignment(
1992: thread_t thread,
1993: processor_set_t *pset)
1994: {
1.1.1.6 root 1995: if (thread == THREAD_NULL)
1996: return KERN_INVALID_ARGUMENT;
1997:
1.1 root 1998: *pset = thread->processor_set;
1999: pset_reference(*pset);
2000: return KERN_SUCCESS;
2001: }
2002:
2003: /*
2004: * thread_priority:
2005: *
2006: * Set priority (and possibly max priority) for thread.
2007: */
2008: kern_return_t
2009: thread_priority(
2010: thread_t thread,
2011: int priority,
2012: boolean_t set_max)
2013: {
2014: spl_t s;
2015: kern_return_t ret = KERN_SUCCESS;
2016:
2017: if ((thread == THREAD_NULL) || invalid_pri(priority))
2018: return KERN_INVALID_ARGUMENT;
2019:
2020: s = splsched();
2021: thread_lock(thread);
2022:
2023: /*
2024: * Check for violation of max priority
2025: */
2026: if (priority < thread->max_priority) {
2027: ret = KERN_FAILURE;
2028: }
2029: else {
2030: /*
2031: * Set priorities. If a depression is in progress,
2032: * change the priority to restore.
2033: */
2034: if (thread->depress_priority >= 0) {
2035: thread->depress_priority = priority;
2036: }
2037: else {
2038: thread->priority = priority;
2039: compute_priority(thread, TRUE);
2040: }
2041:
2042: if (set_max)
2043: thread->max_priority = priority;
2044: }
2045: thread_unlock(thread);
2046: (void) splx(s);
2047:
2048: return ret;
2049: }
2050:
2051: /*
2052: * thread_set_own_priority:
2053: *
2054: * Internal use only; sets the priority of the calling thread.
2055: * Will adjust max_priority if necessary.
2056: */
2057: void
2058: thread_set_own_priority(
2059: int priority)
2060: {
2061: spl_t s;
2062: thread_t thread = current_thread();
2063:
2064: s = splsched();
2065: thread_lock(thread);
2066:
2067: if (priority < thread->max_priority)
2068: thread->max_priority = priority;
2069: thread->priority = priority;
2070: compute_priority(thread, TRUE);
2071:
2072: thread_unlock(thread);
2073: (void) splx(s);
2074: }
2075:
2076: /*
2077: * thread_max_priority:
2078: *
2079: * Reset the max priority for a thread.
2080: */
2081: kern_return_t
2082: thread_max_priority(
2083: thread_t thread,
2084: processor_set_t pset,
2085: int max_priority)
2086: {
2087: spl_t s;
2088: kern_return_t ret = KERN_SUCCESS;
2089:
2090: if ((thread == THREAD_NULL) || (pset == PROCESSOR_SET_NULL) ||
2091: invalid_pri(max_priority))
2092: return KERN_INVALID_ARGUMENT;
2093:
2094: s = splsched();
2095: thread_lock(thread);
2096:
2097: #if MACH_HOST
2098: /*
2099: * Check for wrong processor set.
2100: */
2101: if (pset != thread->processor_set) {
2102: ret = KERN_FAILURE;
2103: }
2104: else {
2105: #endif /* MACH_HOST */
2106: thread->max_priority = max_priority;
2107:
2108: /*
2109: * Reset priority if it violates new max priority
2110: */
2111: if (max_priority > thread->priority) {
2112: thread->priority = max_priority;
2113:
2114: compute_priority(thread, TRUE);
2115: }
2116: else {
2117: if (thread->depress_priority >= 0 &&
2118: max_priority > thread->depress_priority)
2119: thread->depress_priority = max_priority;
2120: }
2121: #if MACH_HOST
2122: }
2123: #endif /* MACH_HOST */
2124:
2125: thread_unlock(thread);
2126: (void) splx(s);
2127:
2128: return ret;
2129: }
2130:
2131: /*
2132: * thread_policy:
2133: *
2134: * Set scheduling policy for thread.
2135: */
2136: kern_return_t
2137: thread_policy(
2138: thread_t thread,
2139: int policy,
2140: int data)
2141: {
2142: #if MACH_FIXPRI
1.1.1.5 root 2143: kern_return_t ret = KERN_SUCCESS;
2144: int temp;
1.1 root 2145: spl_t s;
2146: #endif /* MACH_FIXPRI */
2147:
2148: if ((thread == THREAD_NULL) || invalid_policy(policy))
2149: return KERN_INVALID_ARGUMENT;
2150:
2151: #if MACH_FIXPRI
2152: s = splsched();
2153: thread_lock(thread);
2154:
2155: /*
2156: * Check if changing policy.
2157: */
2158: if (policy == thread->policy) {
2159: /*
2160: * Just changing data. This is meaningless for
2161: * timesharing, quantum for fixed priority (but
2162: * has no effect until current quantum runs out).
2163: */
2164: if (policy == POLICY_FIXEDPRI) {
2165: temp = data * 1000;
2166: if (temp % tick)
2167: temp += tick;
2168: thread->sched_data = temp/tick;
2169: }
2170: }
2171: else {
2172: /*
2173: * Changing policy. Check if new policy is allowed.
2174: */
2175: if ((thread->processor_set->policies & policy) == 0) {
2176: ret = KERN_FAILURE;
2177: }
2178: else {
2179: /*
2180: * Changing policy. Save data and calculate new
2181: * priority.
2182: */
2183: thread->policy = policy;
2184: if (policy == POLICY_FIXEDPRI) {
2185: temp = data * 1000;
2186: if (temp % tick)
2187: temp += tick;
2188: thread->sched_data = temp/tick;
2189: }
2190: compute_priority(thread, TRUE);
2191: }
2192: }
2193: thread_unlock(thread);
2194: (void) splx(s);
2195:
2196: return ret;
2197: #else /* MACH_FIXPRI */
2198: if (policy == POLICY_TIMESHARE)
2199: return KERN_SUCCESS;
2200: else
2201: return KERN_FAILURE;
2202: #endif /* MACH_FIXPRI */
2203: }
2204:
2205: /*
2206: * thread_wire:
2207: *
2208: * Specify that the target thread must always be able
2209: * to run and to allocate memory.
2210: */
2211: kern_return_t
2212: thread_wire(
2213: host_t host,
2214: thread_t thread,
2215: boolean_t wired)
2216: {
2217: spl_t s;
2218:
2219: if (host == HOST_NULL)
2220: return KERN_INVALID_ARGUMENT;
2221:
2222: if (thread == THREAD_NULL)
2223: return KERN_INVALID_ARGUMENT;
2224:
2225: /*
2226: * This implementation only works for the current thread.
2227: * See stack_privilege.
2228: */
2229: if (thread != current_thread())
2230: return KERN_INVALID_ARGUMENT;
2231:
2232: s = splsched();
2233: thread_lock(thread);
2234:
2235: if (wired) {
1.1.1.8 ! root 2236: thread->vm_privilege = 1;
1.1 root 2237: stack_privilege(thread);
2238: }
2239: else {
1.1.1.8 ! root 2240: thread->vm_privilege = 0;
1.1 root 2241: /*XXX stack_unprivilege(thread); */
2242: thread->stack_privilege = 0;
2243: }
2244:
2245: thread_unlock(thread);
2246: splx(s);
2247:
2248: return KERN_SUCCESS;
2249: }
2250:
2251: /*
2252: * thread_collect_scan:
2253: *
2254: * Attempt to free resources owned by threads.
2255: * pcb_collect doesn't do anything yet.
2256: */
2257:
2258: void thread_collect_scan(void)
2259: {
2260: register thread_t thread, prev_thread;
2261: processor_set_t pset, prev_pset;
2262:
2263: prev_thread = THREAD_NULL;
2264: prev_pset = PROCESSOR_SET_NULL;
2265:
2266: simple_lock(&all_psets_lock);
2267: queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
2268: pset_lock(pset);
2269: queue_iterate(&pset->threads, thread, thread_t, pset_threads) {
2270: spl_t s = splsched();
2271: thread_lock(thread);
2272:
2273: /*
2274: * Only collect threads which are
2275: * not runnable and are swapped.
2276: */
2277:
2278: if ((thread->state & (TH_RUN|TH_SWAPPED))
2279: == TH_SWAPPED) {
2280: thread->ref_count++;
2281: thread_unlock(thread);
2282: (void) splx(s);
2283: pset->ref_count++;
2284: pset_unlock(pset);
2285: simple_unlock(&all_psets_lock);
2286:
2287: pcb_collect(thread);
2288:
2289: if (prev_thread != THREAD_NULL)
2290: thread_deallocate(prev_thread);
2291: prev_thread = thread;
2292:
2293: if (prev_pset != PROCESSOR_SET_NULL)
2294: pset_deallocate(prev_pset);
2295: prev_pset = pset;
2296:
2297: simple_lock(&all_psets_lock);
2298: pset_lock(pset);
2299: } else {
2300: thread_unlock(thread);
2301: (void) splx(s);
2302: }
2303: }
2304: pset_unlock(pset);
2305: }
2306: simple_unlock(&all_psets_lock);
2307:
2308: if (prev_thread != THREAD_NULL)
2309: thread_deallocate(prev_thread);
2310: if (prev_pset != PROCESSOR_SET_NULL)
2311: pset_deallocate(prev_pset);
2312: }
2313:
2314: boolean_t thread_collect_allowed = TRUE;
2315: unsigned thread_collect_last_tick = 0;
2316: unsigned thread_collect_max_rate = 0; /* in ticks */
2317:
2318: /*
2319: * consider_thread_collect:
2320: *
2321: * Called by the pageout daemon when the system needs more free pages.
2322: */
2323:
2324: void consider_thread_collect(void)
2325: {
2326: /*
2327: * By default, don't attempt thread collection more frequently
2328: * than once a second.
2329: */
2330:
2331: if (thread_collect_max_rate == 0)
2332: thread_collect_max_rate = hz;
2333:
2334: if (thread_collect_allowed &&
2335: (sched_tick >
2336: (thread_collect_last_tick + thread_collect_max_rate))) {
2337: thread_collect_last_tick = sched_tick;
2338: thread_collect_scan();
2339: }
2340: }
2341:
2342: #if MACH_DEBUG
2343:
2344: vm_size_t stack_usage(
1.1.1.5 root 2345: vm_offset_t stack)
1.1 root 2346: {
1.1.1.7 root 2347: unsigned i;
1.1 root 2348:
2349: for (i = 0; i < KERNEL_STACK_SIZE/sizeof(unsigned int); i++)
2350: if (((unsigned int *)stack)[i] != STACK_MARKER)
2351: break;
2352:
2353: return KERNEL_STACK_SIZE - i * sizeof(unsigned int);
2354: }
2355:
2356: /*
2357: * Machine-dependent code should call stack_init
2358: * before doing its own initialization of the stack.
2359: */
2360:
2361: void stack_init(
1.1.1.5 root 2362: vm_offset_t stack)
1.1 root 2363: {
2364: if (stack_check_usage) {
1.1.1.7 root 2365: unsigned i;
1.1 root 2366:
2367: for (i = 0; i < KERNEL_STACK_SIZE/sizeof(unsigned int); i++)
2368: ((unsigned int *)stack)[i] = STACK_MARKER;
2369: }
2370: }
2371:
2372: /*
2373: * Machine-dependent code should call stack_finalize
2374: * before releasing the stack memory.
2375: */
2376:
2377: void stack_finalize(
1.1.1.5 root 2378: vm_offset_t stack)
1.1 root 2379: {
2380: if (stack_check_usage) {
2381: vm_size_t used = stack_usage(stack);
2382:
2383: simple_lock(&stack_usage_lock);
2384: if (used > stack_max_usage)
2385: stack_max_usage = used;
2386: simple_unlock(&stack_usage_lock);
2387: }
2388: }
2389:
2390: #ifndef MACHINE_STACK
2391: /*
2392: * stack_statistics:
2393: *
2394: * Return statistics on cached kernel stacks.
2395: * *maxusagep must be initialized by the caller.
2396: */
2397:
2398: void stack_statistics(
2399: natural_t *totalp,
2400: vm_size_t *maxusagep)
2401: {
2402: spl_t s;
2403:
2404: s = splsched();
2405: stack_lock();
2406: if (stack_check_usage) {
2407: vm_offset_t stack;
2408:
2409: /*
2410: * This is pretty expensive to do at splsched,
2411: * but it only happens when someone makes
2412: * a debugging call, so it should be OK.
2413: */
2414:
2415: for (stack = stack_free_list; stack != 0;
2416: stack = stack_next(stack)) {
2417: vm_size_t usage = stack_usage(stack);
2418:
2419: if (usage > *maxusagep)
2420: *maxusagep = usage;
2421: }
2422: }
2423:
2424: *totalp = stack_free_count;
2425: stack_unlock();
2426: (void) splx(s);
2427: }
2428: #endif /* MACHINE_STACK */
2429:
2430: kern_return_t host_stack_usage(
2431: host_t host,
2432: vm_size_t *reservedp,
2433: unsigned int *totalp,
2434: vm_size_t *spacep,
2435: vm_size_t *residentp,
2436: vm_size_t *maxusagep,
2437: vm_offset_t *maxstackp)
2438: {
1.1.1.4 root 2439: natural_t total;
1.1 root 2440: vm_size_t maxusage;
2441:
2442: if (host == HOST_NULL)
2443: return KERN_INVALID_HOST;
2444:
2445: simple_lock(&stack_usage_lock);
2446: maxusage = stack_max_usage;
2447: simple_unlock(&stack_usage_lock);
2448:
2449: stack_statistics(&total, &maxusage);
2450:
2451: *reservedp = 0;
2452: *totalp = total;
2453: *spacep = *residentp = total * round_page(KERNEL_STACK_SIZE);
2454: *maxusagep = maxusage;
2455: *maxstackp = 0;
2456: return KERN_SUCCESS;
2457: }
2458:
2459: kern_return_t processor_set_stack_usage(
2460: processor_set_t pset,
2461: unsigned int *totalp,
2462: vm_size_t *spacep,
2463: vm_size_t *residentp,
2464: vm_size_t *maxusagep,
2465: vm_offset_t *maxstackp)
2466: {
2467: unsigned int total;
2468: vm_size_t maxusage;
2469: vm_offset_t maxstack;
2470:
1.1.1.5 root 2471: thread_t *threads;
2472: thread_t tmp_thread;
1.1 root 2473:
2474: unsigned int actual; /* this many things */
2475: unsigned int i;
2476:
2477: vm_size_t size, size_needed;
2478: vm_offset_t addr;
2479:
2480: if (pset == PROCESSOR_SET_NULL)
2481: return KERN_INVALID_ARGUMENT;
2482:
2483: size = 0; addr = 0;
2484:
2485: for (;;) {
2486: pset_lock(pset);
2487: if (!pset->active) {
2488: pset_unlock(pset);
2489: return KERN_INVALID_ARGUMENT;
2490: }
2491:
2492: actual = pset->thread_count;
2493:
2494: /* do we have the memory we need? */
2495:
2496: size_needed = actual * sizeof(thread_t);
2497: if (size_needed <= size)
2498: break;
2499:
2500: /* unlock the pset and allocate more memory */
2501: pset_unlock(pset);
2502:
2503: if (size != 0)
2504: kfree(addr, size);
2505:
2506: assert(size_needed > 0);
2507: size = size_needed;
2508:
2509: addr = kalloc(size);
2510: if (addr == 0)
2511: return KERN_RESOURCE_SHORTAGE;
2512: }
2513:
2514: /* OK, have memory and the processor_set is locked & active */
2515:
2516: threads = (thread_t *) addr;
2517: for (i = 0, tmp_thread = (thread_t) queue_first(&pset->threads);
2518: i < actual;
2519: i++,
2520: tmp_thread = (thread_t) queue_next(&tmp_thread->pset_threads)) {
2521: thread_reference(tmp_thread);
2522: threads[i] = tmp_thread;
2523: }
2524: assert(queue_end(&pset->threads, (queue_entry_t) tmp_thread));
2525:
2526: /* can unlock processor set now that we have the thread refs */
2527: pset_unlock(pset);
2528:
2529: /* calculate maxusage and free thread references */
2530:
2531: total = 0;
2532: maxusage = 0;
2533: maxstack = 0;
2534: for (i = 0; i < actual; i++) {
2535: thread_t thread = threads[i];
2536: vm_offset_t stack = 0;
2537:
2538: /*
2539: * thread->kernel_stack is only accurate if the
2540: * thread isn't swapped and is not executing.
2541: *
2542: * Of course, we don't have the appropriate locks
2543: * for these shenanigans.
2544: */
2545:
2546: if ((thread->state & TH_SWAPPED) == 0) {
2547: int cpu;
2548:
2549: stack = thread->kernel_stack;
2550:
2551: for (cpu = 0; cpu < NCPUS; cpu++)
2552: if (active_threads[cpu] == thread) {
2553: stack = active_stacks[cpu];
2554: break;
2555: }
2556: }
2557:
2558: if (stack != 0) {
2559: total++;
2560:
2561: if (stack_check_usage) {
2562: vm_size_t usage = stack_usage(stack);
2563:
2564: if (usage > maxusage) {
2565: maxusage = usage;
2566: maxstack = (vm_offset_t) thread;
2567: }
2568: }
2569: }
2570:
2571: thread_deallocate(thread);
2572: }
2573:
2574: if (size != 0)
2575: kfree(addr, size);
2576:
2577: *totalp = total;
2578: *residentp = *spacep = total * round_page(KERNEL_STACK_SIZE);
2579: *maxusagep = maxusage;
2580: *maxstackp = maxstack;
2581: return KERN_SUCCESS;
2582: }
2583:
2584: /*
2585: * Useful in the debugger:
2586: */
2587: void
2588: thread_stats(void)
2589: {
1.1.1.5 root 2590: thread_t thread;
1.1 root 2591: int total = 0, rpcreply = 0;
2592:
2593: queue_iterate(&default_pset.threads, thread, thread_t, pset_threads) {
2594: total++;
2595: if (thread->ith_rpc_reply != IP_NULL)
2596: rpcreply++;
2597: }
2598:
2599: printf("%d total threads.\n", total);
2600: printf("%d using rpc_reply.\n", rpcreply);
2601: }
2602: #endif /* MACH_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.