Annotation of XNU/iokit/Kernel/IOCommandQueue.cpp, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.