Annotation of XNU/iokit/Kernel/IOWorkLoop.cpp, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.