The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_intr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1997, Stefan Esser <se@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 unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/5.2/sys/kern/kern_intr.c 122917 2003-11-20 15:35:48Z markm $");
   29 
   30 #include "opt_ddb.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/bus.h>
   34 #include <sys/conf.h>
   35 #include <sys/rtprio.h>
   36 #include <sys/systm.h>
   37 #include <sys/interrupt.h>
   38 #include <sys/kernel.h>
   39 #include <sys/kthread.h>
   40 #include <sys/ktr.h>
   41 #include <sys/lock.h>
   42 #include <sys/malloc.h>
   43 #include <sys/mutex.h>
   44 #include <sys/proc.h>
   45 #include <sys/random.h>
   46 #include <sys/resourcevar.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/unistd.h>
   49 #include <sys/vmmeter.h>
   50 #include <machine/atomic.h>
   51 #include <machine/cpu.h>
   52 #include <machine/md_var.h>
   53 #include <machine/stdarg.h>
   54 #ifdef DDB
   55 #include <ddb/ddb.h>
   56 #include <ddb/db_sym.h>
   57 #endif
   58 
   59 struct  int_entropy {
   60         struct  proc *proc;
   61         uintptr_t vector;
   62 };
   63 
   64 void    *vm_ih;
   65 void    *softclock_ih;
   66 struct  ithd *clk_ithd;
   67 struct  ithd *tty_ithd;
   68 
   69 static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads");
   70 
   71 static void     ithread_update(struct ithd *);
   72 static void     ithread_loop(void *);
   73 static void     start_softintr(void *);
   74 
   75 u_char
   76 ithread_priority(enum intr_type flags)
   77 {
   78         u_char pri;
   79 
   80         flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET |
   81             INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK | INTR_TYPE_AV);
   82         switch (flags) {
   83         case INTR_TYPE_TTY:
   84                 pri = PI_TTYLOW;
   85                 break;
   86         case INTR_TYPE_BIO:
   87                 /*
   88                  * XXX We need to refine this.  BSD/OS distinguishes
   89                  * between tape and disk priorities.
   90                  */
   91                 pri = PI_DISK;
   92                 break;
   93         case INTR_TYPE_NET:
   94                 pri = PI_NET;
   95                 break;
   96         case INTR_TYPE_CAM:
   97                 pri = PI_DISK;          /* XXX or PI_CAM? */
   98                 break;
   99         case INTR_TYPE_AV:              /* Audio/video */
  100                 pri = PI_AV;
  101                 break;
  102         case INTR_TYPE_CLK:
  103                 pri = PI_REALTIME;
  104                 break;
  105         case INTR_TYPE_MISC:
  106                 pri = PI_DULL;          /* don't care */
  107                 break;
  108         default:
  109                 /* We didn't specify an interrupt level. */
  110                 panic("ithread_priority: no interrupt type in flags");
  111         }
  112 
  113         return pri;
  114 }
  115 
  116 /*
  117  * Regenerate the name (p_comm) and priority for a threaded interrupt thread.
  118  */
  119 static void
  120 ithread_update(struct ithd *ithd)
  121 {
  122         struct intrhand *ih;
  123         struct thread *td;
  124         struct proc *p;
  125         int entropy;
  126 
  127         mtx_assert(&ithd->it_lock, MA_OWNED);
  128         td = ithd->it_td;
  129         if (td == NULL)
  130                 return;
  131         p = td->td_proc;
  132 
  133         strlcpy(p->p_comm, ithd->it_name, sizeof(p->p_comm));
  134 
  135         ih = TAILQ_FIRST(&ithd->it_handlers);
  136         if (ih == NULL) {
  137                 mtx_lock_spin(&sched_lock);
  138                 td->td_priority = PRI_MAX_ITHD;
  139                 td->td_base_pri = PRI_MAX_ITHD;
  140                 mtx_unlock_spin(&sched_lock);
  141                 ithd->it_flags &= ~IT_ENTROPY;
  142                 return;
  143         }
  144         entropy = 0;
  145         mtx_lock_spin(&sched_lock);
  146         td->td_priority = ih->ih_pri;
  147         td->td_base_pri = ih->ih_pri;
  148         mtx_unlock_spin(&sched_lock);
  149         TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
  150                 if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 <
  151                     sizeof(p->p_comm)) {
  152                         strcat(p->p_comm, " ");
  153                         strcat(p->p_comm, ih->ih_name);
  154                 } else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) {
  155                         if (p->p_comm[sizeof(p->p_comm) - 2] == '+')
  156                                 p->p_comm[sizeof(p->p_comm) - 2] = '*';
  157                         else
  158                                 p->p_comm[sizeof(p->p_comm) - 2] = '+';
  159                 } else
  160                         strcat(p->p_comm, "+");
  161                 if (ih->ih_flags & IH_ENTROPY)
  162                         entropy++;
  163         }
  164         if (entropy)
  165                 ithd->it_flags |= IT_ENTROPY;
  166         else
  167                 ithd->it_flags &= ~IT_ENTROPY;
  168         CTR2(KTR_INTR, "%s: updated %s", __func__, p->p_comm);
  169 }
  170 
  171 int
  172 ithread_create(struct ithd **ithread, uintptr_t vector, int flags,
  173     void (*disable)(uintptr_t), void (*enable)(uintptr_t), const char *fmt, ...)
  174 {
  175         struct ithd *ithd;
  176         struct thread *td;
  177         struct proc *p;
  178         int error;
  179         va_list ap;
  180 
  181         /* The only valid flag during creation is IT_SOFT. */
  182         if ((flags & ~IT_SOFT) != 0)
  183                 return (EINVAL);
  184 
  185         ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO);
  186         ithd->it_vector = vector;
  187         ithd->it_disable = disable;
  188         ithd->it_enable = enable;
  189         ithd->it_flags = flags;
  190         TAILQ_INIT(&ithd->it_handlers);
  191         mtx_init(&ithd->it_lock, "ithread", NULL, MTX_DEF);
  192 
  193         va_start(ap, fmt);
  194         vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap);
  195         va_end(ap);
  196 
  197         error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID,
  198             0, "%s", ithd->it_name);
  199         if (error) {
  200                 mtx_destroy(&ithd->it_lock);
  201                 free(ithd, M_ITHREAD);
  202                 return (error);
  203         }
  204         td = FIRST_THREAD_IN_PROC(p);   /* XXXKSE */
  205         mtx_lock_spin(&sched_lock);
  206         td->td_ksegrp->kg_pri_class = PRI_ITHD;
  207         td->td_priority = PRI_MAX_ITHD;
  208         TD_SET_IWAIT(td);
  209         mtx_unlock_spin(&sched_lock);
  210         ithd->it_td = td;
  211         td->td_ithd = ithd;
  212         if (ithread != NULL)
  213                 *ithread = ithd;
  214         CTR2(KTR_INTR, "%s: created %s", __func__, ithd->it_name);
  215         return (0);
  216 }
  217 
  218 int
  219 ithread_destroy(struct ithd *ithread)
  220 {
  221 
  222         struct thread *td;
  223         if (ithread == NULL)
  224                 return (EINVAL);
  225 
  226         td = ithread->it_td;
  227         mtx_lock(&ithread->it_lock);
  228         if (!TAILQ_EMPTY(&ithread->it_handlers)) {
  229                 mtx_unlock(&ithread->it_lock);
  230                 return (EINVAL);
  231         }
  232         ithread->it_flags |= IT_DEAD;
  233         mtx_lock_spin(&sched_lock);
  234         if (TD_AWAITING_INTR(td)) {
  235                 TD_CLR_IWAIT(td);
  236                 setrunqueue(td);
  237         }
  238         mtx_unlock_spin(&sched_lock);
  239         mtx_unlock(&ithread->it_lock);
  240         CTR2(KTR_INTR, "%s: killing %s", __func__, ithread->it_name);
  241         return (0);
  242 }
  243 
  244 int
  245 ithread_add_handler(struct ithd* ithread, const char *name,
  246     driver_intr_t handler, void *arg, u_char pri, enum intr_type flags,
  247     void **cookiep)
  248 {
  249         struct intrhand *ih, *temp_ih;
  250 
  251         if (ithread == NULL || name == NULL || handler == NULL)
  252                 return (EINVAL);
  253 
  254         ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO);
  255         ih->ih_handler = handler;
  256         ih->ih_argument = arg;
  257         ih->ih_name = name;
  258         ih->ih_ithread = ithread;
  259         ih->ih_pri = pri;
  260         if (flags & INTR_FAST)
  261                 ih->ih_flags = IH_FAST;
  262         else if (flags & INTR_EXCL)
  263                 ih->ih_flags = IH_EXCLUSIVE;
  264         if (flags & INTR_MPSAFE)
  265                 ih->ih_flags |= IH_MPSAFE;
  266         if (flags & INTR_ENTROPY)
  267                 ih->ih_flags |= IH_ENTROPY;
  268 
  269         mtx_lock(&ithread->it_lock);
  270         if ((flags & INTR_EXCL) != 0 && !TAILQ_EMPTY(&ithread->it_handlers))
  271                 goto fail;
  272         if (!TAILQ_EMPTY(&ithread->it_handlers)) {
  273                 temp_ih = TAILQ_FIRST(&ithread->it_handlers);
  274                 if (temp_ih->ih_flags & IH_EXCLUSIVE)
  275                         goto fail;
  276                 if ((ih->ih_flags & IH_FAST) && !(temp_ih->ih_flags & IH_FAST))
  277                         goto fail;
  278                 if (!(ih->ih_flags & IH_FAST) && (temp_ih->ih_flags & IH_FAST))
  279                         goto fail;
  280         }
  281 
  282         TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next)
  283             if (temp_ih->ih_pri > ih->ih_pri)
  284                     break;
  285         if (temp_ih == NULL)
  286                 TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next);
  287         else
  288                 TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
  289         ithread_update(ithread);
  290         mtx_unlock(&ithread->it_lock);
  291 
  292         if (cookiep != NULL)
  293                 *cookiep = ih;
  294         CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name,
  295             ithread->it_name);
  296         return (0);
  297 
  298 fail:
  299         mtx_unlock(&ithread->it_lock);
  300         free(ih, M_ITHREAD);
  301         return (EINVAL);
  302 }
  303 
  304 int
  305 ithread_remove_handler(void *cookie)
  306 {
  307         struct intrhand *handler = (struct intrhand *)cookie;
  308         struct ithd *ithread;
  309 #ifdef INVARIANTS
  310         struct intrhand *ih;
  311 #endif
  312 
  313         if (handler == NULL)
  314                 return (EINVAL);
  315         ithread = handler->ih_ithread;
  316         KASSERT(ithread != NULL,
  317             ("interrupt handler \"%s\" has a NULL interrupt thread",
  318                 handler->ih_name));
  319         CTR3(KTR_INTR, "%s: removing %s from %s", __func__, handler->ih_name,
  320             ithread->it_name);
  321         mtx_lock(&ithread->it_lock);
  322 #ifdef INVARIANTS
  323         TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next)
  324                 if (ih == handler)
  325                         goto ok;
  326         mtx_unlock(&ithread->it_lock);
  327         panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"",
  328             ih->ih_name, ithread->it_name);
  329 ok:
  330 #endif
  331         /*
  332          * If the interrupt thread is already running, then just mark this
  333          * handler as being dead and let the ithread do the actual removal.
  334          */
  335         mtx_lock_spin(&sched_lock);
  336         if (!TD_AWAITING_INTR(ithread->it_td)) {
  337                 handler->ih_flags |= IH_DEAD;
  338 
  339                 /*
  340                  * Ensure that the thread will process the handler list
  341                  * again and remove this handler if it has already passed
  342                  * it on the list.
  343                  */
  344                 ithread->it_need = 1;
  345         } else 
  346                 TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next);
  347         mtx_unlock_spin(&sched_lock);
  348         if ((handler->ih_flags & IH_DEAD) != 0)
  349                 msleep(handler, &ithread->it_lock, PUSER, "itrmh", 0);
  350         ithread_update(ithread);
  351         mtx_unlock(&ithread->it_lock);
  352         free(handler, M_ITHREAD);
  353         return (0);
  354 }
  355 
  356 int
  357 ithread_schedule(struct ithd *ithread, int do_switch)
  358 {
  359         struct int_entropy entropy;
  360         struct thread *td;
  361         struct thread *ctd;
  362         struct proc *p;
  363 
  364         /*
  365          * If no ithread or no handlers, then we have a stray interrupt.
  366          */
  367         if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers))
  368                 return (EINVAL);
  369 
  370         ctd = curthread;
  371         /*
  372          * If any of the handlers for this ithread claim to be good
  373          * sources of entropy, then gather some.
  374          */
  375         if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) {
  376                 entropy.vector = ithread->it_vector;
  377                 entropy.proc = ctd->td_proc;
  378                 random_harvest(&entropy, sizeof(entropy), 2, 0,
  379                     RANDOM_INTERRUPT);
  380         }
  381 
  382         td = ithread->it_td;
  383         p = td->td_proc;
  384         KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name));
  385         CTR4(KTR_INTR, "%s: pid %d: (%s) need = %d",
  386             __func__, p->p_pid, p->p_comm, ithread->it_need);
  387 
  388         /*
  389          * Set it_need to tell the thread to keep running if it is already
  390          * running.  Then, grab sched_lock and see if we actually need to
  391          * put this thread on the runqueue.  If so and the do_switch flag is
  392          * true and it is safe to switch, then switch to the ithread
  393          * immediately.  Otherwise, set the needresched flag to guarantee
  394          * that this ithread will run before any userland processes.
  395          */
  396         ithread->it_need = 1;
  397         mtx_lock_spin(&sched_lock);
  398         if (TD_AWAITING_INTR(td)) {
  399                 CTR2(KTR_INTR, "%s: setrunqueue %d", __func__, p->p_pid);
  400                 TD_CLR_IWAIT(td);
  401                 setrunqueue(td);
  402                 if (do_switch &&
  403                     (ctd->td_critnest == 1) ) {
  404                         KASSERT((TD_IS_RUNNING(ctd)),
  405                             ("ithread_schedule: Bad state for curthread."));
  406                         ctd->td_proc->p_stats->p_ru.ru_nivcsw++;
  407                         if (ctd->td_flags & TDF_IDLETD)
  408                                 ctd->td_state = TDS_CAN_RUN; /* XXXKSE */
  409                         mi_switch();
  410                 } else {
  411                         curthread->td_flags |= TDF_NEEDRESCHED;
  412                 }
  413         } else {
  414                 CTR4(KTR_INTR, "%s: pid %d: it_need %d, state %d",
  415                     __func__, p->p_pid, ithread->it_need, td->td_state);
  416         }
  417         mtx_unlock_spin(&sched_lock);
  418 
  419         return (0);
  420 }
  421 
  422 int
  423 swi_add(struct ithd **ithdp, const char *name, driver_intr_t handler, 
  424             void *arg, int pri, enum intr_type flags, void **cookiep)
  425 {
  426         struct ithd *ithd;
  427         int error;
  428 
  429         if (flags & (INTR_FAST | INTR_ENTROPY))
  430                 return (EINVAL);
  431 
  432         ithd = (ithdp != NULL) ? *ithdp : NULL;
  433 
  434         if (ithd != NULL) {
  435                 if ((ithd->it_flags & IT_SOFT) == 0)
  436                         return(EINVAL);
  437         } else {
  438                 error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL,
  439                     "swi%d:", pri);
  440                 if (error)
  441                         return (error);
  442 
  443                 if (ithdp != NULL)
  444                         *ithdp = ithd;
  445         }
  446         return (ithread_add_handler(ithd, name, handler, arg,
  447                     (pri * RQ_PPQ) + PI_SOFT, flags, cookiep));
  448 }
  449 
  450 
  451 /*
  452  * Schedule a heavyweight software interrupt process. 
  453  */
  454 void
  455 swi_sched(void *cookie, int flags)
  456 {
  457         struct intrhand *ih = (struct intrhand *)cookie;
  458         struct ithd *it = ih->ih_ithread;
  459         int error;
  460 
  461         atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */
  462                 
  463         CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d",
  464                 it->it_td->td_proc->p_pid, it->it_td->td_proc->p_comm, it->it_need);
  465 
  466         /*
  467          * Set ih_need for this handler so that if the ithread is already
  468          * running it will execute this handler on the next pass.  Otherwise,
  469          * it will execute it the next time it runs.
  470          */
  471         atomic_store_rel_int(&ih->ih_need, 1);
  472         if (!(flags & SWI_DELAY)) {
  473                 error = ithread_schedule(it, !cold && !dumping);
  474                 KASSERT(error == 0, ("stray software interrupt"));
  475         }
  476 }
  477 
  478 /*
  479  * This is the main code for interrupt threads.
  480  */
  481 static void
  482 ithread_loop(void *arg)
  483 {
  484         struct ithd *ithd;              /* our thread context */
  485         struct intrhand *ih;            /* and our interrupt handler chain */
  486         struct thread *td;
  487         struct proc *p;
  488         
  489         td = curthread;
  490         p = td->td_proc;
  491         ithd = (struct ithd *)arg;      /* point to myself */
  492         KASSERT(ithd->it_td == td && td->td_ithd == ithd,
  493             ("%s: ithread and proc linkage out of sync", __func__));
  494 
  495         /*
  496          * As long as we have interrupts outstanding, go through the
  497          * list of handlers, giving each one a go at it.
  498          */
  499         for (;;) {
  500                 /*
  501                  * If we are an orphaned thread, then just die.
  502                  */
  503                 if (ithd->it_flags & IT_DEAD) {
  504                         CTR3(KTR_INTR, "%s: pid %d: (%s) exiting", __func__,
  505                             p->p_pid, p->p_comm);
  506                         td->td_ithd = NULL;
  507                         mtx_destroy(&ithd->it_lock);
  508                         mtx_lock(&Giant);
  509                         free(ithd, M_ITHREAD);
  510                         kthread_exit(0);
  511                 }
  512 
  513                 CTR4(KTR_INTR, "%s: pid %d: (%s) need=%d", __func__,
  514                      p->p_pid, p->p_comm, ithd->it_need);
  515                 while (ithd->it_need) {
  516                         /*
  517                          * Service interrupts.  If another interrupt
  518                          * arrives while we are running, they will set
  519                          * it_need to denote that we should make
  520                          * another pass.
  521                          */
  522                         atomic_store_rel_int(&ithd->it_need, 0);
  523 restart:
  524                         TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
  525                                 if (ithd->it_flags & IT_SOFT && !ih->ih_need)
  526                                         continue;
  527                                 atomic_store_rel_int(&ih->ih_need, 0);
  528                                 CTR6(KTR_INTR,
  529                                     "%s: pid %d ih=%p: %p(%p) flg=%x", __func__,
  530                                     p->p_pid, (void *)ih,
  531                                     (void *)ih->ih_handler, ih->ih_argument,
  532                                     ih->ih_flags);
  533 
  534                                 if ((ih->ih_flags & IH_DEAD) != 0) {
  535                                         mtx_lock(&ithd->it_lock);
  536                                         TAILQ_REMOVE(&ithd->it_handlers, ih,
  537                                             ih_next);
  538                                         wakeup(ih);
  539                                         mtx_unlock(&ithd->it_lock);
  540                                         goto restart;
  541                                 }
  542                                 if ((ih->ih_flags & IH_MPSAFE) == 0)
  543                                         mtx_lock(&Giant);
  544                                 ih->ih_handler(ih->ih_argument);
  545                                 if ((ih->ih_flags & IH_MPSAFE) == 0)
  546                                         mtx_unlock(&Giant);
  547                         }
  548                 }
  549 
  550                 /*
  551                  * Processed all our interrupts.  Now get the sched
  552                  * lock.  This may take a while and it_need may get
  553                  * set again, so we have to check it again.
  554                  */
  555                 WITNESS_WARN(WARN_PANIC, NULL, "suspending ithread");
  556                 mtx_assert(&Giant, MA_NOTOWNED);
  557                 mtx_lock_spin(&sched_lock);
  558                 if (!ithd->it_need) {
  559                         /*
  560                          * Should we call this earlier in the loop above?
  561                          */
  562                         if (ithd->it_enable != NULL)
  563                                 ithd->it_enable(ithd->it_vector);
  564                         TD_SET_IWAIT(td); /* we're idle */
  565                         p->p_stats->p_ru.ru_nvcsw++;
  566                         CTR2(KTR_INTR, "%s: pid %d: done", __func__, p->p_pid);
  567                         mi_switch();
  568                         CTR2(KTR_INTR, "%s: pid %d: resumed", __func__, p->p_pid);
  569                 }
  570                 mtx_unlock_spin(&sched_lock);
  571         }
  572 }
  573 
  574 #ifdef DDB
  575 /*
  576  * Dump details about an interrupt handler
  577  */
  578 static void
  579 db_dump_intrhand(struct intrhand *ih)
  580 {
  581         int comma;
  582 
  583         db_printf("\t%-10s ", ih->ih_name);
  584         switch (ih->ih_pri) {
  585         case PI_REALTIME:
  586                 db_printf("CLK ");
  587                 break;
  588         case PI_AV:
  589                 db_printf("AV  ");
  590                 break;
  591         case PI_TTYHIGH:
  592         case PI_TTYLOW:
  593                 db_printf("TTY ");
  594                 break;
  595         case PI_TAPE:
  596                 db_printf("TAPE");
  597                 break;
  598         case PI_NET:
  599                 db_printf("NET ");
  600                 break;
  601         case PI_DISK:
  602         case PI_DISKLOW:
  603                 db_printf("DISK");
  604                 break;
  605         case PI_DULL:
  606                 db_printf("DULL");
  607                 break;
  608         default:
  609                 if (ih->ih_pri >= PI_SOFT)
  610                         db_printf("SWI ");
  611                 else
  612                         db_printf("%4u", ih->ih_pri);
  613                 break;
  614         }
  615         db_printf(" ");
  616         db_printsym((uintptr_t)ih->ih_handler, DB_STGY_PROC);
  617         db_printf("(%p)", ih->ih_argument);
  618         if (ih->ih_need ||
  619             (ih->ih_flags & (IH_FAST | IH_EXCLUSIVE | IH_ENTROPY | IH_DEAD |
  620             IH_MPSAFE)) != 0) {
  621                 db_printf(" {");
  622                 comma = 0;
  623                 if (ih->ih_flags & IH_FAST) {
  624                         db_printf("FAST");
  625                         comma = 1;
  626                 }
  627                 if (ih->ih_flags & IH_EXCLUSIVE) {
  628                         if (comma)
  629                                 db_printf(", ");
  630                         db_printf("EXCL");
  631                         comma = 1;
  632                 }
  633                 if (ih->ih_flags & IH_ENTROPY) {
  634                         if (comma)
  635                                 db_printf(", ");
  636                         db_printf("ENTROPY");
  637                         comma = 1;
  638                 }
  639                 if (ih->ih_flags & IH_DEAD) {
  640                         if (comma)
  641                                 db_printf(", ");
  642                         db_printf("DEAD");
  643                         comma = 1;
  644                 }
  645                 if (ih->ih_flags & IH_MPSAFE) {
  646                         if (comma)
  647                                 db_printf(", ");
  648                         db_printf("MPSAFE");
  649                         comma = 1;
  650                 }
  651                 if (ih->ih_need) {
  652                         if (comma)
  653                                 db_printf(", ");
  654                         db_printf("NEED");
  655                 }
  656                 db_printf("}");
  657         }
  658         db_printf("\n");
  659 }
  660 
  661 /*
  662  * Dump details about an ithread
  663  */
  664 void
  665 db_dump_ithread(struct ithd *ithd, int handlers)
  666 {
  667         struct proc *p;
  668         struct intrhand *ih;
  669         int comma;
  670 
  671         if (ithd->it_td != NULL) {
  672                 p = ithd->it_td->td_proc;
  673                 db_printf("%s (pid %d)", p->p_comm, p->p_pid);
  674         } else
  675                 db_printf("%s: (no thread)", ithd->it_name);
  676         if ((ithd->it_flags & (IT_SOFT | IT_ENTROPY | IT_DEAD)) != 0 ||
  677             ithd->it_need) {
  678                 db_printf(" {");
  679                 comma = 0;
  680                 if (ithd->it_flags & IT_SOFT) {
  681                         db_printf("SOFT");
  682                         comma = 1;
  683                 }
  684                 if (ithd->it_flags & IT_ENTROPY) {
  685                         if (comma)
  686                                 db_printf(", ");
  687                         db_printf("ENTROPY");
  688                         comma = 1;
  689                 }
  690                 if (ithd->it_flags & IT_DEAD) {
  691                         if (comma)
  692                                 db_printf(", ");
  693                         db_printf("DEAD");
  694                         comma = 1;
  695                 }
  696                 if (ithd->it_need) {
  697                         if (comma)
  698                                 db_printf(", ");
  699                         db_printf("NEED");
  700                 }
  701                 db_printf("}");
  702         }
  703         db_printf("\n");
  704 
  705         if (handlers)
  706                 TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next)
  707                     db_dump_intrhand(ih);
  708 }
  709 #endif /* DDB */
  710 
  711 /*
  712  * Start standard software interrupt threads
  713  */
  714 static void
  715 start_softintr(void *dummy)
  716 {
  717         struct proc *p;
  718 
  719         if (swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK,
  720                 INTR_MPSAFE, &softclock_ih) ||
  721             swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, INTR_MPSAFE, &vm_ih))
  722                 panic("died while creating standard software ithreads");
  723 
  724         p = clk_ithd->it_td->td_proc;
  725         PROC_LOCK(p);
  726         p->p_flag |= P_NOLOAD;
  727         PROC_UNLOCK(p);
  728 }
  729 SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL)
  730 
  731 /* 
  732  * Sysctls used by systat and others: hw.intrnames and hw.intrcnt.
  733  * The data for this machine dependent, and the declarations are in machine
  734  * dependent code.  The layout of intrnames and intrcnt however is machine
  735  * independent.
  736  *
  737  * We do not know the length of intrcnt and intrnames at compile time, so
  738  * calculate things at run time.
  739  */
  740 static int
  741 sysctl_intrnames(SYSCTL_HANDLER_ARGS)
  742 {
  743         return (sysctl_handle_opaque(oidp, intrnames, eintrnames - intrnames, 
  744            req));
  745 }
  746 
  747 SYSCTL_PROC(_hw, OID_AUTO, intrnames, CTLTYPE_OPAQUE | CTLFLAG_RD,
  748     NULL, 0, sysctl_intrnames, "", "Interrupt Names");
  749 
  750 static int
  751 sysctl_intrcnt(SYSCTL_HANDLER_ARGS)
  752 {
  753         return (sysctl_handle_opaque(oidp, intrcnt, 
  754             (char *)eintrcnt - (char *)intrcnt, req));
  755 }
  756 
  757 SYSCTL_PROC(_hw, OID_AUTO, intrcnt, CTLTYPE_OPAQUE | CTLFLAG_RD,
  758     NULL, 0, sysctl_intrcnt, "", "Interrupt Counts");
  759 
  760 #ifdef DDB
  761 /*
  762  * DDB command to dump the interrupt statistics.
  763  */
  764 DB_SHOW_COMMAND(intrcnt, db_show_intrcnt)
  765 {
  766         u_long *i;
  767         char *cp;
  768         int quit;
  769 
  770         cp = intrnames;
  771         db_setup_paging(db_simple_pager, &quit, DB_LINES_PER_PAGE);
  772         for (i = intrcnt, quit = 0; i != eintrcnt && !quit; i++) {
  773                 if (*cp == '\0')
  774                         break;
  775                 if (*i != 0)
  776                         db_printf("%s\t%lu\n", cp, *i);
  777                 cp += strlen(cp) + 1;
  778         }
  779 }
  780 #endif

Cache object: 8927b72dd580f6290fa7de66e0f5fa20


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.