Annotation of XNU/iokit/Kernel/IOCommandQueue.cpp, revision 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.