kern_switch.c revision 165761
1/*-
2 * Copyright (c) 2001 Jake Burkholder <jake@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/kern/kern_switch.c 165761 2007-01-04 08:39:58Z jeff $");
30
31#include "opt_sched.h"
32
33#ifndef KERN_SWITCH_INCLUDE
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kdb.h>
37#include <sys/kernel.h>
38#include <sys/ktr.h>
39#include <sys/lock.h>
40#include <sys/mutex.h>
41#include <sys/proc.h>
42#include <sys/queue.h>
43#include <sys/sched.h>
44#else  /* KERN_SWITCH_INCLUDE */
45#if defined(SMP) && (defined(__i386__) || defined(__amd64__))
46#include <sys/smp.h>
47#endif
48#if defined(SMP) && defined(SCHED_4BSD)
49#include <sys/sysctl.h>
50#endif
51
52/* Uncomment this to enable logging of critical_enter/exit. */
53#if 0
54#define	KTR_CRITICAL	KTR_SCHED
55#else
56#define	KTR_CRITICAL	0
57#endif
58
59#ifdef FULL_PREEMPTION
60#ifndef PREEMPTION
61#error "The FULL_PREEMPTION option requires the PREEMPTION option"
62#endif
63#endif
64
65CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS);
66
67/*
68 * kern.sched.preemption allows user space to determine if preemption support
69 * is compiled in or not.  It is not currently a boot or runtime flag that
70 * can be changed.
71 */
72#ifdef PREEMPTION
73static int kern_sched_preemption = 1;
74#else
75static int kern_sched_preemption = 0;
76#endif
77SYSCTL_INT(_kern_sched, OID_AUTO, preemption, CTLFLAG_RD,
78    &kern_sched_preemption, 0, "Kernel preemption enabled");
79
80/************************************************************************
81 * Functions that manipulate runnability from a thread perspective.	*
82 ************************************************************************/
83/*
84 * Select the thread that will be run next.
85 */
86struct thread *
87choosethread(void)
88{
89	struct td_sched *ts;
90	struct thread *td;
91
92#if defined(SMP) && (defined(__i386__) || defined(__amd64__))
93	if (smp_active == 0 && PCPU_GET(cpuid) != 0) {
94		/* Shutting down, run idlethread on AP's */
95		td = PCPU_GET(idlethread);
96		ts = td->td_sched;
97		CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td);
98		ts->ts_flags |= TSF_DIDRUN;
99		TD_SET_RUNNING(td);
100		return (td);
101	}
102#endif
103
104retry:
105	ts = sched_choose();
106	if (ts) {
107		td = ts->ts_thread;
108		CTR2(KTR_RUNQ, "choosethread: td=%p pri=%d",
109		    td, td->td_priority);
110	} else {
111		/* Simulate runq_choose() having returned the idle thread */
112		td = PCPU_GET(idlethread);
113		ts = td->td_sched;
114		CTR1(KTR_RUNQ, "choosethread: td=%p (idle)", td);
115	}
116	ts->ts_flags |= TSF_DIDRUN;
117
118	/*
119	 * If we are in panic, only allow system threads,
120	 * plus the one we are running in, to be run.
121	 */
122	if (panicstr && ((td->td_proc->p_flag & P_SYSTEM) == 0 &&
123	    (td->td_flags & TDF_INPANIC) == 0)) {
124		/* note that it is no longer on the run queue */
125		TD_SET_CAN_RUN(td);
126		goto retry;
127	}
128
129	TD_SET_RUNNING(td);
130	return (td);
131}
132
133
134#if 0
135/*
136 * currently not used.. threads remove themselves from the
137 * run queue by running.
138 */
139static void
140remrunqueue(struct thread *td)
141{
142	mtx_assert(&sched_lock, MA_OWNED);
143	KASSERT((TD_ON_RUNQ(td)), ("remrunqueue: Bad state on run queue"));
144	CTR1(KTR_RUNQ, "remrunqueue: td%p", td);
145	TD_SET_CAN_RUN(td);
146	/* remove from sys run queue */
147	sched_rem(td);
148	return;
149}
150#endif
151
152/*
153 * Change the priority of a thread that is on the run queue.
154 */
155void
156adjustrunqueue( struct thread *td, int newpri)
157{
158	struct td_sched *ts;
159
160	mtx_assert(&sched_lock, MA_OWNED);
161	KASSERT((TD_ON_RUNQ(td)), ("adjustrunqueue: Bad state on run queue"));
162
163	ts = td->td_sched;
164	CTR1(KTR_RUNQ, "adjustrunqueue: td%p", td);
165		/* We only care about the td_sched in the run queue. */
166	td->td_priority = newpri;
167#ifndef SCHED_CORE
168	if (ts->ts_rqindex != (newpri / RQ_PPQ))
169#else
170	if (ts->ts_rqindex != newpri)
171#endif
172	{
173		sched_rem(td);
174		sched_add(td, SRQ_BORING);
175	}
176}
177
178void
179setrunqueue(struct thread *td, int flags)
180{
181
182	CTR2(KTR_RUNQ, "setrunqueue: td:%p pid:%d",
183	    td, td->td_proc->p_pid);
184	CTR5(KTR_SCHED, "setrunqueue: %p(%s) prio %d by %p(%s)",
185            td, td->td_proc->p_comm, td->td_priority, curthread,
186            curthread->td_proc->p_comm);
187	mtx_assert(&sched_lock, MA_OWNED);
188	KASSERT((td->td_inhibitors == 0),
189			("setrunqueue: trying to run inhibited thread"));
190	KASSERT((TD_CAN_RUN(td) || TD_IS_RUNNING(td)),
191	    ("setrunqueue: bad thread state"));
192	TD_SET_RUNQ(td);
193	sched_add(td, flags);
194}
195
196/*
197 * Kernel thread preemption implementation.  Critical sections mark
198 * regions of code in which preemptions are not allowed.
199 */
200void
201critical_enter(void)
202{
203	struct thread *td;
204
205	td = curthread;
206	td->td_critnest++;
207	CTR4(KTR_CRITICAL, "critical_enter by thread %p (%ld, %s) to %d", td,
208	    (long)td->td_proc->p_pid, td->td_proc->p_comm, td->td_critnest);
209}
210
211void
212critical_exit(void)
213{
214	struct thread *td;
215
216	td = curthread;
217	KASSERT(td->td_critnest != 0,
218	    ("critical_exit: td_critnest == 0"));
219#ifdef PREEMPTION
220	if (td->td_critnest == 1) {
221		td->td_critnest = 0;
222		mtx_assert(&sched_lock, MA_NOTOWNED);
223		if (td->td_owepreempt) {
224			td->td_critnest = 1;
225			mtx_lock_spin(&sched_lock);
226			td->td_critnest--;
227			mi_switch(SW_INVOL, NULL);
228			mtx_unlock_spin(&sched_lock);
229		}
230	} else
231#endif
232		td->td_critnest--;
233
234	CTR4(KTR_CRITICAL, "critical_exit by thread %p (%ld, %s) to %d", td,
235	    (long)td->td_proc->p_pid, td->td_proc->p_comm, td->td_critnest);
236}
237
238/*
239 * This function is called when a thread is about to be put on run queue
240 * because it has been made runnable or its priority has been adjusted.  It
241 * determines if the new thread should be immediately preempted to.  If so,
242 * it switches to it and eventually returns true.  If not, it returns false
243 * so that the caller may place the thread on an appropriate run queue.
244 */
245int
246maybe_preempt(struct thread *td)
247{
248#ifdef PREEMPTION
249	struct thread *ctd;
250	int cpri, pri;
251#endif
252
253	mtx_assert(&sched_lock, MA_OWNED);
254#ifdef PREEMPTION
255	/*
256	 * The new thread should not preempt the current thread if any of the
257	 * following conditions are true:
258	 *
259	 *  - The kernel is in the throes of crashing (panicstr).
260	 *  - The current thread has a higher (numerically lower) or
261	 *    equivalent priority.  Note that this prevents curthread from
262	 *    trying to preempt to itself.
263	 *  - It is too early in the boot for context switches (cold is set).
264	 *  - The current thread has an inhibitor set or is in the process of
265	 *    exiting.  In this case, the current thread is about to switch
266	 *    out anyways, so there's no point in preempting.  If we did,
267	 *    the current thread would not be properly resumed as well, so
268	 *    just avoid that whole landmine.
269	 *  - If the new thread's priority is not a realtime priority and
270	 *    the current thread's priority is not an idle priority and
271	 *    FULL_PREEMPTION is disabled.
272	 *
273	 * If all of these conditions are false, but the current thread is in
274	 * a nested critical section, then we have to defer the preemption
275	 * until we exit the critical section.  Otherwise, switch immediately
276	 * to the new thread.
277	 */
278	ctd = curthread;
279	KASSERT ((ctd->td_sched != NULL && ctd->td_sched->ts_thread == ctd),
280	  ("thread has no (or wrong) sched-private part."));
281	KASSERT((td->td_inhibitors == 0),
282			("maybe_preempt: trying to run inhibited thread"));
283	pri = td->td_priority;
284	cpri = ctd->td_priority;
285	if (panicstr != NULL || pri >= cpri || cold /* || dumping */ ||
286	    TD_IS_INHIBITED(ctd) || td->td_sched->ts_state != TSS_THREAD)
287		return (0);
288#ifndef FULL_PREEMPTION
289	if (pri > PRI_MAX_ITHD && cpri < PRI_MIN_IDLE)
290		return (0);
291#endif
292
293	if (ctd->td_critnest > 1) {
294		CTR1(KTR_PROC, "maybe_preempt: in critical section %d",
295		    ctd->td_critnest);
296		ctd->td_owepreempt = 1;
297		return (0);
298	}
299
300	/*
301	 * Thread is runnable but not yet put on system run queue.
302	 */
303	MPASS(TD_ON_RUNQ(td));
304	MPASS(td->td_sched->ts_state != TSS_ONRUNQ);
305	TD_SET_RUNNING(td);
306	CTR3(KTR_PROC, "preempting to thread %p (pid %d, %s)\n", td,
307	    td->td_proc->p_pid, td->td_proc->p_comm);
308	mi_switch(SW_INVOL|SW_PREEMPT, td);
309	return (1);
310#else
311	return (0);
312#endif
313}
314
315#if 0
316#ifndef PREEMPTION
317/* XXX: There should be a non-static version of this. */
318static void
319printf_caddr_t(void *data)
320{
321	printf("%s", (char *)data);
322}
323static char preempt_warning[] =
324    "WARNING: Kernel preemption is disabled, expect reduced performance.\n";
325SYSINIT(preempt_warning, SI_SUB_COPYRIGHT, SI_ORDER_ANY, printf_caddr_t,
326    preempt_warning)
327#endif
328#endif
329
330/************************************************************************
331 * SYSTEM RUN QUEUE manipulations and tests				*
332 ************************************************************************/
333/*
334 * Initialize a run structure.
335 */
336void
337runq_init(struct runq *rq)
338{
339	int i;
340
341	bzero(rq, sizeof *rq);
342	for (i = 0; i < RQ_NQS; i++)
343		TAILQ_INIT(&rq->rq_queues[i]);
344}
345
346/*
347 * Clear the status bit of the queue corresponding to priority level pri,
348 * indicating that it is empty.
349 */
350static __inline void
351runq_clrbit(struct runq *rq, int pri)
352{
353	struct rqbits *rqb;
354
355	rqb = &rq->rq_status;
356	CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d",
357	    rqb->rqb_bits[RQB_WORD(pri)],
358	    rqb->rqb_bits[RQB_WORD(pri)] & ~RQB_BIT(pri),
359	    RQB_BIT(pri), RQB_WORD(pri));
360	rqb->rqb_bits[RQB_WORD(pri)] &= ~RQB_BIT(pri);
361}
362
363/*
364 * Find the index of the first non-empty run queue.  This is done by
365 * scanning the status bits, a set bit indicates a non-empty queue.
366 */
367static __inline int
368runq_findbit(struct runq *rq)
369{
370	struct rqbits *rqb;
371	int pri;
372	int i;
373
374	rqb = &rq->rq_status;
375	for (i = 0; i < RQB_LEN; i++)
376		if (rqb->rqb_bits[i]) {
377			pri = RQB_FFS(rqb->rqb_bits[i]) + (i << RQB_L2BPW);
378			CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d pri=%d",
379			    rqb->rqb_bits[i], i, pri);
380			return (pri);
381		}
382
383	return (-1);
384}
385
386static __inline int
387runq_findbit_from(struct runq *rq, int start)
388{
389	struct rqbits *rqb;
390	int bit;
391	int pri;
392	int i;
393
394	rqb = &rq->rq_status;
395	bit = start & (RQB_BPW -1);
396	pri = 0;
397	CTR1(KTR_RUNQ, "runq_findbit_from: start %d", start);
398again:
399	for (i = RQB_WORD(start); i < RQB_LEN; i++) {
400		CTR3(KTR_RUNQ, "runq_findbit_from: bits %d = %#x bit = %d",
401		    i, rqb->rqb_bits[i], bit);
402		if (rqb->rqb_bits[i]) {
403			if (bit != 0) {
404				for (pri = bit; pri < RQB_BPW; pri++)
405					if (rqb->rqb_bits[i] & (1ul << pri))
406						break;
407				bit = 0;
408				if (pri >= RQB_BPW)
409					continue;
410			} else
411				pri = RQB_FFS(rqb->rqb_bits[i]);
412			pri += (i << RQB_L2BPW);
413			CTR3(KTR_RUNQ, "runq_findbit_from: bits=%#x i=%d pri=%d",
414			    rqb->rqb_bits[i], i, pri);
415			return (pri);
416		}
417		bit = 0;
418	}
419	if (start != 0) {
420		CTR0(KTR_RUNQ, "runq_findbit_from: restarting");
421		start = 0;
422		goto again;
423	}
424
425	return (-1);
426}
427
428/*
429 * Set the status bit of the queue corresponding to priority level pri,
430 * indicating that it is non-empty.
431 */
432static __inline void
433runq_setbit(struct runq *rq, int pri)
434{
435	struct rqbits *rqb;
436
437	rqb = &rq->rq_status;
438	CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d",
439	    rqb->rqb_bits[RQB_WORD(pri)],
440	    rqb->rqb_bits[RQB_WORD(pri)] | RQB_BIT(pri),
441	    RQB_BIT(pri), RQB_WORD(pri));
442	rqb->rqb_bits[RQB_WORD(pri)] |= RQB_BIT(pri);
443}
444
445/*
446 * Add the thread to the queue specified by its priority, and set the
447 * corresponding status bit.
448 */
449void
450runq_add(struct runq *rq, struct td_sched *ts, int flags)
451{
452	struct rqhead *rqh;
453	int pri;
454
455	pri = ts->ts_thread->td_priority / RQ_PPQ;
456	ts->ts_rqindex = pri;
457	runq_setbit(rq, pri);
458	rqh = &rq->rq_queues[pri];
459	CTR5(KTR_RUNQ, "runq_add: td=%p ts=%p pri=%d %d rqh=%p",
460	    ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh);
461	if (flags & SRQ_PREEMPTED) {
462		TAILQ_INSERT_HEAD(rqh, ts, ts_procq);
463	} else {
464		TAILQ_INSERT_TAIL(rqh, ts, ts_procq);
465	}
466}
467
468void
469runq_add_pri(struct runq *rq, struct td_sched *ts, int pri, int flags)
470{
471	struct rqhead *rqh;
472
473	KASSERT(pri < RQ_NQS, ("runq_add_pri: %d out of range", pri));
474	ts->ts_rqindex = pri;
475	runq_setbit(rq, pri);
476	rqh = &rq->rq_queues[pri];
477	CTR5(KTR_RUNQ, "runq_add_pri: td=%p ke=%p pri=%d idx=%d rqh=%p",
478	    ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh);
479	if (flags & SRQ_PREEMPTED) {
480		TAILQ_INSERT_HEAD(rqh, ts, ts_procq);
481	} else {
482		TAILQ_INSERT_TAIL(rqh, ts, ts_procq);
483	}
484}
485/*
486 * Return true if there are runnable processes of any priority on the run
487 * queue, false otherwise.  Has no side effects, does not modify the run
488 * queue structure.
489 */
490int
491runq_check(struct runq *rq)
492{
493	struct rqbits *rqb;
494	int i;
495
496	rqb = &rq->rq_status;
497	for (i = 0; i < RQB_LEN; i++)
498		if (rqb->rqb_bits[i]) {
499			CTR2(KTR_RUNQ, "runq_check: bits=%#x i=%d",
500			    rqb->rqb_bits[i], i);
501			return (1);
502		}
503	CTR0(KTR_RUNQ, "runq_check: empty");
504
505	return (0);
506}
507
508#if defined(SMP) && defined(SCHED_4BSD)
509int runq_fuzz = 1;
510SYSCTL_INT(_kern_sched, OID_AUTO, runq_fuzz, CTLFLAG_RW, &runq_fuzz, 0, "");
511#endif
512
513/*
514 * Find the highest priority process on the run queue.
515 */
516struct td_sched *
517runq_choose(struct runq *rq)
518{
519	struct rqhead *rqh;
520	struct td_sched *ts;
521	int pri;
522
523	mtx_assert(&sched_lock, MA_OWNED);
524	while ((pri = runq_findbit(rq)) != -1) {
525		rqh = &rq->rq_queues[pri];
526#if defined(SMP) && defined(SCHED_4BSD)
527		/* fuzz == 1 is normal.. 0 or less are ignored */
528		if (runq_fuzz > 1) {
529			/*
530			 * In the first couple of entries, check if
531			 * there is one for our CPU as a preference.
532			 */
533			int count = runq_fuzz;
534			int cpu = PCPU_GET(cpuid);
535			struct td_sched *ts2;
536			ts2 = ts = TAILQ_FIRST(rqh);
537
538			while (count-- && ts2) {
539				if (ts->ts_thread->td_lastcpu == cpu) {
540					ts = ts2;
541					break;
542				}
543				ts2 = TAILQ_NEXT(ts2, ts_procq);
544			}
545		} else
546#endif
547			ts = TAILQ_FIRST(rqh);
548		KASSERT(ts != NULL, ("runq_choose: no proc on busy queue"));
549		CTR3(KTR_RUNQ,
550		    "runq_choose: pri=%d td_sched=%p rqh=%p", pri, ts, rqh);
551		return (ts);
552	}
553	CTR1(KTR_RUNQ, "runq_choose: idleproc pri=%d", pri);
554
555	return (NULL);
556}
557
558struct td_sched *
559runq_choose_from(struct runq *rq, int *idx)
560{
561	struct rqhead *rqh;
562	struct td_sched *ts;
563	int pri;
564
565	mtx_assert(&sched_lock, MA_OWNED);
566	if ((pri = runq_findbit_from(rq, *idx)) != -1) {
567		rqh = &rq->rq_queues[pri];
568		ts = TAILQ_FIRST(rqh);
569		KASSERT(ts != NULL, ("runq_choose: no proc on busy queue"));
570		CTR4(KTR_RUNQ,
571		    "runq_choose_from: pri=%d kse=%p idx=%d rqh=%p",
572		    pri, ts, ts->ts_rqindex, rqh);
573		*idx = ts->ts_rqindex;
574		return (ts);
575	}
576	CTR1(KTR_RUNQ, "runq_choose_from: idleproc pri=%d", pri);
577
578	return (NULL);
579}
580/*
581 * Remove the thread from the queue specified by its priority, and clear the
582 * corresponding status bit if the queue becomes empty.
583 * Caller must set ts->ts_state afterwards.
584 */
585void
586runq_remove(struct runq *rq, struct td_sched *ts)
587{
588
589	runq_remove_idx(rq, ts, NULL);
590}
591
592void
593runq_remove_idx(struct runq *rq, struct td_sched *ts, int *idx)
594{
595	struct rqhead *rqh;
596	int pri;
597
598	KASSERT(ts->ts_thread->td_proc->p_sflag & PS_INMEM,
599		("runq_remove_idx: process swapped out"));
600	pri = ts->ts_rqindex;
601	rqh = &rq->rq_queues[pri];
602	CTR5(KTR_RUNQ, "runq_remove_idx: td=%p, ts=%p pri=%d %d rqh=%p",
603	    ts->ts_thread, ts, ts->ts_thread->td_priority, pri, rqh);
604	TAILQ_REMOVE(rqh, ts, ts_procq);
605	if (TAILQ_EMPTY(rqh)) {
606		CTR0(KTR_RUNQ, "runq_remove_idx: empty");
607		runq_clrbit(rq, pri);
608		if (idx != NULL && *idx == pri)
609			*idx = (pri + 1) % RQ_NQS;
610	}
611}
612
613/****** functions that are temporarily here ***********/
614#include <vm/uma.h>
615extern struct mtx kse_zombie_lock;
616
617/*
618 *  Allocate scheduler specific per-process resources.
619 * The thread and proc have already been linked in.
620 *
621 * Called from:
622 *  proc_init() (UMA init method)
623 */
624void
625sched_newproc(struct proc *p, struct thread *td)
626{
627}
628
629/*
630 * thread is being either created or recycled.
631 * Fix up the per-scheduler resources associated with it.
632 * Called from:
633 *  sched_fork_thread()
634 *  thread_dtor()  (*may go away)
635 *  thread_init()  (*may go away)
636 */
637void
638sched_newthread(struct thread *td)
639{
640	struct td_sched *ts;
641
642	ts = (struct td_sched *) (td + 1);
643	bzero(ts, sizeof(*ts));
644	td->td_sched     = ts;
645	ts->ts_thread	= td;
646	ts->ts_state	= TSS_THREAD;
647}
648
649/*
650 * Called from:
651 *  thr_create()
652 *  proc_init() (UMA) via sched_newproc()
653 */
654void
655sched_init_concurrency(struct proc *p)
656{
657}
658
659/*
660 * Change the concurrency of an existing proc to N
661 * Called from:
662 *  kse_create()
663 *  kse_exit()
664 *  thread_exit()
665 *  thread_single()
666 */
667void
668sched_set_concurrency(struct proc *p, int concurrency)
669{
670}
671
672/*
673 * Called from thread_exit() for all exiting thread
674 *
675 * Not to be confused with sched_exit_thread()
676 * that is only called from thread_exit() for threads exiting
677 * without the rest of the process exiting because it is also called from
678 * sched_exit() and we wouldn't want to call it twice.
679 * XXX This can probably be fixed.
680 */
681void
682sched_thread_exit(struct thread *td)
683{
684}
685
686#endif /* KERN_SWITCH_INCLUDE */
687