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