Annotation of XNU/iokit/Kernel/IOWorkLoop.cpp, revision 1.1.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.