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.13  93/11/17  17:08:47  dbg
   30  *      Changed evc_notify_abort to evc_wait_interrupt, since it is only
   31  *      used by thread_halt (to 'interrupt' an evc_wait).  It knows
   32  *      about the evc_wait continuation.
   33  *      [93/08/20            dbg]
   34  * 
   35  *      Break up thread lock.  Use thread_will_wait and thread_go
   36  *      to change thread state.
   37  *      [93/05/26            dbg]
   38  * 
   39  *      Declare contination functions as returning 'no_return'.
   40  * 
   41  *      Added return code to evc_init.  Fixed locking in evc_signal.
   42  * 
   43  *      Removed include of kern/sched.h.  Added ANSI prototypes.
   44  *      Removed simpler_thread_setrun: we'll fix thread_setrun
   45  *      instead.
   46  *      [93/05/21            dbg]
   47  * 
   48  * Revision 2.12  93/08/10  15:11:22  mrt
   49  *      Added evc_wait_clear.  Always clears count before blocking.
   50  *      [93/03/22            cmaeda]
   51  * 
   52  * Revision 2.11  93/05/15  18:54:40  mrt
   53  *      machparam.h -> machspl.h
   54  * 
   55  * Revision 2.10  93/02/01  09:50:07  danner
   56  *      Remove evc_signal panic for suspension case.
   57  *      [93/01/28            danner]
   58  * 
   59  * Revision 2.9  93/01/24  13:18:45  danner
   60  *      rename notify routines; prototypes.
   61  *      [93/01/22            danner]
   62  * 
   63  * Revision 2.8  93/01/21  12:21:49  danner
   64  *      Added evc_notify_thread_destroy_bkpt and
   65  *      evc_notify_thread_destroy.
   66  *      [93/01/20            bershad]
   67  * 
   68  * Revision 2.7  93/01/14  17:33:59  danner
   69  *      Typecast assert_wait arguments.
   70  *      [93/01/12            danner]
   71  *      Fixes for multiprocessor usage.
   72  *      [92/11/16            jfriedl]
   73  *      Fixed two-for-one bug in evc_wait, per jcb's report.
   74  *      See comments in code.
   75  *      [92/12/15            af]
   76  *      Proper spl typing.
   77  *      [92/11/30            af]
   78  * 
   79  * Revision 2.6  92/08/03  17:36:55  jfriedl
   80  *      removed silly prototypes
   81  *      [92/08/02            jfriedl]
   82  * 
   83  * Revision 2.5  92/05/21  17:13:12  jfriedl
   84  *      Added void type to functions that needed it.
   85  *      [92/05/16            jfriedl]
   86  * 
   87  * Revision 2.4  92/01/03  20:40:02  dbg
   88  *      Made user-safe with a small translation table.
   89  *      This all will be refined at a later time.
   90  *      [91/12/27            af]
   91  * 
   92  * Revision 2.3  91/12/14  14:31:43  jsb
   93  *      Replaced gimmeabreak calls with panics.
   94  * 
   95  * Revision 2.2  91/12/13  14:54:44  jsb
   96  *      Created.
   97  *      [91/11/01            af]
   98  * 
   99  */
  100 /*
  101  *      File:   eventcount.c
  102  *      Author: Alessandro Forin
  103  *      Date:   10/91
  104  *
  105  *      Eventcounters, for user-level drivers synchronization
  106  *
  107  */
  108 
  109 
  110 #include <cpus.h>
  111 
  112 #include <mach/machine.h>
  113 #include <kern/ast.h>
  114 #include <kern/cpu_number.h>
  115 #include <kern/lock.h>
  116 #include <kern/memory.h>
  117 #include <kern/processor.h>
  118 #include <kern/queue.h>
  119 #include <kern/sched_policy.h>
  120 #include <kern/sched_prim.h>
  121 #include <kern/thread.h>
  122 #include <machine/machspl.h>    /* For def'n of splsched() */
  123 
  124 #include <kern/eventcount.h>
  125 
  126 #define MAX_EVCS        10              /* xxx for now */
  127 evc_t   all_eventcounters[MAX_EVCS];
  128 
  129 /*
  130  * Initialization
  131  */
  132 kern_return_t
  133 evc_init(evc_t  ev)
  134 {
  135         int i;
  136 
  137         bzero(ev, sizeof(*ev));
  138 
  139         /* keep track of who is who */
  140         for (i = 0; i < MAX_EVCS; i++)
  141                 if (all_eventcounters[i] == 0) break;
  142         if (i == MAX_EVCS) {
  143 #if 0
  144                 printf("Too many eventcounters\n");
  145 #endif
  146                 return KERN_RESOURCE_SHORTAGE;
  147         }
  148 
  149         all_eventcounters[i] = ev;
  150         ev->ev_id = i;
  151         ev->sanity = ev;
  152         ev->waiting_thread = THREAD_NULL;
  153         simple_lock_init(&ev->lock);
  154 
  155         return KERN_SUCCESS;
  156 }
  157 
  158 /*
  159  * Finalization
  160  */
  161 void
  162 evc_destroy(evc_t       ev)
  163 {
  164         evc_signal(ev);
  165         ev->sanity = 0;
  166         if (all_eventcounters[ev->ev_id] == ev)
  167                 all_eventcounters[ev->ev_id] = 0;
  168         ev->ev_id = -1;
  169 }
  170 
  171 /*
  172  * Just so that we return success, and give
  173  * up the stack while blocked
  174  */
  175 no_return
  176 evc_continue(void)
  177 {
  178         thread_syscall_return(KERN_SUCCESS);
  179         /* NOTREACHED */
  180 }
  181 
  182 /*
  183  * User-trappable
  184  */
  185 kern_return_t evc_wait(natural_t ev_id)
  186 {
  187         spl_t           s;
  188         kern_return_t   ret;
  189         evc_t           ev;
  190 
  191         if ((ev_id >= MAX_EVCS) ||
  192             ((ev = all_eventcounters[ev_id]) == 0) ||
  193             (ev->ev_id != ev_id) || (ev->sanity != ev))
  194                 return KERN_INVALID_ARGUMENT;
  195 
  196         s = splsched();
  197         simple_lock(&ev->lock);
  198                 /*
  199                  * The values assumed by the "count" field are
  200                  * as follows:
  201                  *      0       At initialization time, and with no
  202                  *              waiting thread means no events pending;
  203                  *              with waiting thread means the event
  204                  *              was signalled and the thread not yet resumed
  205                  *      -1      no events, there must be a waiting thread
  206                  *      N>0     no waiting thread means N pending,
  207                  *              with waiting thread N-1 pending.
  208                  *      
  209                  */
  210                 if (ev->count > 0) {
  211                         ev->count--;
  212                         ret = KERN_SUCCESS;
  213                 } else {
  214                         if (ev->waiting_thread == THREAD_NULL) {
  215                                 thread_t thread = current_thread();
  216                                 ev->count--;
  217                                 ev->waiting_thread = thread;
  218                                 thread_will_wait(thread);
  219                                 simple_unlock(&ev->lock);
  220                                 thread_block(evc_continue);
  221                                 /* NOTREACHED */
  222                         }
  223                         ret = KERN_NO_SPACE; /* XX */
  224                 }
  225         simple_unlock(&ev->lock);
  226         splx(s);
  227         return ret;
  228 }
  229 
  230 /*
  231  * User-trappable
  232  */
  233 kern_return_t evc_wait_clear(natural_t ev_id)
  234 {
  235         spl_t           s;
  236         evc_t           ev;
  237 
  238         if ((ev_id >= MAX_EVCS) ||
  239             ((ev = all_eventcounters[ev_id]) == 0) ||
  240             (ev->ev_id != ev_id) || (ev->sanity != ev))
  241                 return KERN_INVALID_ARGUMENT;
  242 
  243         s = splsched();
  244         simple_lock(&ev->lock);
  245 
  246                 /*
  247                  * The values assumed by the "count" field are
  248                  * as follows:
  249                  *      0       At initialization time, and with no
  250                  *              waiting thread means no events pending;
  251                  *              with waiting thread means the event
  252                  *              was signalled and the thread not yet resumed
  253                  *      -1      no events, there must be a waiting thread
  254                  *      N>0     no waiting thread means N pending,
  255                  *              with waiting thread N-1 pending.
  256                  *      
  257                  */
  258                 /*
  259                  *  Note that we always clear count before blocking.
  260                  */
  261                 if (ev->waiting_thread == THREAD_NULL) {
  262                         thread_t thread = current_thread();
  263                         ev->count = -1;
  264                         ev->waiting_thread = thread;
  265                         thread_will_wait(thread);
  266                         simple_unlock(&ev->lock);
  267                         thread_block(evc_continue);
  268                         /* NOTREACHED */
  269                 }
  270 
  271         simple_unlock(&ev->lock);
  272         splx(s);
  273         return KERN_NO_SPACE; /* XX */
  274 }
  275 
  276 /*
  277  * Called exclusively from interrupt context
  278  */
  279 void
  280 evc_signal(evc_t ev)
  281 {
  282     thread_t thread;
  283     spl_t    s;
  284 
  285     if (ev->sanity != ev)
  286       return;
  287 
  288     s = splsched();
  289     simple_lock(&ev->lock);
  290     ev->count++;
  291     thread = ev->waiting_thread;
  292     if (thread != THREAD_NULL)
  293     {
  294         ev->waiting_thread = 0;
  295         thread_go(thread);
  296     }
  297 
  298     simple_unlock(&ev->lock);
  299     splx(s);
  300 }
  301 
  302 /*
  303  * Interrupt an evc_wait.  Called by thread_abort.
  304  * Returns TRUE if the thread was waiting.
  305  *
  306  * Thread is suspended on entry.
  307  *
  308  * (This stuff needs to be fixed.)
  309  */
  310 boolean_t evc_wait_interrupt(thread_t thread)
  311 {
  312     int i;
  313     evc_t ev;
  314     spl_t s;
  315 
  316     if (thread->swap_func != evc_continue)
  317         return FALSE;
  318 
  319     s = splsched();
  320     for (i = 0; i < MAX_EVCS; i++)  {
  321         ev = all_eventcounters[i];
  322         if (ev)  {
  323             simple_lock(&ev->lock);
  324             if (ev->waiting_thread == thread)  
  325               {
  326                 ev->waiting_thread = 0;
  327                 /* Removal of a waiting thread has to bump the count by one */
  328                 ev->count++;
  329               }
  330             simple_unlock(&ev->lock);
  331         }
  332     }
  333     splx(s);
  334 
  335     thread->swap_func = thread_exception_return;
  336     thread_set_syscall_return(thread, KERN_ABORTED);
  337     return TRUE;
  338 }
  339 

Cache object: e61b0c68fc17df876e299fe64ad38fe1


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