}
td->td_intr_nesting_level--;
}
中断线程调度函数ithread_schedule()处理有关中断线程调度的工作 。
代码:
int
ithread_schedule(struct ithd *ithread, int do_switch)
{
struct int_entropy entropy;
struct thread *td;
struct thread *ctd;
struct proc *p;
/*
* If no ithread or no handlers, then we have a stray interrupt.
*/
if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers))
return (EINVAL);
ctd = curthread;
/*
* If any of the handlers for this ithread claim to be good
* sources of entropy, then gather some.
*/
if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) {
entropy.vector = ithread->it_vector;
entropy.proc = ctd->td_proc;
random_harvest(&entropy, sizeof(entropy), 2, 0,
RANDOM_INTERRUPT);
}
如果该中断线程有IT_ENTROPY标志,说明可以当作随机数的来源 。
代码:
td = ithread->it_td;
p = td->td_proc;
KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name));
CTR4(KTR_INTR, "%s: pid %d: (%s) need = %d",
__func__, p->p_pid, p->p_comm, ithread->it_need);
/*
* Set it_need to tell the thread to keep running if it is already
* running. Then, grab sched_lock and see if we actually need to
* put this thread on the runqueue. If so and the do_switch flag is
* true and it is safe to switch, then switch to the ithread
* immediately. Otherwise, set the needresched flag to guarantee
* that this ithread will run before any userland processes.
*/
ithread->it_need = 1;
设置it_need,可以保证中断线程不会在还有中断的情况下,错过中断而去睡眠,见ithread_loop() 。
代码:
mtx_lock_spin(&sched_lock);
if (TD_AWAITING_INTR(td)) {
CTR2(KTR_INTR, "%s: setrunqueue %d", __func__, p->p_pid);
TD_CLR_IWAIT(td);
setrunqueue(td);
if (do_switch &&
(ctd->td_critnest == 1) ) {
KASSERT((TD_IS_RUNNING(ctd)),
("ithread_schedule: Bad state for curthread."));
ctd->td_proc->p_stats->p_ru.ru_nivcsw;
if (ctd->td_flags & TDF_IDLETD)
ctd->td_state = TDS_CAN_RUN; /* XXXKSE */
mi_switch();
} else {
curthread->td_flags |= TDF_NEEDRESCHED;
}
如果中断线程正在睡眠,也就是说中断线程正在等待中断的到来,则将它放入runqueue,马上运行 。
如果参数指示可以调度,并且当前线程的嵌套调度深度为1,即第一次试图调度中断线程,则进行
上下文切换,否则,将不立即调度运行中断线程,而要等到正常调度时再运行 。
这里需要指出的是,如果决定mi_switch(),由于中断线程优先级很高,中断线程将会立即执行,
中断处理函数完成后也许将回到这里,也可能有变数,不会马上回到这里(FIXME),因此前面
intr_execute_handlers()中先应答中断控制器,将中断处理必须做的先做完 。
调度回来后,继续运行,完成整个中断的处理 。
代码:
} else {
CTR4(KTR_INTR, "%s: pid %d: it_need %d, state %d",
__func__, p->p_pid, ithread->it_need, td->td_state);
}
否则,由于已经设置了it_need=1,已经在运行的中断线程将负责处理之 。
代码:
mtx_unlock_spin(&sched_lock);
return (0);
}
我们再来看看中断线程本身,该函数较为简单,两个嵌套的循环保证不会遗漏中断,
如果中断服务完成,则睡眠,调用mi_switch()
代码:
/*
* This is the main code for interrupt threads.
*/
static void
ithread_loop(void *arg)
{
struct ithd *ithd; /* our thread context */
struct intrhand *ih; /* and our interrupt handler chain */
struct thread *td;
struct proc *p;
td = curthread;
p = td->td_proc;
ithd = (struct ithd *)arg; /* point to myself */
KASSERT(ithd->it_td == td && td->td_ithd == ithd,
("%s: ithread and proc linkage out of sync", __func__));
/*
* As long as we have interrupts outstanding, go through the
推荐阅读
- 1、系统安装 FreeBSD网站平台建设全过程
- 用FREEBSD作开发的一些实现方式
- FreeBSD下的内存文件系统
- FreeBSD中/etc下的文件简介
- FreeBSD下Apache2.0运行模型分析及性能调整
- 试用QEMU,安装个FreeBSD 5.3
- FreeBSD下有关分区和mount的一些问题
- RSYNC ON FreeBSD 5.2 HOWTO V1.0
- 系统核心 自订 FreeBSD Kernel
- 一些FreeBSD相关的安全问题