快捷搜索:   服务器  安全  linux 安全  MYSQL  dedecms

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


             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
        * 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;
       }
       return (ithread_add_handler(ithd, name, handler, arg,
              (pri * RQ_PPQ) + PI_SOFT, flags, cookiep));
    }


 

   3.2调度

    硬件时钟中断,需要处理非紧急时钟事务时,调度softclock,以便在响应完硬件时钟中断后
    运行softclock。
    代码:

    /*
     * The real-time timer, interrupting hz times per second.
     */
    void
    hardclock(frame)
       register struct clockframe *frame;
    {
       ......

       if (need_softclock)

顶(0)
踩(0)

您可能还会对下面的文章感兴趣:

最新评论