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