|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_FREE_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,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: */
52: /*
53: * File: kern/thread.c
54: * Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub
55: * Date: 1986
56: *
57: * Thread/thread_shuttle management primitives implementation.
58: */
59: /*
60: * Copyright (c) 1993 The University of Utah and
61: * the Computer Systems Laboratory (CSL). All rights reserved.
62: *
63: * Permission to use, copy, modify and distribute this software and its
64: * documentation is hereby granted, provided that both the copyright
65: * notice and this permission notice appear in all copies of the
66: * software, derivative works or modified versions, and any portions
67: * thereof, and that both notices appear in supporting documentation.
68: *
69: * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
70: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
71: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
72: *
73: * CSL requests users of this software to return to [email protected] any
74: * improvements that they make and grant CSL redistribution rights.
75: *
76: */
77:
78: #include <cpus.h>
79: #include <mach_host.h>
80: #include <simple_clock.h>
81: #include <mach_debug.h>
82: #include <mach_prof.h>
83: #include <dipc.h>
84: #include <stack_usage.h>
85:
86: #include <mach/boolean.h>
87: #include <mach/policy.h>
88: #include <mach/thread_info.h>
89: #include <mach/thread_special_ports.h>
90: #include <mach/thread_status.h>
91: #include <mach/time_value.h>
92: #include <mach/vm_param.h>
93: #include <kern/ast.h>
94: #include <kern/cpu_data.h>
95: #include <kern/counters.h>
96: #include <kern/etap_macros.h>
97: #include <kern/ipc_mig.h>
98: #include <kern/ipc_tt.h>
99: #include <kern/mach_param.h>
100: #include <kern/machine.h>
101: #include <kern/misc_protos.h>
102: #include <kern/processor.h>
103: #include <kern/queue.h>
104: #include <kern/sched.h>
105: #include <kern/sched_prim.h>
106: #include <kern/sf.h>
107: #include <kern/mk_sp.h> /*** ??? fix so this can be removed ***/
108: #include <kern/task.h>
109: #include <kern/thread.h>
110: #include <kern/thread_act.h>
111: #include <kern/thread_swap.h>
112: #include <kern/host.h>
113: #include <kern/zalloc.h>
114: #include <vm/vm_kern.h>
115: #include <ipc/ipc_kmsg.h>
116: #include <ipc/ipc_port.h>
117: #include <machine/thread.h> /* for MACHINE_STACK */
118: #include <kern/profile.h>
119: #include <kern/assert.h>
120: #include <sys/kdebug.h>
121:
122: /*
123: * Exported interfaces
124: */
125:
126: #include <mach/thread_act_server.h>
127: #include <mach/mach_host_server.h>
128:
129: /*
130: * Per-Cpu stashed global state
131: */
132: vm_offset_t active_stacks[NCPUS]; /* per-cpu active stacks */
133: vm_offset_t kernel_stack[NCPUS]; /* top of active stacks */
134: thread_act_t active_kloaded[NCPUS]; /* + act if kernel loaded */
135:
136: decl_mutex_data(, funnel_lock)
137:
138: struct zone *thread_shuttle_zone;
139:
140: queue_head_t reaper_queue;
141: decl_simple_lock_data(,reaper_lock)
142: thread_call_t thread_reaper_call;
143:
144: extern int tick;
145:
146: extern void pcb_module_init(void);
147:
148: /* private */
149: static struct thread_shuttle thr_sh_template;
150:
151: #if MACH_DEBUG
152: #if STACK_USAGE
153: static void stack_init(vm_offset_t stack, unsigned int bytes);
154: void stack_finalize(vm_offset_t stack);
155: vm_size_t stack_usage(vm_offset_t stack);
156: #else /*STACK_USAGE*/
157: #define stack_init(stack, size)
158: #define stack_finalize(stack)
159: #define stack_usage(stack) (vm_size_t)0
160: #endif /*STACK_USAGE*/
161:
162: #ifdef MACHINE_STACK
163: extern
164: #endif
165: void stack_statistics(
166: unsigned int *totalp,
167: vm_size_t *maxusagep);
168:
169: #define STACK_MARKER 0xdeadbeef
170: #if STACK_USAGE
171: boolean_t stack_check_usage = TRUE;
172: #else /* STACK_USAGE */
173: boolean_t stack_check_usage = FALSE;
174: #endif /* STACK_USAGE */
175: decl_simple_lock_data(,stack_usage_lock)
176: vm_size_t stack_max_usage = 0;
177: vm_size_t stack_max_use = KERNEL_STACK_SIZE - 64;
178: #endif /* MACH_DEBUG */
179:
180: /* Forwards */
181: void thread_collect_scan(void);
182:
183: kern_return_t thread_create_shuttle(
184: thread_act_t thr_act,
185: sp_attributes_t policy_attributes,
186: void (*start_at)(void),
187: thread_t *new_thread);
188:
189: extern void Load_context(
190: thread_t thread);
191:
192:
193: /*
194: * Machine-dependent code must define:
195: * thread_machine_init
196: * thread_machine_terminate
197: * thread_machine_collect
198: *
199: * The thread->pcb field is reserved for machine-dependent code.
200: */
201:
202: #ifdef MACHINE_STACK
203: /*
204: * Machine-dependent code must define:
205: * stack_alloc_try
206: * stack_alloc
207: * stack_free
208: * stack_collect
209: * and if MACH_DEBUG:
210: * stack_statistics
211: */
212: #else /* MACHINE_STACK */
213: /*
214: * We allocate stacks from generic kernel VM.
215: * Machine-dependent code must define:
216: * machine_kernel_stack_init
217: *
218: * The stack_free_list can only be accessed at splsched,
219: * because stack_alloc_try/thread_invoke operate at splsched.
220: */
221:
222: decl_simple_lock_data(,stack_lock_data) /* splsched only */
223: #define stack_lock() simple_lock(&stack_lock_data)
224: #define stack_unlock() simple_unlock(&stack_lock_data)
225:
226: vm_offset_t stack_free_list; /* splsched only */
227: unsigned int stack_free_count = 0; /* splsched only */
228: unsigned int stack_free_limit = 1; /* patchable */
229:
230: unsigned int stack_alloc_hits = 0; /* debugging */
231: unsigned int stack_alloc_misses = 0; /* debugging */
232: unsigned int stack_alloc_max = 0; /* debugging */
233:
234: unsigned int stack_alloc_total = 0;
235: unsigned int stack_alloc_hiwater = 0;
236:
237: /*
238: * The next field is at the base of the stack,
239: * so the low end is left unsullied.
240: */
241:
242: #define stack_next(stack) (*((vm_offset_t *)((stack) + KERNEL_STACK_SIZE) - 1))
243:
244: /*
245: * stack_alloc:
246: *
247: * Allocate a kernel stack for an activation.
248: * May block.
249: */
250: vm_offset_t
251: stack_alloc(
252: thread_t thread,
253: void (*continuation)(void))
254: {
255: vm_offset_t stack;
256: spl_t s;
257:
258: /*
259: * We first try the free list. It is probably empty,
260: * or stack_alloc_try would have succeeded, but possibly
261: * a stack was freed before the swapin thread got to us.
262: */
263:
264: s = splsched();
265: stack_lock();
266: stack = stack_free_list;
267: if (stack != 0) {
268: stack_free_list = stack_next(stack);
269: stack_free_count--;
270: }
271: stack_unlock();
272: splx(s);
273:
274: if (stack == 0) {
275: /*
276: * Kernel stacks should be naturally aligned,
277: * so that it is easy to find the starting/ending
278: * addresses of a stack given an address in the middle.
279: */
280:
281: if (kmem_alloc_aligned(kernel_map, &stack,
282: round_page(KERNEL_STACK_SIZE)) != KERN_SUCCESS)
283: panic("stack_alloc");
284:
285: stack_alloc_total++;
286: if (stack_alloc_total > stack_alloc_hiwater)
287: stack_alloc_hiwater = stack_alloc_total;
288:
289: #if MACH_DEBUG
290: stack_init(stack, round_page(KERNEL_STACK_SIZE));
291: #endif /* MACH_DEBUG */
292:
293: /*
294: * If using fractional pages, free the remainder(s)
295: */
296: if (KERNEL_STACK_SIZE < round_page(KERNEL_STACK_SIZE)) {
297: vm_offset_t ptr = stack + KERNEL_STACK_SIZE;
298: vm_offset_t endp = stack + round_page(KERNEL_STACK_SIZE);
299: while (ptr < endp) {
300: #if MACH_DEBUG
301: /*
302: * We need to initialize just the end of the
303: * region.
304: */
305: stack_init(ptr, (unsigned int) (endp - ptr));
306: #endif
307: stack_lock();
308: stack_next(stack) = stack_free_list;
309: stack_free_list = stack;
310: if (++stack_free_count > stack_alloc_max)
311: stack_alloc_max = stack_free_count;
312: stack_unlock();
313: ptr += KERNEL_STACK_SIZE;
314: }
315: }
316: }
317: stack_attach(thread, stack, continuation);
318: return (stack);
319: }
320:
321: /*
322: * stack_free:
323: *
324: * Free a kernel stack.
325: * Called at splsched.
326: */
327:
328: void
329: stack_free(
330: thread_t thread)
331: {
332: vm_offset_t stack = stack_detach(thread);
333: assert(stack);
334: if (stack != thread->stack_privilege) {
335: stack_lock();
336: stack_next(stack) = stack_free_list;
337: stack_free_list = stack;
338: if (++stack_free_count > stack_alloc_max)
339: stack_alloc_max = stack_free_count;
340: stack_unlock();
341: }
342: }
343:
344: /*
345: * stack_collect:
346: *
347: * Free excess kernel stacks.
348: * May block.
349: */
350:
351: void
352: stack_collect(void)
353: {
354: register vm_offset_t stack;
355: spl_t s;
356:
357: /* If using fractional pages, Cannot just call kmem_free(),
358: * and we're too lazy to coalesce small chunks.
359: */
360: if (KERNEL_STACK_SIZE < round_page(KERNEL_STACK_SIZE))
361: return;
362:
363: s = splsched();
364: stack_lock();
365: while (stack_free_count > stack_free_limit) {
366: stack = stack_free_list;
367: stack_free_list = stack_next(stack);
368: stack_free_count--;
369: stack_unlock();
370: splx(s);
371:
372: #if MACH_DEBUG
373: stack_finalize(stack);
374: #endif /* MACH_DEBUG */
375: kmem_free(kernel_map, stack, KERNEL_STACK_SIZE);
376:
377: s = splsched();
378: stack_alloc_total--;
379: stack_lock();
380: }
381: stack_unlock();
382: splx(s);
383: }
384:
385:
386: #if MACH_DEBUG
387: /*
388: * stack_statistics:
389: *
390: * Return statistics on cached kernel stacks.
391: * *maxusagep must be initialized by the caller.
392: */
393:
394: void
395: stack_statistics(
396: unsigned int *totalp,
397: vm_size_t *maxusagep)
398: {
399: spl_t s;
400:
401: s = splsched();
402: stack_lock();
403:
404: #if STACK_USAGE
405: if (stack_check_usage) {
406: vm_offset_t stack;
407:
408: /*
409: * This is pretty expensive to do at splsched,
410: * but it only happens when someone makes
411: * a debugging call, so it should be OK.
412: */
413:
414: for (stack = stack_free_list; stack != 0;
415: stack = stack_next(stack)) {
416: vm_size_t usage = stack_usage(stack);
417:
418: if (usage > *maxusagep)
419: *maxusagep = usage;
420: }
421: }
422: #endif /* STACK_USAGE */
423:
424: *totalp = stack_free_count;
425: stack_unlock();
426: splx(s);
427: }
428: #endif /* MACH_DEBUG */
429:
430: #endif /* MACHINE_STACK */
431:
432:
433: /*
434: * stack_privilege:
435: *
436: * stack_alloc_try on this thread must always succeed.
437: */
438:
439: void
440: stack_privilege(
441: register thread_t thread)
442: {
443: /*
444: * This implementation only works for the current thread.
445: */
446:
447: if (thread != current_thread())
448: panic("stack_privilege");
449:
450: if (thread->stack_privilege == 0)
451: thread->stack_privilege = current_stack();
452: }
453:
454: /*
455: * stack_alloc_try:
456: *
457: * Non-blocking attempt to allocate a kernel stack.
458: * Called at splsched with the thread locked.
459: */
460:
461: boolean_t stack_alloc_try(
462: thread_t thread,
463: void (*resume)(void))
464: {
465: register vm_offset_t stack;
466:
467: if ((stack = thread->stack_privilege) == (vm_offset_t)0) {
468: stack_lock();
469: stack = stack_free_list;
470: if (stack != (vm_offset_t)0) {
471: stack_free_list = stack_next(stack);
472: stack_free_count--;
473: }
474: stack_unlock();
475: }
476:
477: if (stack != 0) {
478: stack_attach(thread, stack, resume);
479: stack_alloc_hits++;
480: return TRUE;
481: } else {
482: stack_alloc_misses++;
483: return FALSE;
484: }
485: }
486:
487: void
488: thread_init(void)
489: {
490: thread_shuttle_zone = zinit(
491: sizeof(struct thread_shuttle),
492: THREAD_MAX * sizeof(struct thread_shuttle),
493: THREAD_CHUNK * sizeof(struct thread_shuttle),
494: "threads");
495:
496: /*
497: * Fill in a template thread_shuttle for fast initialization.
498: * [Fields that must be (or are typically) reset at
499: * time of creation are so noted.]
500: */
501:
502: /* thr_sh_template.links (none) */
503: thr_sh_template.runq = RUN_QUEUE_NULL;
504:
505:
506: /* thr_sh_template.task (later) */
507: /* thr_sh_template.thread_list (later) */
508: /* thr_sh_template.pset_threads (later) */
509:
510: /* one ref for being alive, one to return to the creator */
511: thr_sh_template.ref_count = 2;
512:
513: thr_sh_template.wait_event = NO_EVENT;
514: thr_sh_template.wait_result = KERN_SUCCESS;
515: thr_sh_template.wait_queue = WAIT_QUEUE_NULL;
516: thr_sh_template.wake_active = FALSE;
517: /*thr_sh_template.state = TH_SUSP;*/
518: thr_sh_template.state = 0;
519: thr_sh_template.continuation = (void (*)(void))thread_bootstrap_return;
520: thr_sh_template.top_act = THR_ACT_NULL;
521:
522: /* thr_sh_template.priority (later) */
523: /***??? thr_sh_template.max_priority = BASEPRI_USER; ***/
524: /* thr_sh_template.sched_pri (later - compute_priority) */
525: /***??? thr_sh_template.sched_data = 0; ***/
526: thr_sh_template.policy = POLICY_TIMESHARE;
527: /***??? thr_sh_template.depress_priority = -1; ***/
528: /***??? thr_sh_template.cpu_usage = 0; ***/
529: /***??? thr_sh_template.sched_usage = 0; ***/
530: /* thr_sh_template.sched_stamp (later) */
531: /***??? thr_sh_template.sched_change_stamp = 1; ***/
532:
533: thr_sh_template.vm_privilege = FALSE;
534:
535: /* thr_sh_template.<IPC structures> (later) */
536:
537: timer_init(&(thr_sh_template.user_timer));
538: timer_init(&(thr_sh_template.system_timer));
539: thr_sh_template.user_timer_save.low = 0;
540: thr_sh_template.user_timer_save.high = 0;
541: thr_sh_template.system_timer_save.low = 0;
542: thr_sh_template.system_timer_save.high = 0;
543: thr_sh_template.cpu_delta = 0;
544: thr_sh_template.sched_delta = 0;
545:
546: thr_sh_template.active = FALSE; /* reset */
547:
548: /* thr_sh_template.processor_set (later) */
549: #if NCPUS > 1
550: thr_sh_template.bound_processor = PROCESSOR_NULL;
551: #endif /*NCPUS > 1*/
552: #if MACH_HOST
553: thr_sh_template.may_assign = TRUE;
554: thr_sh_template.assign_active = FALSE;
555: #endif /* MACH_HOST */
556: thr_sh_template.funnel_state = 0;
557:
558: #if NCPUS > 1
559: /* thr_sh_template.last_processor (later) */
560: #endif /* NCPUS > 1 */
561:
562: /*
563: * Initialize other data structures used in
564: * this module.
565: */
566:
567: queue_init(&reaper_queue);
568: simple_lock_init(&reaper_lock, ETAP_THREAD_REAPER);
569: mutex_init(&funnel_lock,0);
570:
571: #ifndef MACHINE_STACK
572: simple_lock_init(&stack_lock_data, ETAP_THREAD_STACK);
573: #endif /* MACHINE_STACK */
574:
575: #if MACH_DEBUG
576: simple_lock_init(&stack_usage_lock, ETAP_THREAD_STACK_USAGE);
577: #endif /* MACH_DEBUG */
578:
579: #if MACH_LDEBUG
580: thr_sh_template.kthread = FALSE;
581: thr_sh_template.mutex_count = 0;
582: #endif /* MACH_LDEBUG */
583:
584: /*
585: * Initialize any machine-dependent
586: * per-thread structures necessary.
587: */
588: thread_machine_init();
589: }
590:
591: void
592: thread_reaper_enqueue(
593: thread_t thread)
594: {
595: /*
596: * thread lock is already held, splsched()
597: * not necessary here.
598: */
599: simple_lock(&reaper_lock);
600:
601: enqueue_tail(&reaper_queue, (queue_entry_t)thread);
602: #if 0 /* CHECKME! */
603: /*
604: * Since thread has been put in the reaper_queue, it must no longer
605: * be preempted (otherwise, it could be put back in a run queue).
606: */
607: thread->preempt = TH_NOT_PREEMPTABLE;
608: #endif
609:
610: simple_unlock(&reaper_lock);
611:
612: thread_call_enter(thread_reaper_call);
613: }
614:
615: void
616: thread_terminate_self(void)
617: {
618: register thread_t thread = current_thread();
619: thread_act_t thr_act, prev_act;
620: task_t task;
621: sched_policy_t *policy;
622: spl_t s;
623:
624: /*
625: * Check for rpc chain. If so, switch to the previous
626: * activation, set error code, switch stacks and jump
627: * to mach_rpc_return_error.
628: */
629: thr_act = thread->top_act;
630: thread = thr_act->thread;
631: task = thr_act->task;
632:
633: if (task) {
634: time_value_t user_time, system_time;
635: void *proc = NULL;
636:
637: /*
638: * Accumulate times for dead threads into task.
639: */
640: thread_read_times(thread, &user_time, &system_time);
641:
642: task_lock(task);
643: time_value_add(&task->total_user_time, &user_time);
644: time_value_add(&task->total_system_time, &system_time);
645: if (task->thr_act_count == 1)
646: proc = task->bsd_info;
647: task_unlock(task);
648:
649: if (proc)
650: proc_exit(proc);
651: }
652:
653: thread = act_lock_thread(thr_act);
654:
655: /* Unlink the thr_act from the task's thr_act list,
656: * so it doesn't appear in calls to task_threads and such.
657: * The thr_act still keeps its ref on the task, however.
658: */
659: task_lock(task);
660: mutex_lock(&task->act_list_lock);
661: queue_remove(&task->thr_acts, thr_act, thread_act_t, thr_acts);
662:
663: /*
664: * Decrement the act count for this task.
665: */
666: task->thr_act_count--;
667:
668: #if THREAD_SWAPPER
669: /*
670: * Thread is supposed to be unswappable by now...
671: */
672: assert(thr_act->swap_state == TH_SW_UNSWAPPABLE ||
673: !(thread_swap_unwire_stack ||
674: thread_swap_unwire_user_stack));
675: #endif /* THREAD_SWAPPER */
676: task->res_act_count--;
677: thr_act->thr_acts.next = NULL;
678: mutex_unlock(&task->act_list_lock);
679: task_unlock(task);
680:
681: #ifdef CALLOUT_RPC_MODEL
682: if (thr_act->lower) {
683: /*
684: * JMM - RPC will not be using a callout/stack manipulation
685: * mechanism. instead we will let it return normally as if
686: * from a continuation. Accordingly, these need to be cleaned
687: * up a bit.
688: */
689: act_unlock(thr_act);
690: act_switch_swapcheck(thread, (ipc_port_t)0);
691: act_lock(thr_act); /* hierarchy violation XXX */
692: (void) switch_act(THR_ACT_NULL);
693: assert(thr_act->ref_count == 1); /* XXX */
694: /* act_deallocate(thr_act); XXX */
695: prev_act = thread->top_act;
696: /* disable preemption to protect kernel stack changes */
697: disable_preemption();
698: MACH_RPC_RET(prev_act) = KERN_RPC_SERVER_TERMINATED;
699: * machine_kernel_stack_init(thread,
700: * (void (*)(void)) mach_rpc_return_error);
701: * Load_context(thread);
702: */
703: /* NOTREACHED */
704: }
705:
706: #else /* !CALLOUT_RPC_MODEL */
707:
708: assert(!thr_act->lower);
709:
710: #endif /* CALLOUT_RPC_MODEL */
711:
712: act_unlock_thread(thr_act);
713:
714: s = splsched();
715: thread_lock(thread);
716: policy = &sched_policy[thread->policy];
717: thr_act = thread->top_act;
718: thread->active = FALSE;
719: thread_unlock(thread);
720: splx(s);
721:
722: policy->sp_ops.sp_thread_depress_abort(policy, thread);
723: thread_cancel_timer();
724:
725: /* flush any lazy HW state while in own context */
726: thread_machine_flush(thr_act);
727:
728: /* Reap times from dying threads */
729: ipc_thr_act_disable(thr_act);
730:
731: /*
732: * the test for task_active seems unnecessary because
733: * the thread holds a reference to the task (so it
734: * can't be deleted out from under it).
735: */
736: if( task && task->active) {
737: #if THREAD_SWAPPER
738: thread_swap_disable(thr_act);
739: #endif /* THREAD_SWAPPER */
740:
741: task_lock(task);
742:
743: /* Make act inactive iff it was born as a base activation */
744: act_lock_thread(thr_act);
745: if( thr_act->active && (thr_act->pool_port == IP_NULL))
746: act_disable_task_locked( thr_act );
747: act_unlock_thread(thr_act);
748: task_unlock( task );
749: }
750:
751: thread_deallocate(thread); /* take caller's ref; 1 left for reaper */
752:
753: ipc_thread_terminate(thread);
754:
755: s = splsched();
756: thread_lock(thread);
757: thread->state |= (TH_HALTED|TH_TERMINATE);
758: assert((thread->state & TH_UNINT) == 0);
759: #if 0 /* CHECKME! */
760: /*
761: * Since thread has been put in the reaper_queue, it must no longer
762: * be preempted (otherwise, it could be put back in a run queue).
763: */
764: thread->preempt = TH_NOT_PREEMPTABLE;
765: #endif
766: thread_mark_wait_locked(thread);
767: thread_unlock(thread);
768: /* splx(s); */
769:
770: ETAP_SET_REASON(thread, BLOCKED_ON_TERMINATION);
771: thread_block((void (*)(void)) 0);
772: panic("the zombie walks!");
773: /*NOTREACHED*/
774: }
775:
776:
777: /*
778: * Create a new thread in the specified activation (i.e. "populate" the
779: * activation). The activation can be either user or kernel, but it must
780: * be brand-new: no thread, no pool_port, nobody else knows about it.
781: * Doesn't start the thread running; use thread_setrun to start it.
782: */
783: kern_return_t
784: thread_create_shuttle(
785: thread_act_t thr_act,
786: sp_attributes_t attributes,
787: void (*start_at)(void),
788: thread_t *new_thread)
789: {
790: thread_t new_shuttle;
791: task_t parent_task = thr_act->task;
792: processor_set_t pset;
793: kern_return_t result;
794: sched_policy_t *policy;
795: sf_return_t sfr;
796: int suspcnt;
797:
798: /*
799: * Allocate a thread and initialize static fields
800: */
801: new_shuttle = (thread_t)zalloc(thread_shuttle_zone);
802: if (new_shuttle == THREAD_NULL)
803: return (KERN_RESOURCE_SHORTAGE);
804:
805: *new_shuttle = thr_sh_template;
806:
807: /* Allocate space for scheduling information and attributes */
808: /*** Think about integrating with shuttle structure someday ***/
809: new_shuttle->sp_info = (sp_info_t)kalloc(max_sched_info_size);
810: if (new_shuttle->sp_info == SP_INFO_NULL) {
811: zfree(thread_shuttle_zone, (vm_offset_t)new_shuttle);
812: return (KERN_RESOURCE_SHORTAGE);
813: }
814: new_shuttle->pending_sched_attr =
815: (sp_attributes_t)kalloc(max_sched_attributes_size);
816: if (new_shuttle->pending_sched_attr == SP_ATTRIBUTES_NULL) {
817: kfree((vm_offset_t)new_shuttle->sp_info,
818: (vm_size_t)max_sched_info_size);
819: zfree(thread_shuttle_zone, (vm_offset_t)new_shuttle);
820: return (KERN_RESOURCE_SHORTAGE);
821: }
822:
823: thread_lock_init(new_shuttle);
824: rpc_lock_init(new_shuttle);
825: wake_lock_init(new_shuttle);
826: new_shuttle->sleep_stamp = sched_tick;
827:
828: /*
829: * No need to lock thr_act, since it can't be known to anyone --
830: * we set its suspend_count to one more than the task suspend_count
831: * by calling thread_hold.
832: */
833: thr_act->user_stop_count = 1;
834: for (suspcnt = thr_act->task->suspend_count + 1; suspcnt; --suspcnt)
835: thread_hold(thr_act);
836:
837: simple_lock_init(&new_shuttle->lock, ETAP_THREAD_NEW);
838:
839: /*
840: * Initialize system-dependent part.
841: */
842: result = thread_machine_create(new_shuttle, thr_act, start_at);
843: if (result != KERN_SUCCESS) {
844: kfree((vm_offset_t)new_shuttle->pending_sched_attr,
845: (vm_size_t)max_sched_attributes_size);
846: kfree((vm_offset_t)new_shuttle->sp_info,
847: (vm_size_t)max_sched_info_size);
848: zfree(thread_shuttle_zone, (vm_offset_t)new_shuttle);
849: return (result);
850: }
851:
852: /* Attach the thread to the activation. */
853: assert(!thr_act->thread);
854: assert(!thr_act->pool_port);
855: /* Synchronize with act_lock_thread() et al. */
856: act_lock(thr_act);
857: /* Thread holds a ref to the thr_act */
858: act_locked_act_reference(thr_act);
859: act_attach(thr_act, new_shuttle, 0);
860: act_unlock(thr_act);
861:
862: /*
863: * Initialize runtime-dependent fields
864: */
865: thread_timer_setup(new_shuttle);
866: machine_kernel_stack_init(new_shuttle, (void (*)(void))thread_continue);
867: ipc_thread_init(new_shuttle);
868: thread_start(new_shuttle, start_at);
869:
870: pset = parent_task->processor_set;
871: if (!pset->active) {
872: pset = &default_pset;
873: }
874: pset_lock(pset);
875:
876: task_lock(parent_task);
877:
878: if (attributes == SP_ATTRIBUTES_NULL)
879: attributes = parent_task->sp_attributes;
880:
881: /* Associate the thread with that scheduling policy */
882: new_shuttle->policy = attributes->policy_id;
883: policy = &sched_policy[new_shuttle->policy];
884: sfr = policy->sp_ops.sp_thread_attach(policy, new_shuttle);
885: if (sfr != SF_SUCCESS)
886: panic("thread_create_shuttle: sp_thread_attach");
887:
888: /* Indicate that no change in scheduling policy is pending */
889: new_shuttle->pending_policy = POLICY_NULL;
890:
891: /* Associate the thread with the processor set */
892: sfr = policy->sp_ops.sp_thread_processor_set(policy, new_shuttle, pset);
893: if (sfr != SF_SUCCESS)
894: panic("thread_create_shuttle: sp_thread_proceessor_set");
895:
896: /* Set the thread's scheduling parameters */
897: sfr = policy->sp_ops.sp_thread_set(policy, new_shuttle, attributes);
898: if (sfr != SF_SUCCESS)
899: panic("thread_create_shuttle: sp_thread_set");
900:
901: /***
902: *** ??? Have to do something here. I want the call above to
903: *** send the parameters to the policy and have the policy do
904: *** its thing. Unfortunately, I can't see the "artful" way
905: *** to use the current MK SP routines to do this without
906: *** alteration.
907: ***
908: *** I must return to this.
909: ***
910: *** Perhaps a state bit should be associated with each thread
911: *** under the MK SP indicating whether that thread is runnable.
912: *** If it is not, `compute_priority()' or one of its siblings
913: *** is used to adjust scheduling parameter values; if it is
914: *** runnable, then the scheduling parameter adjustments can be
915: *** followed by code that tries to place the thread on the
916: *** appropriate run queue, or tries to run it immediately.
917: ***/
918:
919: #if ETAP_EVENT_MONITOR
920: new_thread->etap_reason = 0;
921: new_thread->etap_trace = FALSE;
922: #endif /* ETAP_EVENT_MONITOR */
923:
924: new_shuttle->active = TRUE;
925:
926: /*
927: * Don't need to initialize because the context switch
928: * code will set it before it can be used.
929: */
930: if (!parent_task->active) {
931: task_unlock(parent_task);
932: pset_unlock(pset);
933: thread_deallocate(new_shuttle);
934: /* Drop ref we'd have given caller */
935: thread_deallocate(new_shuttle);
936:
937: return (KERN_FAILURE);
938: }
939:
940: task_unlock(parent_task);
941: pset_unlock(pset);
942:
943: *new_thread = new_shuttle;
944:
945: {
946: long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4;
947:
948: KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_DATA, 1)) | DBG_FUNC_NONE,
949: new_shuttle, 0,0,0,0);
950:
951: kdbg_trace_string(parent_task->bsd_info, &dbg_arg1, &dbg_arg2, &dbg_arg3,
952: &dbg_arg4);
953: KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_STRING, 1)) | DBG_FUNC_NONE,
954: dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0);
955: }
956:
957: return (KERN_SUCCESS);
958: }
959:
960: kern_return_t
961: thread_create(
962: task_t task,
963: thread_act_t *new_act)
964: {
965: thread_act_t thr_act;
966: thread_t thread;
967: kern_return_t result;
968: sched_policy_t *policy;
969: sf_return_t sfr;
970: spl_t s;
971: extern void thread_bootstrap_return(void);
972:
973: result = act_create(task, NULL_PARAMS, &thr_act);
974: if (result != KERN_SUCCESS)
975: return (result);
976:
977: result = thread_create_shuttle(thr_act, SP_ATTRIBUTES_NULL,
978: thread_bootstrap_return, &thread);
979: if (result != KERN_SUCCESS) {
980: thread_terminate(thr_act);
981: act_deallocate(thr_act);
982: return (result);
983: }
984:
985: if (task->kernel_loaded)
986: thread_user_to_kernel(thread);
987:
988: /* Start the thread running (it will immediately suspend itself). */
989: s = splsched();
990: thread_ast_set(thr_act, AST_APC);
991: thread_lock(thread);
992: thread->state |= TH_RUN; /*** ??? I think this is okay ***/
993:
994: /* Allow the thread to execute */
995: policy = &sched_policy[thread->policy];
996: sfr = policy->sp_ops.sp_thread_dispatch(policy, thread);
997: if (sfr != SF_SUCCESS)
998: panic("thread_create: sp_thread_dispatch");
999:
1000: thread_unlock(thread);
1001: splx(s);
1002:
1003: /*****
1004: act_lock_thread(thr_act);
1005: thread_dowait( thr_act, FALSE);
1006: act_unlock_thread(thr_act);
1007: *****/
1008:
1009: *new_act = thr_act;
1010:
1011: return (KERN_SUCCESS);
1012: }
1013:
1014: /*
1015: * Update thread that belongs to a task created via kernel_task_create().
1016: */
1017: void
1018: thread_user_to_kernel(
1019: thread_t thread)
1020: {
1021: /*
1022: * Used to set special swap_func here...
1023: */
1024: }
1025:
1026: kern_return_t
1027: thread_create_running(
1028: register task_t parent_task,
1029: int flavor,
1030: thread_state_t new_state,
1031: mach_msg_type_number_t new_state_count,
1032: thread_act_t *child_act) /* OUT */
1033: {
1034: register kern_return_t result;
1035:
1036: result = thread_create(parent_task, child_act);
1037: if (result != KERN_SUCCESS)
1038: return (result);
1039:
1040: result = act_set_state(*child_act, flavor, new_state, new_state_count);
1041: if (result != KERN_SUCCESS) {
1042: (void) thread_terminate(*child_act);
1043: return (result);
1044: }
1045:
1046: result = thread_resume(*child_act);
1047: if (result != KERN_SUCCESS) {
1048: (void) thread_terminate(*child_act);
1049: return (result);
1050: }
1051:
1052: return (result);
1053: }
1054:
1055: /*
1056: * kernel_thread:
1057: *
1058: * Create and kernel thread in the specified task, and
1059: * optionally start it running.
1060: */
1061: thread_t
1062: kernel_thread_with_attributes(
1063: task_t task,
1064: sp_attributes_t attributes,
1065: void (*start_at)(void),
1066: boolean_t start_running)
1067: {
1068: kern_return_t result;
1069: thread_t thread;
1070: thread_act_t thr_act;
1071: sched_policy_t *policy;
1072: sf_return_t sfr;
1073: spl_t s;
1074:
1075: result = act_create(task, NULL_PARAMS, &thr_act);
1076: if (result != KERN_SUCCESS) {
1077: printf("kernel_thread act_create %x\n", result);
1078: panic("act_create failure");
1079: }
1080:
1081: result = thread_create_shuttle(thr_act, attributes, start_at, &thread);
1082: if (result != KERN_SUCCESS) {
1083: printf("kernel_thread create_shuttle %x\n", result);
1084: panic("create_shuttle failure");
1085: }
1086:
1087: thread_swappable(thr_act, FALSE);
1088:
1089: s = splsched();
1090: thread_lock(thread);
1091:
1092: thr_act = thread->top_act;
1093: #if MACH_LDEBUG
1094: thread->kthread = TRUE;
1095: #endif /* MACH_LDEBUG */
1096:
1097: if (start_running) {
1098: policy = &sched_policy[thread->policy];
1099: thread->state |= TH_RUN;
1100: sfr = policy->sp_ops.sp_thread_unblock(policy, thread);
1101: if (sfr != SF_SUCCESS)
1102: panic("kernel_thread: sp_thread_unblock");
1103: }
1104:
1105: thread_unlock(thread);
1106: splx(s);
1107:
1108: act_deallocate(thr_act);
1109:
1110: if (start_running)
1111: thread_resume(thr_act);
1112:
1113: return (thread);
1114: }
1115:
1116: thread_t
1117: kernel_thread(
1118: task_t task,
1119: void (*start_at)(void))
1120: {
1121: return kernel_thread_with_attributes(
1122: task, SP_ATTRIBUTES_NULL, start_at, TRUE);
1123: }
1124:
1125: unsigned int c_weird_pset_ref_exit = 0; /* pset code raced us */
1126:
1127: void
1128: thread_deallocate(
1129: thread_t thread)
1130: {
1131: task_t task;
1132: processor_set_t pset;
1133: sched_policy_t *policy;
1134: sf_return_t sfr;
1135: spl_t s;
1136:
1137: if (thread == THREAD_NULL)
1138: return;
1139:
1140: /*
1141: * First, check for new count > 0 (the common case).
1142: * Only the thread needs to be locked.
1143: */
1144: s = splsched();
1145: thread_lock(thread);
1146: if (--thread->ref_count > 0) {
1147: thread_unlock(thread);
1148: splx(s);
1149: return;
1150: }
1151:
1152: /*
1153: * Count is zero. However, the processor set's
1154: * thread list has an implicit reference to
1155: * the thread, and may make new ones. Its lock also
1156: * dominate the thread lock. To check for this, we
1157: * temporarily restore the one thread reference, unlock
1158: * the thread, and then lock the pset in the proper order.
1159: */
1160: assert(thread->ref_count == 0); /* Else this is an extra dealloc! */
1161: thread->ref_count++;
1162: thread_unlock(thread);
1163: splx(s);
1164:
1165: #if MACH_HOST
1166: thread_freeze(thread);
1167: #endif /* MACH_HOST */
1168:
1169: pset = thread->processor_set;
1170: pset_lock(pset);
1171:
1172: s = splsched();
1173: thread_lock(thread);
1174:
1175: if (--thread->ref_count > 0) {
1176: #if MACH_HOST
1177: boolean_t need_wakeup = FALSE;
1178: /*
1179: * processor_set made extra reference.
1180: */
1181: /* Inline the unfreeze */
1182: thread->may_assign = TRUE;
1183: if (thread->assign_active) {
1184: need_wakeup = TRUE;
1185: thread->assign_active = FALSE;
1186: }
1187: #endif /* MACH_HOST */
1188: thread_unlock(thread);
1189: splx(s);
1190: pset_unlock(pset);
1191: #if MACH_HOST
1192: if (need_wakeup)
1193: thread_wakeup((event_t)&thread->assign_active);
1194: #endif /* MACH_HOST */
1195: c_weird_pset_ref_exit++;
1196: return;
1197: }
1198: #if MACH_HOST
1199: assert(thread->assign_active == FALSE);
1200: #endif /* MACH_HOST */
1201:
1202: /*
1203: * Thread has no references - we can remove it.
1204: */
1205:
1206: /*
1207: * A quick sanity check
1208: */
1209: if (thread == current_thread())
1210: panic("thread deallocating itself");
1211:
1212: /* Detach thread (shuttle) from its sched policy */
1213: policy = &sched_policy[thread->policy];
1214: sfr = policy->sp_ops.sp_thread_detach(policy, thread);
1215: if (sfr != SF_SUCCESS)
1216: panic("thread_deallocate: sp_thread_detach");
1217:
1218: /* Release storage used for scheduling info and attributes */
1219: assert(thread->pending_sched_attr != SP_ATTRIBUTES_NULL);
1220: kfree((vm_offset_t) thread->pending_sched_attr,
1221: (vm_size_t) max_sched_attributes_size);
1222: assert(thread->sp_info != SP_INFO_NULL);
1223: kfree((vm_offset_t) thread->sp_info,
1224: (vm_size_t) max_sched_info_size);
1225:
1226: pset_remove_thread(pset, thread);
1227:
1228: thread_unlock(thread); /* no more references - safe */
1229: splx(s);
1230: pset_unlock(pset);
1231:
1232: pset_deallocate(thread->processor_set);
1233:
1234: /* frees kernel stack & other MD resources */
1235: thread->stack_privilege = 0;
1236: thread_machine_destroy(thread);
1237:
1238: zfree(thread_shuttle_zone, (vm_offset_t) thread);
1239: }
1240:
1241: void
1242: thread_reference(
1243: thread_t thread)
1244: {
1245: spl_t s;
1246:
1247: if (thread == THREAD_NULL)
1248: return;
1249:
1250: s = splsched();
1251: thread_lock(thread);
1252: thread->ref_count++;
1253: thread_unlock(thread);
1254: splx(s);
1255: }
1256:
1257: /*
1258: * Called with "appropriate" thread-related locks held on
1259: * thread and its top_act for synchrony with RPC (see
1260: * act_lock_thread()).
1261: */
1262: kern_return_t
1263: thread_info_shuttle(
1264: register thread_act_t thr_act,
1265: thread_flavor_t flavor,
1266: thread_info_t thread_info_out, /* ptr to OUT array */
1267: mach_msg_type_number_t *thread_info_count) /*IN/OUT*/
1268: {
1269: register thread_t thread = thr_act->thread;
1270: int state, flags;
1271: spl_t s;
1272:
1273: if (thread == THREAD_NULL)
1274: return (KERN_INVALID_ARGUMENT);
1275:
1276: if (flavor == THREAD_BASIC_INFO) {
1277: register thread_basic_info_t basic_info;
1278:
1279: if (*thread_info_count < THREAD_BASIC_INFO_COUNT)
1280: return (KERN_INVALID_ARGUMENT);
1281:
1282: basic_info = (thread_basic_info_t) thread_info_out;
1283:
1284: s = splsched();
1285: thread_lock(thread);
1286:
1287: /* fill in info */
1288:
1289: thread_read_times(thread, &basic_info->user_time,
1290: &basic_info->system_time);
1291:
1292: /*** ??? fix me ***/
1293: if (thread->policy & (POLICY_TIMESHARE|POLICY_RR|POLICY_FIFO)) {
1294: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info;
1295:
1296: /*
1297: * Update lazy-evaluated scheduler info because someone wants it.
1298: */
1299: assert(sp_info != SP_INFO_NULL);
1300: if (sp_info->sched_stamp != sched_tick)
1301: update_priority(thread);
1302:
1303: basic_info->sleep_time = 0;
1304:
1305: /*
1306: * To calculate cpu_usage, first correct for timer rate,
1307: * then for 5/8 ageing. The correction factor [3/5] is
1308: * (1/(5/8) - 1).
1309: */
1310: basic_info->cpu_usage = sp_info->cpu_usage /
1311: (TIMER_RATE / TH_USAGE_SCALE);
1312: basic_info->cpu_usage = (basic_info->cpu_usage * 3) / 5;
1313: #if SIMPLE_CLOCK
1314: /*
1315: * Clock drift compensation.
1316: */
1317: basic_info->cpu_usage =
1318: (basic_info->cpu_usage * 1000000) / sched_usec;
1319: #endif /* SIMPLE_CLOCK */
1320: }
1321: else
1322: basic_info->sleep_time = basic_info->cpu_usage = 0;
1323:
1324: basic_info->policy = thread->policy;
1325:
1326: flags = 0;
1327: if (thread->state & TH_SWAPPED_OUT)
1328: flags = TH_FLAGS_SWAPPED;
1329: else
1330: if (thread->state & TH_IDLE)
1331: flags = TH_FLAGS_IDLE;
1332:
1333: state = 0;
1334: if (thread->state & TH_HALTED)
1335: state = TH_STATE_HALTED;
1336: else
1337: if (thread->state & TH_RUN)
1338: state = TH_STATE_RUNNING;
1339: else
1340: if (thread->state & TH_UNINT)
1341: state = TH_STATE_UNINTERRUPTIBLE;
1342: else
1343: if (thread->state & TH_SUSP)
1344: state = TH_STATE_STOPPED;
1345: else
1346: if (thread->state & TH_WAIT)
1347: state = TH_STATE_WAITING;
1348:
1349: basic_info->run_state = state;
1350: basic_info->flags = flags;
1351:
1352: basic_info->suspend_count = thr_act->user_stop_count;
1353:
1354: thread_unlock(thread);
1355: splx(s);
1356:
1357: *thread_info_count = THREAD_BASIC_INFO_COUNT;
1358:
1359: return (KERN_SUCCESS);
1360: }
1361: else
1362: if (flavor == THREAD_SCHED_TIMESHARE_INFO) {
1363: policy_timeshare_info_t ts_info;
1364: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info;
1365:
1366: if (*thread_info_count < POLICY_TIMESHARE_INFO_COUNT)
1367: return (KERN_INVALID_ARGUMENT);
1368:
1369: ts_info = (policy_timeshare_info_t)thread_info_out;
1370:
1371: s = splsched();
1372: thread_lock(thread);
1373:
1374: if (thread->policy != POLICY_TIMESHARE) {
1375: thread_unlock(thread);
1376: splx(s);
1377:
1378: return (KERN_INVALID_POLICY);
1379: }
1380:
1381: /*** ??? fix me ***/
1382: assert(sp_info != SP_INFO_NULL);
1383: ts_info->base_priority = sp_info->priority;
1384: ts_info->max_priority = sp_info->max_priority;
1385: ts_info->cur_priority = thread->sched_pri;
1386:
1387: ts_info->depressed = (sp_info->depress_priority >= 0);
1388: ts_info->depress_priority = sp_info->depress_priority;
1389:
1390: thread_unlock(thread);
1391: splx(s);
1392:
1393: *thread_info_count = POLICY_TIMESHARE_INFO_COUNT;
1394:
1395: return (KERN_SUCCESS);
1396: }
1397: else
1398: if (flavor == THREAD_SCHED_FIFO_INFO) {
1399: policy_fifo_info_t fifo_info;
1400: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info;
1401:
1402: if (*thread_info_count < POLICY_FIFO_INFO_COUNT)
1403: return (KERN_INVALID_ARGUMENT);
1404:
1405: fifo_info = (policy_fifo_info_t)thread_info_out;
1406:
1407: s = splsched();
1408: thread_lock(thread);
1409:
1410: if (thread->policy != POLICY_FIFO) {
1411: thread_unlock(thread);
1412: splx(s);
1413:
1414: return (KERN_INVALID_POLICY);
1415: }
1416:
1417: /*** ??? fix me ***/
1418: assert(sp_info != SP_INFO_NULL);
1419: fifo_info->base_priority = sp_info->priority;
1420: fifo_info->max_priority = sp_info->max_priority;
1421:
1422: fifo_info->depressed = (sp_info->depress_priority >= 0);
1423: fifo_info->depress_priority = sp_info->depress_priority;
1424:
1425: thread_unlock(thread);
1426: splx(s);
1427:
1428: *thread_info_count = POLICY_FIFO_INFO_COUNT;
1429:
1430: return (KERN_SUCCESS);
1431: }
1432: else
1433: if (flavor == THREAD_SCHED_RR_INFO) {
1434: policy_rr_info_t rr_info;
1435: mk_sp_info_t sp_info = (mk_sp_info_t)thread->sp_info;
1436:
1437: if (*thread_info_count < POLICY_RR_INFO_COUNT)
1438: return (KERN_INVALID_ARGUMENT);
1439:
1440: rr_info = (policy_rr_info_t) thread_info_out;
1441:
1442: s = splsched();
1443: thread_lock(thread);
1444:
1445: if (thread->policy != POLICY_RR) {
1446: thread_unlock(thread);
1447: splx(s);
1448:
1449: return (KERN_INVALID_POLICY);
1450: }
1451:
1452: /*** ??? fix me ***/
1453: assert(sp_info != SP_INFO_NULL);
1454: rr_info->base_priority = sp_info->priority;
1455: rr_info->max_priority = sp_info->max_priority;
1456:
1457: rr_info->quantum = (sp_info->sched_data * tick) / 1000;
1458:
1459: rr_info->depressed = (sp_info->depress_priority >= 0);
1460: rr_info->depress_priority = sp_info->depress_priority;
1461:
1462: thread_unlock(thread);
1463: splx(s);
1464:
1465: *thread_info_count = POLICY_RR_INFO_COUNT;
1466:
1467: return (KERN_SUCCESS);
1468: }
1469:
1470: return (KERN_INVALID_ARGUMENT);
1471: }
1472:
1473: void
1474: thread_doreap(
1475: register thread_t thread)
1476: {
1477: thread_act_t thr_act;
1478: struct ipc_port *pool_port;
1479:
1480:
1481: thr_act = thread_lock_act(thread);
1482: assert(thr_act && thr_act->thread == thread);
1483:
1484: act_locked_act_reference(thr_act);
1485: pool_port = thr_act->pool_port;
1486:
1487: /*
1488: * Replace `act_unlock_thread()' with individual
1489: * calls. (`act_detach()' can change fields used
1490: * to determine which locks are held, confusing
1491: * `act_unlock_thread()'.)
1492: */
1493: rpc_unlock(thread);
1494: if (pool_port != IP_NULL)
1495: ip_unlock(pool_port);
1496: act_unlock(thr_act);
1497:
1498: /* Remove the reference held by a rooted thread */
1499: if (pool_port == IP_NULL)
1500: act_deallocate(thr_act);
1501:
1502: /* Remove the reference held by the thread: */
1503: act_deallocate(thr_act);
1504: }
1505:
1506: static thread_call_data_t thread_reaper_call_data;
1507:
1508: /*
1509: * reaper_thread:
1510: *
1511: * This kernel thread runs forever looking for threads to destroy
1512: * (when they request that they be destroyed, of course).
1513: *
1514: * The reaper thread will disappear in the next revision of thread
1515: * control when it's function will be moved into thread_dispatch.
1516: */
1517: void
1518: thread_reaper(void)
1519: {
1520: register thread_t thread;
1521: spl_t s;
1522:
1523: s = splsched();
1524: simple_lock(&reaper_lock);
1525:
1526: if (thread_reaper_call == NULL) {
1527: thread_call_setup(&thread_reaper_call_data, thread_reaper, NULL);
1528: thread_reaper_call = &thread_reaper_call_data;
1529: }
1530:
1531: while ((thread = (thread_t) dequeue_head(&reaper_queue)) != THREAD_NULL) {
1532: simple_unlock(&reaper_lock);
1533:
1534: /*
1535: * wait for run bit to clear
1536: */
1537: thread_lock(thread);
1538: if (thread->state & TH_RUN)
1539: panic("thread reaper: TH_RUN");
1540: thread_unlock(thread);
1541: splx(s);
1542:
1543: thread_doreap(thread);
1544:
1545: s = splsched();
1546: simple_lock(&reaper_lock);
1547: }
1548:
1549: simple_unlock(&reaper_lock);
1550: splx(s);
1551: }
1552:
1553: #if MACH_HOST
1554: /*
1555: * thread_assign:
1556: *
1557: * Change processor set assignment.
1558: * Caller must hold an extra reference to the thread (if this is
1559: * called directly from the ipc interface, this is an operation
1560: * in progress reference). Caller must hold no locks -- this may block.
1561: */
1562:
1563: kern_return_t
1564: thread_assign(
1565: thread_act_t thr_act,
1566: processor_set_t new_pset)
1567: {
1568: thread_t thread;
1569:
1570: if (thr_act == THR_ACT_NULL || new_pset == PROCESSOR_SET_NULL)
1571: return(KERN_INVALID_ARGUMENT);
1572: thread = act_lock_thread(thr_act);
1573: if (thread == THREAD_NULL) {
1574: act_unlock_thread(thr_act);
1575: return(KERN_INVALID_ARGUMENT);
1576: }
1577:
1578: thread_freeze(thread);
1579: thread_doassign(thread, new_pset, TRUE);
1580: act_unlock_thread(thr_act);
1581: return(KERN_SUCCESS);
1582: }
1583:
1584: /*
1585: * thread_freeze:
1586: *
1587: * Freeze thread's assignment. Prelude to assigning thread.
1588: * Only one freeze may be held per thread.
1589: */
1590: void
1591: thread_freeze(
1592: thread_t thread)
1593: {
1594: spl_t s;
1595:
1596: /*
1597: * Freeze the assignment, deferring to a prior freeze.
1598: */
1599:
1600: s = splsched();
1601: thread_lock(thread);
1602: while (thread->may_assign == FALSE) {
1603: thread->assign_active = TRUE;
1604: thread_sleep_simple_lock((event_t) &thread->assign_active,
1605: simple_lock_addr(thread->lock), TRUE);
1606: thread_lock(thread);
1607: }
1608: thread->may_assign = FALSE;
1609: thread_unlock(thread);
1610: splx(s);
1611:
1612: }
1613:
1614: /*
1615: * thread_unfreeze: release freeze on thread's assignment.
1616: */
1617: void
1618: thread_unfreeze(
1619: thread_t thread)
1620: {
1621: spl_t s;
1622:
1623: s = splsched();
1624: thread_lock(thread);
1625: thread->may_assign = TRUE;
1626: if (thread->assign_active) {
1627: thread->assign_active = FALSE;
1628: thread_unlock(thread);
1629: splx(s);
1630: thread_wakeup((event_t)&thread->assign_active);
1631: return;
1632: }
1633: thread_unlock(thread);
1634: splx(s);
1635: }
1636:
1637: /*
1638: * thread_doassign:
1639: *
1640: * Actually do thread assignment. thread_will_assign must have been
1641: * called on the thread. release_freeze argument indicates whether
1642: * to release freeze on thread.
1643: *
1644: * Called with "appropriate" thread-related locks held on thread (see
1645: * act_lock_thread()). Returns with thread unlocked.
1646: */
1647:
1648: void
1649: thread_doassign(
1650: register thread_t thread,
1651: register processor_set_t new_pset,
1652: boolean_t release_freeze)
1653: {
1654: register boolean_t old_empty, new_empty;
1655: register processor_set_t pset;
1656: boolean_t recompute_pri = FALSE;
1657: int max_priority;
1658: spl_t s;
1659: thread_act_t thr_act = thread->top_act;
1660:
1661: /*
1662: * Check for silly no-op.
1663: */
1664: pset = thread->processor_set;
1665: if (pset == new_pset) {
1666: if (release_freeze)
1667: thread_unfreeze(thread);
1668: return;
1669: }
1670: /*
1671: * Suspend the thread and stop it if it's not the current thread.
1672: */
1673: thread_hold(thr_act);
1674: act_locked_act_reference(thr_act);
1675: act_unlock_thread(thr_act);
1676: if (thread != current_thread()) {
1677: if (thread_stop_wait(thread) == FALSE ){
1678: (void)act_lock_thread(thr_act);
1679: thread_release(thr_act);
1680: act_locked_act_deallocate(thr_act);
1681: act_unlock_thread(thr_act);
1682: if (release_freeze )
1683: thread_unfreeze(thread);
1684: return;
1685: }
1686: }
1687: /*
1688: * Had to release thread-related locks before acquiring pset
1689: * locks.
1690: */
1691:
1692: /*
1693: * Lock both psets now, use ordering to avoid deadlocks.
1694: */
1695: Restart:
1696: if (pset < new_pset) {
1697: pset_lock(pset);
1698: pset_lock(new_pset);
1699: } else {
1700: pset_lock(new_pset);
1701: pset_lock(pset);
1702: }
1703:
1704: /*
1705: * Check if new_pset is ok to assign to. If not, reassign
1706: * to default_pset.
1707: */
1708: if (!new_pset->active) {
1709: pset_unlock(pset);
1710: pset_unlock(new_pset);
1711: new_pset = &default_pset;
1712: goto Restart;
1713: }
1714:
1715: /*
1716: * Grab the thread lock and move the thread.
1717: * Then drop the lock on the old pset and the thread's
1718: * reference to it.
1719: */
1720:
1721: s = splsched();
1722: thread_lock(thread);
1723:
1724: thread_change_psets(thread, pset, new_pset);
1725:
1726: old_empty = pset->empty;
1727: new_empty = new_pset->empty;
1728:
1729: pset_unlock(pset);
1730: pset_deallocate(pset);
1731:
1732: /*
1733: * Reset policy and priorities if needed.
1734: *
1735: * There are three rules for threads under assignment:
1736: *
1737: * (1) If the new pset has the old policy enabled, keep the
1738: * old policy. Otherwise, use the default policy for the pset.
1739: * (2) The new limits will be the pset limits for the new policy.
1740: * (3) The new base will be the same as the old base unless either
1741: * (a) the new policy changed to the pset default policy;
1742: * in this case, the new base is the default policy
1743: * base,
1744: * or
1745: * (b) the new limits are different from the old limits;
1746: * in this case, the new base is the new limits.
1747: */
1748: /*** ??? fix me to fit into MK Scheduling Framework ***/
1749: max_priority = pset_max_priority(new_pset, thread->policy);
1750: if ((thread->policy & new_pset->policies) == 0) {
1751: thread->policy = new_pset->policy_default;
1752: thread->sched_data =
1753: pset_sched_data(new_pset, thread->policy);
1754: thread->unconsumed_quantum = thread->sched_data;
1755: thread->priority =
1756: pset_base_priority(new_pset, thread->policy);
1757: max_priority = pset_max_priority(new_pset, thread->policy);
1758: recompute_pri = TRUE;
1759: }
1760: else if (thread->max_priority != max_priority) {
1761: thread->priority = max_priority;
1762: recompute_pri = TRUE;
1763: }
1764:
1765: thread->max_priority = max_priority;
1766: if ((thread->depress_priority >= 0) &&
1767: (thread->depress_priority > thread->max_priority)) {
1768: thread->depress_priority = thread->max_priority;
1769: }
1770:
1771: pset_unlock(new_pset);
1772:
1773: if (recompute_pri)
1774: compute_priority(thread, TRUE);
1775:
1776: if (release_freeze) {
1777: boolean_t need_wakeup = FALSE;
1778: thread->may_assign = TRUE;
1779: if (thread->assign_active) {
1780: thread->assign_active = FALSE;
1781: need_wakeup = TRUE;
1782: }
1783: thread_unlock(thread);
1784: splx(s);
1785: if (need_wakeup)
1786: thread_wakeup((event_t)&thread->assign_active);
1787: } else {
1788: thread_unlock(thread);
1789: splx(s);
1790: }
1791: if (thread != current_thread())
1792: thread_unstop(thread);
1793: /*
1794: * Figure out hold status of thread. Threads assigned to empty
1795: * psets must be held. Therefore:
1796: * If old pset was empty release its hold.
1797: * Release our hold from above unless new pset is empty.
1798: */
1799:
1800: (void)act_lock_thread(thr_act);
1801: if (old_empty)
1802: thread_release(thr_act);
1803: if (!new_empty)
1804: thread_release(thr_act);
1805: act_locked_act_deallocate(thr_act);
1806: act_unlock_thread(thr_act);
1807:
1808: /*
1809: * If current_thread is assigned, context switch to force
1810: * assignment to happen. This also causes hold to take
1811: * effect if the new pset is empty.
1812: */
1813: if (thread == current_thread()) {
1814: s = splsched();
1815: mp_disable_preemption();
1816: ast_on(AST_BLOCK);
1817: mp_enable_preemption();
1818: splx(s);
1819: }
1820: }
1821:
1822: #else /* MACH_HOST */
1823:
1824: kern_return_t
1825: thread_assign(
1826: thread_act_t thr_act,
1827: processor_set_t new_pset)
1828: {
1829: #ifdef lint
1830: thread++; new_pset++;
1831: #endif /* lint */
1832: return(KERN_FAILURE);
1833: }
1834: #endif /* MACH_HOST */
1835:
1836: /*
1837: * thread_assign_default:
1838: *
1839: * Special version of thread_assign for assigning threads to default
1840: * processor set.
1841: */
1842: kern_return_t
1843: thread_assign_default(
1844: thread_act_t thr_act)
1845: {
1846: return (thread_assign(thr_act, &default_pset));
1847: }
1848:
1849: /*
1850: * thread_get_assignment
1851: *
1852: * Return current assignment for this thread.
1853: */
1854: kern_return_t
1855: thread_get_assignment(
1856: thread_act_t thr_act,
1857: processor_set_t *pset)
1858: {
1859: thread_t thread;
1860:
1861: if (thr_act == THR_ACT_NULL)
1862: return(KERN_INVALID_ARGUMENT);
1863: thread = act_lock_thread(thr_act);
1864: if (thread == THREAD_NULL) {
1865: act_unlock_thread(thr_act);
1866: return(KERN_INVALID_ARGUMENT);
1867: }
1868: *pset = thread->processor_set;
1869: act_unlock_thread(thr_act);
1870: pset_reference(*pset);
1871: return(KERN_SUCCESS);
1872: }
1873:
1874: /*
1875: * thread_wire:
1876: *
1877: * Specify that the target thread must always be able
1878: * to run and to allocate memory.
1879: */
1880: kern_return_t
1881: thread_wire(
1882: host_t host,
1883: thread_act_t thr_act,
1884: boolean_t wired)
1885: {
1886: spl_t s;
1887: thread_t thread;
1888: extern void vm_page_free_reserve(int pages);
1889:
1890: if (thr_act == THR_ACT_NULL || host == HOST_NULL)
1891: return (KERN_INVALID_ARGUMENT);
1892: thread = act_lock_thread(thr_act);
1893: if (thread ==THREAD_NULL) {
1894: act_unlock_thread(thr_act);
1895: return(KERN_INVALID_ARGUMENT);
1896: }
1897:
1898: /*
1899: * This implementation only works for the current thread.
1900: * See stack_privilege.
1901: */
1902: if (thr_act != current_act())
1903: return KERN_INVALID_ARGUMENT;
1904:
1905: s = splsched();
1906: thread_lock(thread);
1907:
1908: if (wired) {
1909: if (thread->vm_privilege == FALSE)
1910: vm_page_free_reserve(1); /* XXX */
1911: thread->vm_privilege = TRUE;
1912: } else {
1913: if (thread->vm_privilege == TRUE)
1914: vm_page_free_reserve(-1); /* XXX */
1915: thread->vm_privilege = FALSE;
1916: }
1917:
1918: thread_unlock(thread);
1919: splx(s);
1920: act_unlock_thread(thr_act);
1921:
1922: /*
1923: * Make the thread unswappable.
1924: */
1925: thread_swappable(thr_act, FALSE);
1926:
1927: return KERN_SUCCESS;
1928: }
1929:
1930: /*
1931: * thread_collect_scan:
1932: *
1933: * Attempt to free resources owned by threads.
1934: */
1935:
1936: void
1937: thread_collect_scan(void)
1938: {
1939: /* This code runs very quickly! */
1940: }
1941:
1942: boolean_t thread_collect_allowed = TRUE;
1943: unsigned thread_collect_last_tick = 0;
1944: unsigned thread_collect_max_rate = 0; /* in ticks */
1945:
1946: /*
1947: * consider_thread_collect:
1948: *
1949: * Called by the pageout daemon when the system needs more free pages.
1950: */
1951:
1952: void
1953: consider_thread_collect(void)
1954: {
1955: /*
1956: * By default, don't attempt thread collection more frequently
1957: * than once a second (one scheduler tick).
1958: */
1959:
1960: if (thread_collect_max_rate == 0)
1961: thread_collect_max_rate = 2; /* sched_tick is a 1 second resolution 2 here insures at least 1 second interval */
1962:
1963: if (thread_collect_allowed &&
1964: (sched_tick >
1965: (thread_collect_last_tick + thread_collect_max_rate))) {
1966: thread_collect_last_tick = sched_tick;
1967: thread_collect_scan();
1968: }
1969: }
1970:
1971: #if MACH_DEBUG
1972: #if STACK_USAGE
1973:
1974: vm_size_t
1975: stack_usage(
1976: register vm_offset_t stack)
1977: {
1978: int i;
1979:
1980: for (i = 0; i < KERNEL_STACK_SIZE/sizeof(unsigned int); i++)
1981: if (((unsigned int *)stack)[i] != STACK_MARKER)
1982: break;
1983:
1984: return KERNEL_STACK_SIZE - i * sizeof(unsigned int);
1985: }
1986:
1987: /*
1988: * Machine-dependent code should call stack_init
1989: * before doing its own initialization of the stack.
1990: */
1991:
1992: static void
1993: stack_init(
1994: register vm_offset_t stack,
1995: unsigned int bytes)
1996: {
1997: if (stack_check_usage) {
1998: int i;
1999:
2000: for (i = 0; i < bytes / sizeof(unsigned int); i++)
2001: ((unsigned int *)stack)[i] = STACK_MARKER;
2002: }
2003: }
2004:
2005: /*
2006: * Machine-dependent code should call stack_finalize
2007: * before releasing the stack memory.
2008: */
2009:
2010: void
2011: stack_finalize(
2012: register vm_offset_t stack)
2013: {
2014: if (stack_check_usage) {
2015: vm_size_t used = stack_usage(stack);
2016:
2017: simple_lock(&stack_usage_lock);
2018: if (used > stack_max_usage)
2019: stack_max_usage = used;
2020: simple_unlock(&stack_usage_lock);
2021: if (used > stack_max_use) {
2022: printf("stack usage = %x\n", used);
2023: panic("stack overflow");
2024: }
2025: }
2026: }
2027:
2028: #endif /*STACK_USAGE*/
2029: #endif /* MACH_DEBUG */
2030:
2031: kern_return_t
2032: host_stack_usage(
2033: host_t host,
2034: vm_size_t *reservedp,
2035: unsigned int *totalp,
2036: vm_size_t *spacep,
2037: vm_size_t *residentp,
2038: vm_size_t *maxusagep,
2039: vm_offset_t *maxstackp)
2040: {
2041: #if !MACH_DEBUG
2042: return KERN_NOT_SUPPORTED;
2043: #else
2044: unsigned int total;
2045: vm_size_t maxusage;
2046:
2047: if (host == HOST_NULL)
2048: return KERN_INVALID_HOST;
2049:
2050: simple_lock(&stack_usage_lock);
2051: maxusage = stack_max_usage;
2052: simple_unlock(&stack_usage_lock);
2053:
2054: stack_statistics(&total, &maxusage);
2055:
2056: *reservedp = 0;
2057: *totalp = total;
2058: *spacep = *residentp = total * round_page(KERNEL_STACK_SIZE);
2059: *maxusagep = maxusage;
2060: *maxstackp = 0;
2061: return KERN_SUCCESS;
2062:
2063: #endif /* MACH_DEBUG */
2064: }
2065:
2066: /*
2067: * Return info on stack usage for threads in a specific processor set
2068: */
2069: kern_return_t
2070: processor_set_stack_usage(
2071: processor_set_t pset,
2072: unsigned int *totalp,
2073: vm_size_t *spacep,
2074: vm_size_t *residentp,
2075: vm_size_t *maxusagep,
2076: vm_offset_t *maxstackp)
2077: {
2078: #if !MACH_DEBUG
2079: return KERN_NOT_SUPPORTED;
2080: #else
2081: unsigned int total;
2082: vm_size_t maxusage;
2083: vm_offset_t maxstack;
2084:
2085: register thread_t *threads;
2086: register thread_t thread;
2087:
2088: unsigned int actual; /* this many things */
2089: unsigned int i;
2090:
2091: vm_size_t size, size_needed;
2092: vm_offset_t addr;
2093:
2094: if (pset == PROCESSOR_SET_NULL)
2095: return KERN_INVALID_ARGUMENT;
2096:
2097: size = 0; addr = 0;
2098:
2099: for (;;) {
2100: pset_lock(pset);
2101: if (!pset->active) {
2102: pset_unlock(pset);
2103: return KERN_INVALID_ARGUMENT;
2104: }
2105:
2106: actual = pset->thread_count;
2107:
2108: /* do we have the memory we need? */
2109:
2110: size_needed = actual * sizeof(thread_t);
2111: if (size_needed <= size)
2112: break;
2113:
2114: /* unlock the pset and allocate more memory */
2115: pset_unlock(pset);
2116:
2117: if (size != 0)
2118: kfree(addr, size);
2119:
2120: assert(size_needed > 0);
2121: size = size_needed;
2122:
2123: addr = kalloc(size);
2124: if (addr == 0)
2125: return KERN_RESOURCE_SHORTAGE;
2126: }
2127:
2128: /* OK, have memory and the processor_set is locked & active */
2129:
2130: threads = (thread_t *) addr;
2131: for (i = 0, thread = (thread_t) queue_first(&pset->threads);
2132: i < actual;
2133: i++,
2134: thread = (thread_t) queue_next(&thread->pset_threads)) {
2135: thread_reference(thread);
2136: threads[i] = thread;
2137: }
2138: assert(queue_end(&pset->threads, (queue_entry_t) thread));
2139:
2140: /* can unlock processor set now that we have the thread refs */
2141: pset_unlock(pset);
2142:
2143: /* calculate maxusage and free thread references */
2144:
2145: total = 0;
2146: maxusage = 0;
2147: maxstack = 0;
2148: for (i = 0; i < actual; i++) {
2149: int cpu;
2150: thread_t thread = threads[i];
2151: vm_offset_t stack = 0;
2152:
2153: /*
2154: * thread->kernel_stack is only accurate if the
2155: * thread isn't swapped and is not executing.
2156: *
2157: * Of course, we don't have the appropriate locks
2158: * for these shenanigans.
2159: */
2160:
2161: stack = thread->kernel_stack;
2162:
2163: for (cpu = 0; cpu < NCPUS; cpu++)
2164: if (cpu_data[cpu].active_thread == thread) {
2165: stack = active_stacks[cpu];
2166: break;
2167: }
2168:
2169: if (stack != 0) {
2170: total++;
2171:
2172: if (stack_check_usage) {
2173: vm_size_t usage = stack_usage(stack);
2174:
2175: if (usage > maxusage) {
2176: maxusage = usage;
2177: maxstack = (vm_offset_t) thread;
2178: }
2179: }
2180: }
2181:
2182: thread_deallocate(thread);
2183: }
2184:
2185: if (size != 0)
2186: kfree(addr, size);
2187:
2188: *totalp = total;
2189: *residentp = *spacep = total * round_page(KERNEL_STACK_SIZE);
2190: *maxusagep = maxusage;
2191: *maxstackp = maxstack;
2192: return KERN_SUCCESS;
2193:
2194: #endif /* MACH_DEBUG */
2195: }
2196:
2197:
2198: /*
2199: * We consider a thread not preemptable if it is marked as either
2200: * suspended or waiting.
2201: */
2202:
2203: boolean_t thread_not_preemptable(
2204: thread_t thread)
2205: {
2206:
2207: /* XXX - when scheduling framework and such is done, the
2208: thread state check can be eliminated */
2209:
2210: if ((thread->state & (TH_WAIT|TH_SUSP)) || thread->preempt)
2211: return (TRUE);
2212: else
2213: return (FALSE);
2214: }
2215:
2216:
2217: /*
2218: * thread_set_sched
2219: *
2220: * Set scheduling policy and parameters for the given thread.
2221: * Policy must be a policy which is enabled for the
2222: * processor set.
2223: * (This should replace `thread_set_policy()' with the addition
2224: * of the MK Scheduling Framework to the kernel.)
2225: */
2226: kern_return_t
2227: thread_set_sched(
2228: thread_act_t thr_act,
2229: policy_t policy_id,
2230: sched_attr_t sched_attr,
2231: mach_msg_type_number_t sched_attrCnt)
2232: {
2233: thread_t thread;
2234: processor_set_t pset;
2235: kern_return_t result = KERN_SUCCESS;
2236: sched_policy_t *policy;
2237: sf_return_t sfr;
2238: boolean_t do_dispatch = FALSE;
2239: spl_t s;
2240:
2241: if (thr_act == THR_ACT_NULL)
2242: return (KERN_INVALID_ARGUMENT);
2243:
2244: thread = act_lock_thread(thr_act);
2245: if ( thread == THREAD_NULL ||
2246: (sched_attrCnt * sizeof(int)) !=
2247: sched_policy[policy_id].sched_attributes_size ) {
2248: act_unlock_thread(thr_act);
2249: return(KERN_INVALID_ARGUMENT);
2250: }
2251:
2252: if (invalid_policy(policy_id)) {
2253: act_unlock_thread(thr_act);
2254: return(KERN_INVALID_POLICY);
2255: }
2256:
2257: /* coordinate changes to thread scheduling state with others */
2258: s = splsched();
2259: thread_lock(thread);
2260:
2261: /* see if thread's policy is to be changed */
2262: if (thread->policy != policy_id) {
2263: /* it is; see if the target is executing */
2264: if (thread != current_thread()) { /*** fix for SMP ***/
2265: /* it is not; detach from old policy */
2266: policy = &sched_policy[thread->policy];
2267: sfr = policy->sp_ops.sp_thread_detach(policy, thread);
2268: if (sfr != SF_SUCCESS)
2269: panic("thread_set_sched: sp_thread_detach");
2270:
2271: /* attach to this policy */
2272: policy = &sched_policy[policy_id];
2273: sfr = policy->sp_ops.sp_thread_attach(policy, thread);
2274: if (sfr != SF_SUCCESS) {
2275: thread_unlock(thread);
2276: splx(s);
2277: act_unlock_thread(thr_act);
2278: return(KERN_FAILURE);
2279: }
2280:
2281: /* remember to dispatch thread after setting parms */
2282: do_dispatch = TRUE;
2283: }
2284: else {
2285: /* target is currently executing */
2286: /* defer policy change until thread leaves processor */
2287: thread->pending_policy = policy_id;
2288: bcopy((char *)sched_attr,
2289: (char *)thread->pending_sched_attr,
2290: (sched_attrCnt * sizeof(int)));
2291:
2292: /* try to get off processor to effect change */
2293: thread_unlock(thread);
2294: splx(s);
2295: act_unlock_thread(thr_act);
2296: thread_block((void (*)(void)) 0);
2297:
2298: /* by now, new attributes have been installed */
2299: act_lock_thread(thr_act);
2300: /*** check to see it's same thread? ***/
2301:
2302: s = splsched();
2303: thread_lock(thread);
2304: result = (thread->change_sfr == SF_SUCCESS)?
2305: KERN_SUCCESS : KERN_FAILURE;
2306: thread_unlock(thread);
2307: splx(s);
2308: act_unlock_thread(thr_act);
2309: return(result);
2310: }
2311:
2312: }
2313:
2314: /* call policy-specific routine to install new scheduling parameters */
2315: policy = &sched_policy[policy_id];
2316: sfr = policy->sp_ops.sp_thread_set(
2317: policy, thread, (sp_attributes_t)sched_attr);
2318:
2319: /* dispatch thread under new policy, if appropriate */
2320: if (do_dispatch == TRUE && sfr == SF_SUCCESS) {
2321: sfr = policy->sp_ops.sp_thread_dispatch(policy, thread);
2322: }
2323:
2324: thread_unlock(thread);
2325: splx(s);
2326:
2327: if (sfr != SF_SUCCESS)
2328: result = KERN_FAILURE;
2329:
2330: act_unlock_thread(thr_act);
2331: return(result);
2332: }
2333:
2334:
2335: /*
2336: * thread_get_sched
2337: *
2338: * Get scheduling policy and parameters for the given thread.
2339: * (This was added as part of the MK Scheduling Framework.)
2340: */
2341: kern_return_t
2342: thread_get_sched(
2343: thread_act_t thr_act,
2344: policy_t *policy_id_out,
2345: sched_attr_t sched_attr,
2346: mach_msg_type_number_t *sched_attrCnt)
2347: {
2348: thread_t thread;
2349: kern_return_t result = KERN_SUCCESS;
2350: policy_t policy_id;
2351: sched_policy_t *policy;
2352: sf_return_t sfr;
2353: int size;
2354: spl_t s;
2355:
2356: if (thr_act == THR_ACT_NULL)
2357: return (KERN_INVALID_ARGUMENT);
2358:
2359: thread = act_lock_thread(thr_act);
2360: if (thread == THREAD_NULL) {
2361: act_unlock_thread(thr_act);
2362: *policy_id_out = POLICY_NULL;
2363: return(KERN_INVALID_ARGUMENT);
2364: }
2365:
2366: size = *sched_attrCnt * sizeof(int);
2367:
2368: /* coordinate changes to thread scheduling state with others */
2369: s = splsched();
2370: thread_lock(thread);
2371:
2372: policy_id = thread->policy;
2373: if (size < sched_policy[policy_id].sched_attributes_size) {
2374: thread_unlock(thread);
2375: splx(s);
2376: act_unlock_thread(thr_act);
2377: *policy_id_out = policy_id;
2378: return(KERN_INVALID_ARGUMENT);
2379: }
2380:
2381: /* note policy for caller */
2382: *policy_id_out = policy_id;
2383:
2384: /* call policy-specific routine */
2385: policy = &sched_policy[policy_id];
2386: sfr = policy->sp_ops.sp_thread_get(
2387: policy, thread, (sp_attributes_t)sched_attr, size);
2388:
2389: if (sfr != SF_SUCCESS)
2390: result = KERN_FAILURE;
2391:
2392: *sched_attrCnt = policy->sched_attributes_size / sizeof(int);
2393:
2394: thread_unlock(thread);
2395: splx(s);
2396: act_unlock_thread(thr_act);
2397: return(result);
2398: }
2399:
2400: boolean_t
2401: thread_get_funneled(
2402: void)
2403: {
2404: return((current_thread()->funnel_state & TH_FN_OWNED) == TH_FN_OWNED);
2405: }
2406:
2407: boolean_t
2408: thread_set_funneled(
2409: boolean_t funneled)
2410: {
2411: thread_t cur_thread;
2412: boolean_t funnel_state_prev;
2413:
2414: cur_thread = current_thread();
2415: funnel_state_prev = ((cur_thread->funnel_state & TH_FN_OWNED) == TH_FN_OWNED);
2416:
2417: if (funnel_state_prev != funneled) {
2418: if (funneled == TRUE) {
2419: mutex_lock(&funnel_lock);
2420: cur_thread->funnel_state |= TH_FN_OWNED;
2421: } else {
2422: cur_thread->funnel_state &= ~TH_FN_OWNED;
2423: mutex_unlock(&funnel_lock);
2424: }
2425: }
2426: return(funnel_state_prev);
2427: }
2428:
2429: void
2430: thread_set_cont_arg(int arg)
2431: {
2432: thread_t th = current_thread();
2433: th->cont_arg = arg;
2434: }
2435:
2436: int
2437: thread_get_cont_arg(void)
2438: {
2439: thread_t th = current_thread();
2440: return(th->cont_arg);
2441: }
2442:
2443: /*
2444: * Export routines to other components for things that are done as macros
2445: * within the osfmk component.
2446: */
2447: #undef thread_should_halt
2448: boolean_t
2449: thread_should_halt(
2450: thread_shuttle_t th)
2451: {
2452: return(thread_should_halt_fast(th));
2453: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.