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/iokit/Kernel/IOCommandQueue.cpp

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) 1998-2004 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 /*
   29 Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
   30 
   31 HISTORY
   32     1998-7-13   Godfrey van der Linden(gvdl)
   33         Created.
   34 ]*/
   35 #include <IOKit/IOCommandQueue.h>
   36 #include <IOKit/IOWorkLoop.h>
   37 #include <IOKit/IOTimeStamp.h>
   38 
   39 #include <mach/sync_policy.h>
   40 
   41 #define NUM_FIELDS_IN_COMMAND   4
   42 typedef struct commandEntryTag {
   43     void *f[NUM_FIELDS_IN_COMMAND];
   44 } commandEntryT;
   45 
   46 #define super IOEventSource
   47 
   48 OSDefineMetaClassAndStructors(IOCommandQueue, IOEventSource)
   49 
   50 /*[
   51 Instance Methods
   52 
   53 initWithNext:owner:action:size:
   54     - initWithNext: (IOEventSource *) inNext
   55             owner: (id) inOwner
   56             action: (SEL) inAction
   57               size: (int) inSize;
   58 
   59 Primary initialiser for the IOCommandQueue class.  Returns an
   60 IOCommandQueue object that is initialised with the next object in
   61 the chain and the owner and action. On return the signalWorkAvailableIMP
   62 has been cached for this function.
   63 
   64 If the object fails to initialise for some reason then [self free] will
   65 be called and nil will be returned.
   66 
   67 See also: initWithNext:owner:action:(IOEventSource)
   68 ]*/
   69 bool IOCommandQueue::init(OSObject *inOwner,
   70                           IOCommandQueueAction inAction,
   71                           int inSize)
   72 {
   73     if ( !super::init(inOwner, (IOEventSourceAction) inAction) )
   74         return false;
   75     
   76     if (KERN_SUCCESS
   77     !=  semaphore_create(kernel_task, &producerSema, SYNC_POLICY_FIFO, inSize))
   78         return false;
   79 
   80     size = inSize + 1; /* Allocate one more entry than needed */
   81 
   82     queue = (void *)kalloc(size * sizeof(commandEntryT));
   83     if (!queue)
   84         return false;
   85 
   86     producerLock = IOLockAlloc();
   87     if (!producerLock)
   88         return false;
   89 
   90     producerIndex = consumerIndex = 0;
   91 
   92     return true;
   93 }
   94 
   95 IOCommandQueue *
   96 IOCommandQueue::commandQueue(OSObject *inOwner,
   97                              IOCommandQueueAction inAction,
   98                              int inSize)
   99 {
  100     IOCommandQueue *me = new IOCommandQueue;
  101 
  102     if (me && !me->init(inOwner, inAction, inSize)) {
  103         me->free();
  104         return 0;
  105     }
  106 
  107     return me;
  108 }
  109 
  110 /*[
  111 free
  112     - free
  113 
  114 Mandatory free of the object independent of the current retain count.
  115 Returns nil.
  116 ]*/
  117 void IOCommandQueue::free()
  118 {
  119     if (queue)
  120         kfree(queue, size * sizeof(commandEntryT));
  121     if (producerSema)
  122         semaphore_destroy(kernel_task, producerSema);
  123     if (producerLock)
  124         IOLockFree(producerLock);
  125 
  126     super::free();
  127 }
  128 
  129 #if NUM_FIELDS_IN_COMMAND != 4
  130 #error IOCommandQueue::checkForWork needs to be updated for new command size
  131 #endif
  132 
  133 bool IOCommandQueue::checkForWork()
  134 {
  135     void *field0, *field1, *field2, *field3;
  136 
  137     if (!enabled || consumerIndex == producerIndex)
  138         return false;
  139 
  140     {
  141         commandEntryT *q = (commandEntryT *) queue;
  142         int localIndex = consumerIndex;
  143 
  144         field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1];
  145         field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3];
  146         semaphore_signal(producerSema);
  147     }
  148 
  149     if (++consumerIndex >= size)
  150         consumerIndex = 0;
  151 
  152     IOTimeStampConstant(IODBG_CMDQ(IOCMDQ_ACTION),
  153                         (unsigned int) action, (unsigned int) owner);
  154 
  155     (*(IOCommandQueueAction) action)(owner, field0, field1, field2, field3);
  156 
  157     return (consumerIndex != producerIndex);
  158 }
  159 
  160 /*[
  161 enqueueSleep:command:
  162     - (kern_return_t) enqueueSleepRaw: (BOOL) gotoSleep
  163                                field0: (void *) field0 field1: (void *) field1
  164                                field2: (void *) field2 field3: (void *) field3;
  165 
  166 Key method that enqueues the four input fields onto the command queue
  167 and calls signalWorkAvailable to indicate that work is available to the
  168 consumer.  This routine is safe against multiple threaded producers.
  169 
  170 A family of convenience functions have been provided to assist with the
  171 enqueueing of an method selector and an integer tag.  This relies on the
  172 IODevice rawCommandOccurred... command to forward on the requests.
  173 
  174 See also: signalWorkAvailable, checkForWork
  175 ]*/
  176 #if NUM_FIELDS_IN_COMMAND != 4
  177 #error IOCommandQueue::enqueueCommand needs to be updated
  178 #endif
  179 
  180 kern_return_t
  181 IOCommandQueue::enqueueCommand(bool gotoSleep,
  182                                void *field0, void *field1,
  183                                void *field2, void *field3)
  184 {
  185     kern_return_t rtn = KERN_SUCCESS;
  186     int retry;
  187 
  188     /* Make sure there is room in the queue before doing anything else */
  189 
  190     if (gotoSleep) {
  191         retry = 0;
  192         do
  193         rtn = semaphore_wait(producerSema);
  194         while(     (KERN_SUCCESS != rtn)
  195                 && (KERN_OPERATION_TIMED_OUT != rtn)
  196                 && (KERN_SEMAPHORE_DESTROYED != rtn)
  197                 && (KERN_TERMINATED != rtn)
  198                 && ((retry++) < 4));
  199     } else
  200         rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO);
  201 
  202     if (KERN_SUCCESS != rtn)
  203         return rtn;
  204 
  205     /* Block other producers */
  206     IOTakeLock(producerLock);
  207 
  208     /*
  209      * Make sure that we update the current producer entry before we
  210      * increment the producer pointer.  This avoids a nasty race as the
  211      * as the test for work is producerIndex != consumerIndex and a signal.
  212      */
  213     {
  214         commandEntryT *q = (commandEntryT *) queue;
  215         int localIndex = producerIndex;
  216 
  217         q[localIndex].f[0] = field0; q[localIndex].f[1] = field1;
  218         q[localIndex].f[2] = field2; q[localIndex].f[3] = field3;
  219     }
  220     if (++producerIndex >= size)
  221         producerIndex = 0;
  222 
  223     /* Clear to allow other producers to go now */
  224     IOUnlock(producerLock);
  225 
  226     /*
  227      * Right we have created some new work, we had better make sure that
  228      * we notify the work loop that it has to test producerIndex.
  229      */
  230     signalWorkAvailable();
  231     return rtn;
  232 }
  233 
  234 int IOCommandQueue::performAndFlush(OSObject *target,
  235                                     IOCommandQueueAction inAction)
  236 {
  237     int numEntries;
  238     kern_return_t rtn;
  239 
  240     // Set the defaults if necessary
  241     if (!target)
  242         target = owner;
  243     if (!inAction)
  244         inAction = (IOCommandQueueAction) action;
  245 
  246     // Lock out the producers first
  247     do {
  248         rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO);
  249     } while (rtn == KERN_SUCCESS);
  250 
  251     // now step over all remaining entries in the command queue
  252     for (numEntries = 0; consumerIndex != producerIndex; ) {
  253         void *field0, *field1, *field2, *field3;
  254 
  255         {
  256             commandEntryT *q = (commandEntryT *) queue;
  257             int localIndex = consumerIndex;
  258 
  259             field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1];
  260             field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3];
  261         }
  262 
  263         if (++consumerIndex >= size)
  264             consumerIndex = 0;
  265 
  266         (*inAction)(target, field0, field1, field2, field3);
  267     }
  268 
  269     // finally refill the producer semaphore to size - 1
  270     for (int i = 1; i < size; i++)
  271         semaphore_signal(producerSema);
  272 
  273     return numEntries;
  274 }

Cache object: b7285ebbe22185b2a4059bb62f0cd681


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