|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.