1/* 2 * Copyright (c) 1998-2000, 2009-2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28#include <libkern/OSDebug.h> 29 30#include <IOKit/IOCommandGate.h> 31#include <IOKit/IOWorkLoop.h> 32#include <IOKit/IOReturn.h> 33#include <IOKit/IOTimeStamp.h> 34#include <IOKit/IOKitDebug.h> 35 36#define super IOEventSource 37 38OSDefineMetaClassAndStructors(IOCommandGate, IOEventSource) 39#if __LP64__ 40OSMetaClassDefineReservedUnused(IOCommandGate, 0); 41#else 42OSMetaClassDefineReservedUsed(IOCommandGate, 0); 43#endif 44OSMetaClassDefineReservedUnused(IOCommandGate, 1); 45OSMetaClassDefineReservedUnused(IOCommandGate, 2); 46OSMetaClassDefineReservedUnused(IOCommandGate, 3); 47OSMetaClassDefineReservedUnused(IOCommandGate, 4); 48OSMetaClassDefineReservedUnused(IOCommandGate, 5); 49OSMetaClassDefineReservedUnused(IOCommandGate, 6); 50OSMetaClassDefineReservedUnused(IOCommandGate, 7); 51 52#if IOKITSTATS 53 54#define IOStatisticsInitializeCounter() \ 55do { \ 56 IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsCommandGateCounter); \ 57} while (0) 58 59#define IOStatisticsActionCall() \ 60do { \ 61 IOStatistics::countCommandGateActionCall(IOEventSource::reserved->counter); \ 62} while (0) 63 64#else 65 66#define IOStatisticsInitializeCounter() 67#define IOStatisticsActionCall() 68 69#endif /* IOKITSTATS */ 70 71bool IOCommandGate::init(OSObject *inOwner, Action inAction) 72{ 73 bool res = super::init(inOwner, (IOEventSource::Action) inAction); 74 if (res) { 75 IOStatisticsInitializeCounter(); 76 } 77 78 return res; 79} 80 81IOCommandGate * 82IOCommandGate::commandGate(OSObject *inOwner, Action inAction) 83{ 84 IOCommandGate *me = new IOCommandGate; 85 86 if (me && !me->init(inOwner, inAction)) { 87 me->release(); 88 return 0; 89 } 90 91 return me; 92} 93 94/* virtual */ void IOCommandGate::disable() 95{ 96 if (workLoop && !workLoop->inGate()) 97 OSReportWithBacktrace("IOCommandGate::disable() called when not gated"); 98 99 super::disable(); 100} 101 102/* virtual */ void IOCommandGate::enable() 103{ 104 if (workLoop) { 105 closeGate(); 106 super::enable(); 107 wakeupGate(&enabled, /* oneThread */ false); // Unblock sleeping threads 108 openGate(); 109 } 110} 111 112/* virtual */ void IOCommandGate::free() 113{ 114 setWorkLoop(0); 115 super::free(); 116} 117 118/* virtual */ void IOCommandGate::setWorkLoop(IOWorkLoop *inWorkLoop) 119{ 120 uintptr_t *sleepersP = (uintptr_t *) &reserved; 121 if (!inWorkLoop && workLoop) { // tearing down 122 closeGate(); 123 *sleepersP |= 1; 124 while (*sleepersP >> 1) { 125 thread_wakeup_with_result(&enabled, THREAD_INTERRUPTED); 126 sleepGate(sleepersP, THREAD_UNINT); 127 } 128 *sleepersP = 0; 129 openGate(); 130 } 131 else 132 133 super::setWorkLoop(inWorkLoop); 134} 135 136IOReturn IOCommandGate::runCommand(void *arg0, void *arg1, 137 void *arg2, void *arg3) 138{ 139 return runAction((Action) action, arg0, arg1, arg2, arg3); 140} 141 142IOReturn IOCommandGate::attemptCommand(void *arg0, void *arg1, 143 void *arg2, void *arg3) 144{ 145 return attemptAction((Action) action, arg0, arg1, arg2, arg3); 146} 147 148IOReturn IOCommandGate::runAction(Action inAction, 149 void *arg0, void *arg1, 150 void *arg2, void *arg3) 151{ 152 if (!inAction) 153 return kIOReturnBadArgument; 154 155 // closeGate is recursive needn't worry if we already hold the lock. 156 closeGate(); 157 158 // If the command gate is disabled and we aren't on the workloop thread 159 // itself then sleep until we get enabled. 160 IOReturn res; 161 if (!workLoop->onThread()) { 162 while (!enabled) { 163 uintptr_t *sleepersP = (uintptr_t *) &reserved; 164 165 *sleepersP += 2; 166 IOReturn res = sleepGate(&enabled, THREAD_ABORTSAFE); 167 *sleepersP -= 2; 168 169 bool wakeupTearDown = (*sleepersP & 1); 170 if (res || wakeupTearDown) { 171 openGate(); 172 173 if (wakeupTearDown) 174 commandWakeup(sleepersP); // No further resources used 175 176 return kIOReturnAborted; 177 } 178 } 179 } 180 181 bool trace = ( gIOKitTrace & kIOTraceCommandGates ) ? true : false; 182 183 if (trace) 184 IOTimeStampStartConstant(IODBG_CMDQ(IOCMDQ_ACTION), 185 VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner); 186 187 IOStatisticsActionCall(); 188 189 // Must be gated and on the work loop or enabled 190 res = (*inAction)(owner, arg0, arg1, arg2, arg3); 191 192 if (trace) 193 IOTimeStampEndConstant(IODBG_CMDQ(IOCMDQ_ACTION), 194 VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner); 195 196 openGate(); 197 198 return res; 199} 200 201IOReturn IOCommandGate::attemptAction(Action inAction, 202 void *arg0, void *arg1, 203 void *arg2, void *arg3) 204{ 205 IOReturn res; 206 207 if (!inAction) 208 return kIOReturnBadArgument; 209 210 // Try to close the gate if can't get return immediately. 211 if (!tryCloseGate()) 212 return kIOReturnCannotLock; 213 214 // If the command gate is disabled then sleep until we get a wakeup 215 if (!workLoop->onThread() && !enabled) 216 res = kIOReturnNotPermitted; 217 else { 218 219 bool trace = ( gIOKitTrace & kIOTraceCommandGates ) ? true : false; 220 221 if (trace) 222 IOTimeStampStartConstant(IODBG_CMDQ(IOCMDQ_ACTION), 223 VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner); 224 225 IOStatisticsActionCall(); 226 227 res = (*inAction)(owner, arg0, arg1, arg2, arg3); 228 229 if (trace) 230 IOTimeStampEndConstant(IODBG_CMDQ(IOCMDQ_ACTION), 231 VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner); 232 } 233 234 openGate(); 235 236 return res; 237} 238 239IOReturn IOCommandGate::commandSleep(void *event, UInt32 interruptible) 240{ 241 if (!workLoop->inGate()) 242 return kIOReturnNotPermitted; 243 244 return sleepGate(event, interruptible); 245} 246 247IOReturn IOCommandGate::commandSleep(void *event, AbsoluteTime deadline, UInt32 interruptible) 248{ 249 if (!workLoop->inGate()) 250 return kIOReturnNotPermitted; 251 252 return sleepGate(event, deadline, interruptible); 253} 254 255void IOCommandGate::commandWakeup(void *event, bool oneThread) 256{ 257 wakeupGate(event, oneThread); 258} 259