FreeBSD 5 内核源代码分析之中断处理( 七 )


* list of handlers, giving each one a go at it.
*/
for (;;) {
/*
* If we are an orphaned thread, then just die.
*/
if (ithd->it_flags & IT_DEAD) {
CTR3(KTR_INTR, "%s: pid %d: (%s) exiting", __func__,
p->p_pid, p->p_comm);
td->td_ithd = NULL;
mtx_destroy(&ithd->it_lock);
mtx_lock(&Giant);
free(ithd, M_ITHREAD);
kthread_exit(0);
}

如果已经删除当前IRQ的中断处理程序,则需要退出中断线程 。
代码:
CTR4(KTR_INTR, "%s: pid %d: (%s) need=%d", __func__,
p->p_pid, p->p_comm, ithd->it_need);
while (ithd->it_need) {
/*
* Service interrupts. If another interrupt
* arrives while we are running, they will set
* it_need to denote that we should make
* another pass.
*/
atomic_store_rel_int(&ithd->it_need, 0);

清除it_need标志,当清除后又有中断发生时,it_need将变成1,从而循环继续 。
代码:
restart:
TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
if (ithd->it_flags & IT_SOFT && !ih->ih_need)
continue;
atomic_store_rel_int(&ih->ih_need, 0);
CTR6(KTR_INTR,
"%s: pid %d ih=%p: %p(%p) flg=%x", __func__,
p->p_pid, (void *)ih,
(void *)ih->ih_handler, ih->ih_argument,
ih->ih_flags);

if ((ih->ih_flags & IH_DEAD) != 0) {
mtx_lock(&ithd->it_lock);
TAILQ_REMOVE(&ithd->it_handlers, ih,
ih_next);
wakeup(ih);
mtx_unlock(&ithd->it_lock);
goto restart;
}
if ((ih->ih_flags & IH_MPSAFE) == 0)
mtx_lock(&Giant);
ih->ih_handler(ih->ih_argument);

调用设备驱动的中断服务函数 。所有注册到该IRQ的函数都将被调用,各个设备的函数将检查
自己设备的状态以确定是否是自己的设备产生的中断 。
代码:
if ((ih->ih_flags & IH_MPSAFE) == 0)
mtx_unlock(&Giant);
}
}

/*
* Processed all our interrupts. Now get the sched
* lock. This may take a while and it_need may get
* set again, so we have to check it again.
*/
WITNESS_WARN(WARN_PANIC, NULL, "suspending ithread");
mtx_assert(&Giant, MA_NOTOWNED);
mtx_lock_spin(&sched_lock);
if (!ithd->it_need) {
/*
* Should we call this earlier in the loop above?
*/
if (ithd->it_enable != NULL)
ithd->it_enable(ithd->it_vector);
TD_SET_IWAIT(td); /* we"re idle */
p->p_stats->p_ru.ru_nvcsw;
CTR2(KTR_INTR, "%s: pid %d: done", __func__, p->p_pid);
mi_switch();
CTR2(KTR_INTR, "%s: pid %d: resumed", __func__, p->p_pid);
}

如果此时it_need==1,则说明新来了中断,继续for循环为该中断服务,
否则挂起调度 。
代码:
mtx_unlock_spin(&sched_lock);
}
}

3,软件中断swi

我们将举例说明软件中断swi 。

3.1登记

系统启动时,调用start_softintr()登记两个重要的软件中断,
软时钟中断和VM软中断 。
当情况需要时,内核将调用swi_sched()来调度软件中断的运行 。
代码:
/*
* Start standard software interrupt threads
*/
static void
start_softintr(void *dummy)
{
struct proc *p;

if (swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK,
INTR_MPSAFE, &softclock_ih) ||
swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, INTR_MPSAFE, &vm_ih))
panic("died while creating standard software ithreads");

p = clk_ithd->it_td->td_proc;
PROC_LOCK(p);
p->p_flag |= P_NOLOAD;
PROC_UNLOCK(p);
}

int
swi_add(struct ithd **ithdp, const char *name, driver_intr_t handler,
void *arg, int pri, enum intr_type flags, void **cookiep)
{
struct ithd *ithd;
int error;

if (flags & (INTR_FAST | INTR_ENTROPY))
return (EINVAL);

ithd = (ithdp != NULL) ? *ithdp : NULL;

if (ithd != NULL) {
if ((ithd->it_flags & IT_SOFT) == 0)
return(EINVAL);
} else {
error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL,
"swi%d:", pri);
if (error)
return (error);

if (ithdp != NULL)
*ithdp = ithd;

推荐阅读