|
|
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/IOWorkLoop.h> ! 30: #include <IOKit/IOEventSource.h> ! 31: #include <IOKit/IOInterruptEventSource.h> ! 32: #include <IOKit/IOCommandGate.h> ! 33: #include <IOKit/IOTimeStamp.h> ! 34: ! 35: #define super OSObject ! 36: ! 37: OSDefineMetaClassAndStructors(IOWorkLoop, OSObject) ! 38: ! 39: void IOWorkLoop::launchThreadMain(void *self) ! 40: { ! 41: IOWorkLoop *me = (IOWorkLoop *) self; ! 42: register thread_t mythread = current_thread(); ! 43: ! 44: // Make sure that this thread always has a kernel stack ! 45: stack_privilege(mythread); ! 46: thread_set_cont_arg((int) me); ! 47: threadMainContinuation(); ! 48: } ! 49: ! 50: bool IOWorkLoop::init() ! 51: { ! 52: // The super init and gateLock allocation MUST be done first ! 53: if ( !super::init() || !(gateLock = IORecursiveLockAlloc()) ) ! 54: return false; ! 55: ! 56: if ( !(workToDoLock = IOSimpleLockAlloc()) ) ! 57: return false; ! 58: IOSimpleLockInit(workToDoLock); ! 59: workToDo = false; ! 60: ! 61: controlG = IOCommandGate::commandGate(this, ! 62: (IOCommandGate::Action) &IOWorkLoop::_maintRequest); ! 63: if ( !controlG ) ! 64: return false; ! 65: ! 66: // Point the controlGate at the workLoop. Usually addEventSource ! 67: // does this automatically. The problem is in this case addEventSource ! 68: // uses the control gate and it has to be bootstrapped. ! 69: controlG->setWorkLoop(this); ! 70: if (addEventSource(controlG) != kIOReturnSuccess) ! 71: return false; ! 72: ! 73: workThread = IOCreateThread(launchThreadMain, (void *) this); ! 74: if (!workThread) ! 75: return false; ! 76: ! 77: return true; ! 78: } ! 79: ! 80: IOWorkLoop * ! 81: IOWorkLoop::workLoop() ! 82: { ! 83: IOWorkLoop *me = new IOWorkLoop; ! 84: ! 85: if (me && !me->init()) { ! 86: me->free(); ! 87: return 0; ! 88: } ! 89: ! 90: return me; ! 91: } ! 92: ! 93: void IOWorkLoop::free() ! 94: { ! 95: // Hmm, we didn't even acquire the gate lock succesfully... ! 96: if (!gateLock) { ! 97: super::free(); // ... so just issue a super free ! 98: return; // and return immediately ! 99: } ! 100: ! 101: if (workThread && !onThread()) ! 102: closeGate(); ! 103: ! 104: if (controlG) { ! 105: IOCommandGate *tmpControlG = controlG; ! 106: controlG = 0; ! 107: tmpControlG->release(); ! 108: } ! 109: ! 110: disableAllEventSources(); ! 111: ! 112: // Partial initialisation no thread yet so get rid of event sources. ! 113: if (!workThread && eventChain) { ! 114: IOEventSource *event, *next; ! 115: ! 116: for (event = eventChain; event; event = next) { ! 117: next = event->getNext(); ! 118: event->release(); ! 119: } ! 120: eventChain = 0; ! 121: } ! 122: ! 123: // This is safe as we have disabled all of our interrupt event sources. ! 124: if (workToDoLock) { ! 125: IOSimpleLockFree(workToDoLock); ! 126: workToDoLock = 0; ! 127: } ! 128: ! 129: // ! 130: // Three cases: ! 131: // 1> If I don't have a work thread yet just delete the command gate and ! 132: // free the super class ! 133: // 2> If I have a work loop and I'm on the thread, then one of the event ! 134: // sources must be issueing a free request. In which case we issue a ! 135: // loop restart request and return for the main loop to detect. ! 136: // 3> Client free request. The workToDoLock being set to 0 is a signal ! 137: // for the main thread to wake up and kill itself. ! 138: // ! 139: if (!workThread) { ! 140: IORecursiveLockFree(gateLock); ! 141: super::free(); ! 142: } ! 143: else if (onThread()) ! 144: loopRestart = true; ! 145: else { ! 146: thread_wakeup_one((void *) &workToDo); // Wakeup any sleepers ! 147: openGate(); ! 148: } ! 149: } ! 150: ! 151: IOReturn IOWorkLoop::addEventSource(IOEventSource *newEvent) ! 152: { ! 153: return controlG->runCommand((void *) mAddEvent, (void *) newEvent); ! 154: } ! 155: ! 156: IOReturn IOWorkLoop::removeEventSource(IOEventSource *toRemove) ! 157: { ! 158: return controlG->runCommand((void *) mRemoveEvent, (void *) toRemove); ! 159: } ! 160: ! 161: void IOWorkLoop::enableAllEventSources() const ! 162: { ! 163: IOEventSource *event; ! 164: ! 165: for (event = eventChain; event; event = event->getNext()) ! 166: event->enable(); ! 167: } ! 168: ! 169: void IOWorkLoop::disableAllEventSources() const ! 170: { ! 171: IOEventSource *event; ! 172: ! 173: for (event = eventChain; event; event = event->getNext()) ! 174: event->disable(); ! 175: } ! 176: ! 177: void IOWorkLoop::enableAllInterrupts() const ! 178: { ! 179: IOEventSource *event; ! 180: ! 181: for (event = eventChain; event; event = event->getNext()) ! 182: if (OSDynamicCast(IOInterruptEventSource, event)) ! 183: event->enable(); ! 184: } ! 185: ! 186: void IOWorkLoop::disableAllInterrupts() const ! 187: { ! 188: IOEventSource *event; ! 189: ! 190: for (event = eventChain; event; event = event->getNext()) ! 191: if (OSDynamicCast(IOInterruptEventSource, event)) ! 192: event->disable(); ! 193: } ! 194: ! 195: #if KDEBUG ! 196: #define IOTimeClientS() \ ! 197: do { \ ! 198: IOTimeStampStart(IODBG_WORKLOOP(IOWL_CLIENT), \ ! 199: (unsigned int) this, (unsigned int) event); \ ! 200: } while(0) ! 201: ! 202: #define IOTimeClientE() \ ! 203: do { \ ! 204: IOTimeStampEnd(IODBG_WORKLOOP(IOWL_CLIENT), \ ! 205: (unsigned int) this, (unsigned int) event); \ ! 206: } while(0) ! 207: ! 208: #define IOTimeWorkS() \ ! 209: do { \ ! 210: IOTimeStampStart(IODBG_WORKLOOP(IOWL_WORK), (unsigned int) this); \ ! 211: } while(0) ! 212: ! 213: #define IOTimeWorkE() \ ! 214: do { \ ! 215: IOTimeStampEnd(IODBG_WORKLOOP(IOWL_WORK),(unsigned int) this); \ ! 216: } while(0) ! 217: ! 218: #else /* !KDEBUG */ ! 219: ! 220: #define IOTimeClientS() ! 221: #define IOTimeClientE() ! 222: #define IOTimeWorkS() ! 223: #define IOTimeWorkE() ! 224: ! 225: #endif /* KDEBUG */ ! 226: ! 227: void IOWorkLoop::threadMainContinuation() ! 228: { ! 229: IOWorkLoop* self; ! 230: self = (IOWorkLoop *) thread_get_cont_arg(); ! 231: ! 232: self->threadMain(); ! 233: } ! 234: ! 235: void IOWorkLoop::threadMain() ! 236: { ! 237: loopRestart = false; ! 238: ! 239: for (;;) { ! 240: bool more; ! 241: ! 242: IOTimeWorkS(); ! 243: ! 244: closeGate(); ! 245: if (!workToDoLock) ! 246: goto exitThread; ! 247: ! 248: do { ! 249: IOEventSource *event; ! 250: ! 251: restartLoop: ! 252: ! 253: workToDo = more = false; ! 254: for (event = eventChain; event; event = event->getNext()) { ! 255: ! 256: IOTimeClientS(); ! 257: more |= event->checkForWork(); ! 258: IOTimeClientE(); ! 259: ! 260: if (!workToDoLock) ! 261: goto exitThread; ! 262: else if (loopRestart) { ! 263: loopRestart = false; ! 264: ! 265: goto restartLoop; ! 266: } ! 267: } ! 268: } while (more); ! 269: ! 270: IOTimeWorkE(); ! 271: ! 272: openGate(); ! 273: ! 274: if (workToDoLock) { ! 275: IOInterruptState is; ! 276: ! 277: is = IOSimpleLockLockDisableInterrupt(workToDoLock); ! 278: if (!workToDo) { ! 279: assert_wait((void *) &workToDo, false); ! 280: IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); ! 281: thread_block(&threadMainContinuation); ! 282: /* NOTREACHED */ ! 283: } ! 284: else ! 285: IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); ! 286: } ! 287: ! 288: if (!workToDoLock) { ! 289: IOEventSource *event, *next; ! 290: exitThread: ! 291: ! 292: for (event = eventChain; event; event = next) { ! 293: next = event->getNext(); ! 294: event->release(); ! 295: } ! 296: eventChain = 0; ! 297: ! 298: IORecursiveLockFree(gateLock); ! 299: super::free(); ! 300: IOExitThread(0); ! 301: } ! 302: } ! 303: } ! 304: ! 305: IOThread IOWorkLoop::getThread() const ! 306: { ! 307: return workThread; ! 308: } ! 309: ! 310: bool IOWorkLoop::onThread() const ! 311: { ! 312: return (IOThreadSelf() == workThread); ! 313: } ! 314: ! 315: bool IOWorkLoop::inGate() const ! 316: { ! 317: return IORecursiveLockHaveLock(gateLock); ! 318: } ! 319: ! 320: // Internal APIs used by event sources to control the thread ! 321: void IOWorkLoop::signalWorkAvailable() ! 322: { ! 323: if (workToDoLock) { ! 324: IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock); ! 325: workToDo = true; ! 326: thread_wakeup_one((void *) &workToDo); ! 327: IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); ! 328: } ! 329: } ! 330: ! 331: void IOWorkLoop::openGate() ! 332: { ! 333: IORecursiveLockUnlock(gateLock); ! 334: } ! 335: ! 336: void IOWorkLoop::closeGate() ! 337: { ! 338: IORecursiveLockLock(gateLock); ! 339: } ! 340: ! 341: IOReturn IOWorkLoop::_maintRequest(void *inC, void *inD, void *, void *) ! 342: { ! 343: maintCommandEnum command = (maintCommandEnum) (vm_address_t) inC; ! 344: IOEventSource *inEvent = (IOEventSource *) inD; ! 345: IOReturn res = kIOReturnSuccess; ! 346: ! 347: switch (command) ! 348: { ! 349: case mAddEvent: ! 350: loopRestart = true; ! 351: inEvent->retain(); ! 352: inEvent->setWorkLoop(this); ! 353: inEvent->setNext(0); ! 354: ! 355: if (!eventChain) ! 356: eventChain = inEvent; ! 357: else { ! 358: IOEventSource *event, *next; ! 359: ! 360: for (event = eventChain; (next = event->getNext()); event = next) ! 361: ; ! 362: event->setNext(inEvent); ! 363: } ! 364: break; ! 365: ! 366: case mRemoveEvent: ! 367: if (eventChain == inEvent) ! 368: eventChain = inEvent->getNext(); ! 369: else { ! 370: IOEventSource *event, *next; ! 371: ! 372: event = eventChain; ! 373: while ((next = event->getNext()) && next != inEvent) ! 374: event = next; ! 375: ! 376: if (!next) { ! 377: res = kIOReturnBadArgument; ! 378: break; ! 379: } ! 380: event->setNext(inEvent->getNext()); ! 381: } ! 382: ! 383: inEvent->setWorkLoop(0); ! 384: inEvent->setNext(0); ! 385: inEvent->release(); ! 386: loopRestart = true; ! 387: break; ! 388: ! 389: default: ! 390: return kIOReturnUnsupported; ! 391: } ! 392: ! 393: return res; ! 394: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.