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/eventcount.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  * Mach Operating System
    3  * Copyright (c) 1993-1987 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        eventcount.c,v $
   29  * Revision 2.12  93/08/10  15:11:22  mrt
   30  *      Added evc_wait_clear.  Always clears count before blocking.
   31  *      [93/03/22            cmaeda]
   32  * 
   33  * Revision 2.11  93/05/15  18:54:40  mrt
   34  *      machparam.h -> machspl.h
   35  * 
   36  * Revision 2.10  93/02/01  09:50:07  danner
   37  *      Remove evc_signal panic for suspension case.
   38  *      [93/01/28            danner]
   39  * 
   40  * Revision 2.9  93/01/24  13:18:45  danner
   41  *      rename notify routines; prototypes.
   42  *      [93/01/22            danner]
   43  * 
   44  * Revision 2.8  93/01/21  12:21:49  danner
   45  *      Added evc_notify_thread_destroy_bkpt and
   46  *      evc_notify_thread_destroy.
   47  *      [93/01/20            bershad]
   48  * 
   49  * Revision 2.7  93/01/14  17:33:59  danner
   50  *      Typecast assert_wait arguments.
   51  *      [93/01/12            danner]
   52  *      Fixes for multiprocessor usage.
   53  *      [92/11/16            jfriedl]
   54  *      Fixed two-for-one bug in evc_wait, per jcb's report.
   55  *      See comments in code.
   56  *      [92/12/15            af]
   57  *      Proper spl typing.
   58  *      [92/11/30            af]
   59  * 
   60  * Revision 2.6  92/08/03  17:36:55  jfriedl
   61  *      removed silly prototypes
   62  *      [92/08/02            jfriedl]
   63  * 
   64  * Revision 2.5  92/05/21  17:13:12  jfriedl
   65  *      Added void type to functions that needed it.
   66  *      [92/05/16            jfriedl]
   67  * 
   68  * Revision 2.4  92/01/03  20:40:02  dbg
   69  *      Made user-safe with a small translation table.
   70  *      This all will be refined at a later time.
   71  *      [91/12/27            af]
   72  * 
   73  * Revision 2.3  91/12/14  14:31:43  jsb
   74  *      Replaced gimmeabreak calls with panics.
   75  * 
   76  * Revision 2.2  91/12/13  14:54:44  jsb
   77  *      Created.
   78  *      [91/11/01            af]
   79  * 
   80  */
   81 /*
   82  *      File:   eventcount.c
   83  *      Author: Alessandro Forin
   84  *      Date:   10/91
   85  *
   86  *      Eventcounters, for user-level drivers synchronization
   87  *
   88  */
   89 
   90 
   91 #include <cpus.h>
   92 
   93 #include <mach/machine.h>
   94 #include <kern/ast.h>
   95 #include <kern/cpu_number.h>
   96 #include <kern/lock.h>
   97 #include <kern/processor.h>
   98 #include <kern/queue.h>
   99 #include <kern/sched.h>
  100 #include <kern/sched_prim.h>
  101 #include <kern/thread.h>
  102 #include <machine/machspl.h>    /* For def'n of splsched() */
  103 
  104 #include <kern/eventcount.h>
  105 
  106 
  107 #if  NCPUS <= 1
  108 void simpler_thread_setrun(
  109         thread_t        th,
  110         boolean_t       may_preempt); /* forward */
  111 #endif
  112 
  113 #define MAX_EVCS        10              /* xxx for now */
  114 evc_t   all_eventcounters[MAX_EVCS];
  115 
  116 /*
  117  * Initialization
  118  */
  119 void
  120 evc_init(evc_t  ev)
  121 {
  122         int i;
  123 
  124         bzero((char*)ev, sizeof(*ev));
  125 
  126         /* keep track of who is who */
  127         for (i = 0; i < MAX_EVCS; i++)
  128                 if (all_eventcounters[i] == 0) break;
  129         if (i == MAX_EVCS) {
  130                 printf("Too many eventcounters\n");
  131                 return;
  132         }
  133 
  134         all_eventcounters[i] = ev;
  135         ev->ev_id = i;
  136         ev->sanity = ev;
  137         ev->waiting_thread = THREAD_NULL;
  138         simple_lock_init(&ev->lock);
  139 }
  140 
  141 /*
  142  * Finalization
  143  */
  144 void
  145 evc_destroy(evc_t       ev)
  146 {
  147         evc_signal(ev);
  148         ev->sanity = 0;
  149         if (all_eventcounters[ev->ev_id] == ev)
  150                 all_eventcounters[ev->ev_id] = 0;
  151         ev->ev_id = -1;
  152 }
  153 
  154 /*
  155  * Thread termination.
  156  * HORRIBLE. This stuff needs to be fixed.
  157  */
  158 void evc_notify_abort(thread_t thread)
  159 {
  160     int i;
  161     evc_t ev;
  162     int s = splsched();
  163     for (i = 0; i < MAX_EVCS; i++)  {
  164         ev = all_eventcounters[i];
  165         if (ev)  {
  166             simple_lock(&ev->lock);
  167             if (ev->waiting_thread == thread)  
  168               {
  169                 ev->waiting_thread = 0;
  170                 /* Removal of a waiting thread has to bump the count by one */
  171                 ev->count++;
  172               }
  173             simple_unlock(&ev->lock);
  174         }
  175     }
  176     splx(s);
  177 }
  178 
  179 /*
  180  * Just so that we return success, and give
  181  * up the stack while blocked
  182  */
  183 static void
  184 evc_continue(void)
  185 {
  186         thread_syscall_return(KERN_SUCCESS);
  187         /* NOTREACHED */
  188 }
  189 
  190 /*
  191  * User-trappable
  192  */
  193 kern_return_t evc_wait(natural_t ev_id)
  194 {
  195         spl_t           s;
  196         kern_return_t   ret;
  197         evc_t           ev;
  198 
  199         if ((ev_id >= MAX_EVCS) ||
  200             ((ev = all_eventcounters[ev_id]) == 0) ||
  201             (ev->ev_id != ev_id) || (ev->sanity != ev))
  202                 return KERN_INVALID_ARGUMENT;
  203 
  204         s = splsched();
  205         simple_lock(&ev->lock);
  206                 /*
  207                  * The values assumed by the "count" field are
  208                  * as follows:
  209                  *      0       At initialization time, and with no
  210                  *              waiting thread means no events pending;
  211                  *              with waiting thread means the event
  212                  *              was signalled and the thread not yet resumed
  213                  *      -1      no events, there must be a waiting thread
  214                  *      N>0     no waiting thread means N pending,
  215                  *              with waiting thread N-1 pending.
  216                  *      
  217                  */
  218                 if (ev->count > 0) {
  219                         ev->count--;
  220                         ret = KERN_SUCCESS;
  221                 } else {
  222                         if (ev->waiting_thread == THREAD_NULL) {
  223                                 ev->count--;
  224                                 ev->waiting_thread = current_thread();
  225                                 assert_wait((event_t) 0, TRUE); /* ifnot race */
  226                                 simple_unlock(&ev->lock);
  227                                 thread_block(evc_continue);
  228                                 /* NOTREACHED */
  229                         }
  230                         ret = KERN_NO_SPACE; /* XX */
  231                 }
  232         simple_unlock(&ev->lock);
  233         splx(s);
  234         return ret;
  235 }
  236 
  237 /*
  238  * User-trappable
  239  */
  240 kern_return_t evc_wait_clear(natural_t ev_id)
  241 {
  242         spl_t           s;
  243         kern_return_t   ret;
  244         evc_t           ev;
  245 
  246         if ((ev_id >= MAX_EVCS) ||
  247             ((ev = all_eventcounters[ev_id]) == 0) ||
  248             (ev->ev_id != ev_id) || (ev->sanity != ev))
  249                 return KERN_INVALID_ARGUMENT;
  250 
  251         s = splsched();
  252         simple_lock(&ev->lock);
  253 
  254                 /*
  255                  * The values assumed by the "count" field are
  256                  * as follows:
  257                  *      0       At initialization time, and with no
  258                  *              waiting thread means no events pending;
  259                  *              with waiting thread means the event
  260                  *              was signalled and the thread not yet resumed
  261                  *      -1      no events, there must be a waiting thread
  262                  *      N>0     no waiting thread means N pending,
  263                  *              with waiting thread N-1 pending.
  264                  *      
  265                  */
  266                 /*
  267                  *  Note that we always clear count before blocking.
  268                  */
  269                 if (ev->waiting_thread == THREAD_NULL) {
  270                         ev->count = -1;
  271                         ev->waiting_thread = current_thread();
  272                         assert_wait((event_t) 0, TRUE); /* ifnot race */
  273                         simple_unlock(&ev->lock);
  274                         thread_block(evc_continue);
  275                         /* NOTREACHED */
  276                 }
  277 
  278         simple_unlock(&ev->lock);
  279         splx(s);
  280         ret = KERN_NO_SPACE; /* XX */
  281 }
  282 
  283 /*
  284  * Called exclusively from interrupt context
  285  */
  286 void
  287 evc_signal(evc_t ev)
  288 {
  289     register volatile thread_t thread;
  290     register int state;
  291     spl_t    s;
  292     if (ev->sanity != ev)
  293       return;
  294 
  295     s = splsched();
  296     simple_lock(&ev->lock);
  297     ev->count++;
  298     if (thread = ev->waiting_thread, thread != THREAD_NULL)
  299     {
  300         ev->waiting_thread = 0;
  301 
  302 #if (NCPUS > 1)
  303       retry:
  304         while((thread->state & TH_RUN) || thread->lock.lock_data)
  305                 ;
  306 #endif
  307         thread_lock(thread);
  308 
  309         /* make thread runnable on this processor */
  310         /* taken from clear_wait */
  311         switch ((state = thread->state) & TH_SCHED_STATE)
  312         {
  313             case  TH_WAIT | TH_SUSP | TH_UNINT:
  314             case  TH_WAIT           | TH_UNINT:
  315             case  TH_WAIT:
  316                 /*
  317                  *      Sleeping and not suspendable - put
  318                  *      on run queue.
  319                  */
  320                 thread->state = (state &~ TH_WAIT) | TH_RUN;
  321                 thread_unlock(thread);
  322 #if NCPUS > 1
  323                 thread_setrun(thread, TRUE);
  324 #else
  325                 simpler_thread_setrun(thread, TRUE);
  326 #endif
  327                 break;
  328 
  329             case TH_RUN | TH_WAIT:
  330 #if (NCPUS > 1)
  331                 /*
  332                  * Legal on MP: between assert_wait()
  333                  * and thread_block(), in evc_wait() above.
  334                  *
  335                  * Mmm. Maybe don't need now that the while(..) check is
  336                  * done before the thread lock is grabbed.....
  337                  */
  338                 thread_unlock(thread);
  339                 goto retry;
  340 #else
  341                 /*FALLTHROUGH*/
  342 #endif
  343             case          TH_WAIT | TH_SUSP:
  344             case TH_RUN | TH_WAIT | TH_SUSP:
  345             case TH_RUN | TH_WAIT           | TH_UNINT:
  346             case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT:
  347 
  348                 /*
  349                  *      Either already running, or suspended.
  350                  *      Just clear the wait.
  351                  */
  352                 thread->state = state &~ TH_WAIT;
  353                 thread_unlock(thread);
  354                 break;
  355 
  356             default:
  357                 /*
  358                  *      Not waiting.
  359                  */
  360                 panic("evc_signal.3");
  361                 thread_unlock(thread);
  362                 break;
  363         }
  364     }
  365 
  366     simple_unlock(&ev->lock);
  367     splx(s);
  368 }
  369 
  370 #if     NCPUS <= 1
  371 /*
  372  * The scheduler is too messy for my old little brain
  373  */
  374 void
  375 simpler_thread_setrun(
  376         thread_t        th,
  377         boolean_t       may_preempt)
  378 {
  379         register struct run_queue       *rq;
  380         register                        whichq;
  381 
  382         /*
  383          *      XXX should replace queue with a boolean in this case.
  384          */
  385         if (default_pset.idle_count > 0) {
  386                 processor_t     processor;
  387 
  388                 processor = (processor_t) queue_first(&default_pset.idle_queue);
  389                 queue_remove(&default_pset.idle_queue, processor,
  390                 processor_t, processor_queue);
  391                 default_pset.idle_count--;
  392                 processor->next_thread = th;
  393                 processor->state = PROCESSOR_DISPATCHING;
  394                 return;
  395         }
  396         rq = &(master_processor->runq);
  397         ast_on(cpu_number(), AST_BLOCK);
  398 
  399         whichq = (th)->sched_pri;
  400         simple_lock(&(rq)->lock);       /* lock the run queue */
  401         enqueue_head(&(rq)->runq[whichq], (queue_entry_t) (th));
  402 
  403         if (whichq < (rq)->low || (rq)->count == 0)
  404                  (rq)->low = whichq;    /* minimize */
  405         (rq)->count++;
  406         (th)->runq = (rq);
  407         simple_unlock(&(rq)->lock);
  408 
  409         /*
  410          *      Turn off first_quantum to allow context switch.
  411          */
  412         current_processor()->first_quantum = FALSE;
  413 }
  414 #endif  /* NCPUS > 1 */
  415 

Cache object: e8604ffdcc9f18d9380d0830ab4c585a


[ 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.