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