X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/378393581903b274cb7a4d18e0d978071a6b592d..eb6b6ca394357805f2bdba989abae309f718b4d8:/iokit/Kernel/IOCommandQueue.cpp diff --git a/iokit/Kernel/IOCommandQueue.cpp b/iokit/Kernel/IOCommandQueue.cpp index 328c96190..2623d063d 100644 --- a/iokit/Kernel/IOCommandQueue.cpp +++ b/iokit/Kernel/IOCommandQueue.cpp @@ -1,40 +1,58 @@ /* - * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998-2010 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ -/* -Copyright (c) 1998 Apple Computer, Inc. All rights reserved. -HISTORY - 1998-7-13 Godfrey van der Linden(gvdl) - Created. -]*/ +#if !defined(__LP64__) + #include #include #include +#include #include -#define NUM_FIELDS_IN_COMMAND 4 +#if IOKITSTATS + +#define IOStatisticsInitializeCounter() \ + IOStatistics::setCounterType(reserved->counter, kIOStatisticsCommandQueueCounter) + +#define IOStatisticsActionCall() \ + IOStatistics::countCommandQueueActionCall(reserved->counter) + +#else + +#define IOStatisticsInitializeCounter() +#define IOStatisticsActionCall() + +#endif /* IOKITSTATS */ + +#define NUM_FIELDS_IN_COMMAND 4 typedef struct commandEntryTag { - void *f[NUM_FIELDS_IN_COMMAND]; + void *f[NUM_FIELDS_IN_COMMAND]; } commandEntryT; #define super IOEventSource @@ -42,227 +60,260 @@ typedef struct commandEntryTag { OSDefineMetaClassAndStructors(IOCommandQueue, IOEventSource) /*[ -Instance Methods - -initWithNext:owner:action:size: - - initWithNext: (IOEventSource *) inNext - owner: (id) inOwner - action: (SEL) inAction - size: (int) inSize; - -Primary initialiser for the IOCommandQueue class. Returns an -IOCommandQueue object that is initialised with the next object in -the chain and the owner and action. On return the signalWorkAvailableIMP -has been cached for this function. - -If the object fails to initialise for some reason then [self free] will -be called and nil will be returned. - -See also: initWithNext:owner:action:(IOEventSource) -]*/ -bool IOCommandQueue::init(OSObject *inOwner, - IOCommandQueueAction inAction, - int inSize) + * Instance Methods + * + * initWithNext:owner:action:size: + * - initWithNext: (IOEventSource *) inNext + * owner: (id) inOwner + * action: (SEL) inAction + * size: (int) inSize; + * + * Primary initialiser for the IOCommandQueue class. Returns an + * IOCommandQueue object that is initialised with the next object in + * the chain and the owner and action. On return the signalWorkAvailableIMP + * has been cached for this function. + * + * If the object fails to initialise for some reason then [self free] will + * be called and nil will be returned. + * + * See also: initWithNext:owner:action:(IOEventSource) + * ]*/ +bool +IOCommandQueue::init(OSObject *inOwner, + IOCommandQueueAction inAction, + int inSize) { - if ( !super::init(inOwner, (IOEventSourceAction) inAction) ) - return false; - - if (KERN_SUCCESS - != semaphore_create(kernel_task, &producerSema, SYNC_POLICY_FIFO, inSize)) - return false; + if (!super::init(inOwner, (IOEventSourceAction) inAction)) { + return false; + } + + if (KERN_SUCCESS + != semaphore_create(kernel_task, &producerSema, SYNC_POLICY_FIFO, inSize)) { + return false; + } - size = inSize + 1; /* Allocate one more entry than needed */ + size = inSize + 1; /* Allocate one more entry than needed */ - queue = (void *)kalloc(size * sizeof(commandEntryT)); - if (!queue) - return false; + queue = (void *)kalloc(size * sizeof(commandEntryT)); + if (!queue) { + return false; + } - producerLock = IOLockAlloc(); - if (!producerLock) - return false; + producerLock = IOLockAlloc(); + if (!producerLock) { + return false; + } - producerIndex = consumerIndex = 0; + producerIndex = consumerIndex = 0; - return true; + IOStatisticsInitializeCounter(); + + return true; } IOCommandQueue * IOCommandQueue::commandQueue(OSObject *inOwner, - IOCommandQueueAction inAction, - int inSize) + IOCommandQueueAction inAction, + int inSize) { - IOCommandQueue *me = new IOCommandQueue; + IOCommandQueue *me = new IOCommandQueue; - if (me && !me->init(inOwner, inAction, inSize)) { - me->free(); - return 0; - } + if (me && !me->init(inOwner, inAction, inSize)) { + me->free(); + return NULL; + } - return me; + return me; } /*[ -free - - free - -Mandatory free of the object independent of the current retain count. -Returns nil. -]*/ -void IOCommandQueue::free() + * free + * - free + * + * Mandatory free of the object independent of the current retain count. + * Returns nil. + * ]*/ +void +IOCommandQueue::free() { - if (queue) - kfree(queue, size * sizeof(commandEntryT)); - if (producerSema) - semaphore_destroy(kernel_task, producerSema); - if (producerLock) - IOLockFree(producerLock); - - super::free(); + if (queue) { + kfree(queue, size * sizeof(commandEntryT)); + } + if (producerSema) { + semaphore_destroy(kernel_task, producerSema); + } + if (producerLock) { + IOLockFree(producerLock); + } + + super::free(); } #if NUM_FIELDS_IN_COMMAND != 4 #error IOCommandQueue::checkForWork needs to be updated for new command size #endif -bool IOCommandQueue::checkForWork() +bool +IOCommandQueue::checkForWork() { - void *field0, *field1, *field2, *field3; + void *field0, *field1, *field2, *field3; + bool trace = (gIOKitTrace & kIOTraceCommandGates) ? true : false; + + if (!enabled || consumerIndex == producerIndex) { + return false; + } - if (!enabled || consumerIndex == producerIndex) - return false; + { + commandEntryT *q = (commandEntryT *) queue; + int localIndex = consumerIndex; - { - commandEntryT *q = (commandEntryT *) queue; - int localIndex = consumerIndex; + field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1]; + field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3]; + semaphore_signal(producerSema); + } - field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1]; - field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3]; - semaphore_signal(producerSema); - } + if (++consumerIndex >= size) { + consumerIndex = 0; + } - if (++consumerIndex >= size) - consumerIndex = 0; + if (trace) { + IOTimeStampStartConstant(IODBG_CMDQ(IOCMDQ_ACTION), + VM_KERNEL_ADDRHIDE(action), VM_KERNEL_ADDRHIDE(owner)); + } - IOTimeStampConstant(IODBG_CMDQ(IOCMDQ_ACTION), - (unsigned int) action, (unsigned int) owner); + IOStatisticsActionCall(); + (*(IOCommandQueueAction) action)(owner, field0, field1, field2, field3); - (*(IOCommandQueueAction) action)(owner, field0, field1, field2, field3); + if (trace) { + IOTimeStampEndConstant(IODBG_CMDQ(IOCMDQ_ACTION), + VM_KERNEL_ADDRHIDE(action), VM_KERNEL_ADDRHIDE(owner)); + } - return (consumerIndex != producerIndex); + return consumerIndex != producerIndex; } /*[ -enqueueSleep:command: - - (kern_return_t) enqueueSleepRaw: (BOOL) gotoSleep - field0: (void *) field0 field1: (void *) field1 - field2: (void *) field2 field3: (void *) field3; - -Key method that enqueues the four input fields onto the command queue -and calls signalWorkAvailable to indicate that work is available to the -consumer. This routine is safe against multiple threaded producers. - -A family of convenience functions have been provided to assist with the -enqueueing of an method selector and an integer tag. This relies on the -IODevice rawCommandOccurred... command to forward on the requests. - -See also: signalWorkAvailable, checkForWork -]*/ + * enqueueSleep:command: + * - (kern_return_t) enqueueSleepRaw: (BOOL) gotoSleep + * field0: (void *) field0 field1: (void *) field1 + * field2: (void *) field2 field3: (void *) field3; + * + * Key method that enqueues the four input fields onto the command queue + * and calls signalWorkAvailable to indicate that work is available to the + * consumer. This routine is safe against multiple threaded producers. + * + * A family of convenience functions have been provided to assist with the + * enqueueing of an method selector and an integer tag. This relies on the + * IODevice rawCommandOccurred... command to forward on the requests. + * + * See also: signalWorkAvailable, checkForWork + * ]*/ #if NUM_FIELDS_IN_COMMAND != 4 #error IOCommandQueue::enqueueCommand needs to be updated #endif kern_return_t IOCommandQueue::enqueueCommand(bool gotoSleep, - void *field0, void *field1, - void *field2, void *field3) + void *field0, void *field1, + void *field2, void *field3) { - kern_return_t rtn = KERN_SUCCESS; - int retry; - - /* Make sure there is room in the queue before doing anything else */ - - if (gotoSleep) { - retry = 0; - do - rtn = semaphore_wait(producerSema); - while( (KERN_SUCCESS != rtn) - && (KERN_OPERATION_TIMED_OUT != rtn) - && (KERN_SEMAPHORE_DESTROYED != rtn) - && (KERN_TERMINATED != rtn) - && ((retry++) < 4)); - } else - rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO); - - if (KERN_SUCCESS != rtn) - return rtn; - - /* Block other producers */ - IOTakeLock(producerLock); - - /* - * Make sure that we update the current producer entry before we - * increment the producer pointer. This avoids a nasty race as the - * as the test for work is producerIndex != consumerIndex and a signal. - */ - { - commandEntryT *q = (commandEntryT *) queue; - int localIndex = producerIndex; - - q[localIndex].f[0] = field0; q[localIndex].f[1] = field1; - q[localIndex].f[2] = field2; q[localIndex].f[3] = field3; - } - if (++producerIndex >= size) - producerIndex = 0; - - /* Clear to allow other producers to go now */ - IOUnlock(producerLock); - - /* - * Right we have created some new work, we had better make sure that - * we notify the work loop that it has to test producerIndex. - */ - signalWorkAvailable(); - return rtn; + kern_return_t rtn = KERN_SUCCESS; + int retry; + + /* Make sure there is room in the queue before doing anything else */ + + if (gotoSleep) { + retry = 0; + do{ + rtn = semaphore_wait(producerSema); + } while ((KERN_SUCCESS != rtn) + && (KERN_OPERATION_TIMED_OUT != rtn) + && (KERN_SEMAPHORE_DESTROYED != rtn) + && (KERN_TERMINATED != rtn) + && ((retry++) < 4)); + } else { + rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO); + } + + if (KERN_SUCCESS != rtn) { + return rtn; + } + + /* Block other producers */ + IOTakeLock(producerLock); + + /* + * Make sure that we update the current producer entry before we + * increment the producer pointer. This avoids a nasty race as the + * test for work is producerIndex != consumerIndex and a signal. + */ + { + commandEntryT *q = (commandEntryT *) queue; + int localIndex = producerIndex; + + q[localIndex].f[0] = field0; q[localIndex].f[1] = field1; + q[localIndex].f[2] = field2; q[localIndex].f[3] = field3; + } + if (++producerIndex >= size) { + producerIndex = 0; + } + + /* Clear to allow other producers to go now */ + IOUnlock(producerLock); + + /* + * Right we have created some new work, we had better make sure that + * we notify the work loop that it has to test producerIndex. + */ + signalWorkAvailable(); + return rtn; } -int IOCommandQueue::performAndFlush(OSObject *target, - IOCommandQueueAction inAction) +int +IOCommandQueue::performAndFlush(OSObject *target, + IOCommandQueueAction inAction) { - int numEntries; - kern_return_t rtn; - - // Set the defaults if necessary - if (!target) - target = owner; - if (!inAction) - inAction = (IOCommandQueueAction) action; - - // Lock out the producers first - do { - rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO); - } while (rtn == KERN_SUCCESS); - - // now step over all remaining entries in the command queue - for (numEntries = 0; consumerIndex != producerIndex; ) { - void *field0, *field1, *field2, *field3; - - { - commandEntryT *q = (commandEntryT *) queue; - int localIndex = consumerIndex; - - field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1]; - field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3]; - } - - if (++consumerIndex >= size) - consumerIndex = 0; - - (*inAction)(target, field0, field1, field2, field3); - } - - // finally refill the producer semaphore to size - 1 - for (int i = 1; i < size; i++) - semaphore_signal(producerSema); - - return numEntries; + int numEntries; + kern_return_t rtn; + + // Set the defaults if necessary + if (!target) { + target = owner; + } + if (!inAction) { + inAction = (IOCommandQueueAction) action; + } + + // Lock out the producers first + do { + rtn = semaphore_timedwait(producerSema, MACH_TIMESPEC_ZERO); + } while (rtn == KERN_SUCCESS); + + // now step over all remaining entries in the command queue + for (numEntries = 0; consumerIndex != producerIndex;) { + void *field0, *field1, *field2, *field3; + + { + commandEntryT *q = (commandEntryT *) queue; + int localIndex = consumerIndex; + + field0 = q[localIndex].f[0]; field1 = q[localIndex].f[1]; + field2 = q[localIndex].f[2]; field3 = q[localIndex].f[3]; + } + + if (++consumerIndex >= size) { + consumerIndex = 0; + } + + (*inAction)(target, field0, field1, field2, field3); + } + + // finally refill the producer semaphore to size - 1 + for (int i = 1; i < size; i++) { + semaphore_signal(producerSema); + } + + return numEntries; } + +#endif /* !defined(__LP64__) */