The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/iokit/Kernel/IOWorkLoop.cpp

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1998-2007 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 /*
   29 Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
   30 
   31 HISTORY
   32     1998-7-13   Godfrey van der Linden(gvdl)
   33         Created.
   34 */
   35 #include <IOKit/IOWorkLoop.h>
   36 #include <IOKit/IOEventSource.h>
   37 #include <IOKit/IOInterruptEventSource.h>
   38 #include <IOKit/IOCommandGate.h>
   39 #include <IOKit/IOTimeStamp.h>
   40 #include <libkern/OSDebug.h>
   41 
   42 #define super OSObject
   43 
   44 OSDefineMetaClassAndStructors(IOWorkLoop, OSObject);
   45 
   46 // Block of unused functions intended for future use
   47 OSMetaClassDefineReservedUsed(IOWorkLoop, 0);
   48 OSMetaClassDefineReservedUsed(IOWorkLoop, 1);
   49 
   50 OSMetaClassDefineReservedUnused(IOWorkLoop, 2);
   51 OSMetaClassDefineReservedUnused(IOWorkLoop, 3);
   52 OSMetaClassDefineReservedUnused(IOWorkLoop, 4);
   53 OSMetaClassDefineReservedUnused(IOWorkLoop, 5);
   54 OSMetaClassDefineReservedUnused(IOWorkLoop, 6);
   55 OSMetaClassDefineReservedUnused(IOWorkLoop, 7);
   56 
   57 enum IOWorkLoopState { kLoopRestart = 0x1, kLoopTerminate = 0x2 };
   58 #ifdef __ppc__
   59 static inline void SETP(void *addr, unsigned int flag)
   60     { unsigned int *num = (unsigned int *) addr; *num |= flag; }
   61 static inline void CLRP(void *addr, unsigned int flag)
   62     { unsigned int *num = (unsigned int *) addr; *num &= ~flag; }
   63 static inline bool ISSETP(void *addr, unsigned int flag)
   64     { unsigned int *num = (unsigned int *) addr; return (*num & flag) != 0; }
   65 #else
   66 static inline void SETP(void *addr, unsigned int flag)
   67     { unsigned char *num = (unsigned char *) addr; *num |= flag; }
   68 static inline void CLRP(void *addr, unsigned int flag)
   69     { unsigned char *num = (unsigned char *) addr; *num &= ~flag; }
   70 static inline bool ISSETP(void *addr, unsigned int flag)
   71     { unsigned char *num = (unsigned char *) addr; return (*num & flag) != 0; }
   72 #endif
   73 
   74 #define fFlags loopRestart
   75 
   76 bool IOWorkLoop::init()
   77 {
   78     // The super init and gateLock allocation MUST be done first
   79     if ( !super::init() )
   80         return false;
   81         
   82     if ( gateLock == NULL ) {
   83         if ( !( gateLock = IORecursiveLockAlloc()) )
   84             return false;
   85     }
   86         
   87     if ( workToDoLock == NULL ) {
   88         if ( !(workToDoLock = IOSimpleLockAlloc()) )
   89             return false;
   90         IOSimpleLockInit(workToDoLock);
   91         workToDo = false;
   92     }
   93 
   94     if ( controlG == NULL ) {
   95         controlG = IOCommandGate::commandGate(
   96             this,
   97             OSMemberFunctionCast(
   98                 IOCommandGate::Action,
   99                 this,
  100                 &IOWorkLoop::_maintRequest));
  101 
  102         if ( !controlG )
  103             return false;
  104         // Point the controlGate at the workLoop.  Usually addEventSource
  105         // does this automatically.  The problem is in this case addEventSource
  106         // uses the control gate and it has to be bootstrapped.
  107         controlG->setWorkLoop(this);
  108         if (addEventSource(controlG) != kIOReturnSuccess)
  109             return false;
  110     }
  111 
  112     if ( workThread == NULL ) {
  113         IOThreadFunc cptr = OSMemberFunctionCast(
  114             IOThreadFunc,
  115             this,
  116             &IOWorkLoop::threadMain);
  117         workThread = IOCreateThread(cptr, this);
  118         if (!workThread)
  119             return false;
  120     }
  121 
  122     return true;
  123 }
  124 
  125 IOWorkLoop *
  126 IOWorkLoop::workLoop()
  127 {
  128     return IOWorkLoop::workLoopWithOptions(0);
  129 }
  130 
  131 IOWorkLoop *
  132 IOWorkLoop::workLoopWithOptions(IOOptionBits options)
  133 {
  134     IOWorkLoop *me = new IOWorkLoop;
  135 
  136     if (me && options) {
  137         me->reserved = IONew(ExpansionData, 1);
  138         if (!me->reserved) {
  139             me->release();
  140             return 0;
  141         }
  142         me->reserved->options = options;
  143     }
  144 
  145     if (me && !me->init()) {
  146         me->release();
  147         return 0;
  148     }
  149 
  150     return me;
  151 }
  152 
  153 // Free is called twice:
  154 // First when the atomic retainCount transitions from 1 -> 0
  155 // Secondly when the work loop itself is commiting hari kari
  156 // Hence the each leg of the free must be single threaded.
  157 void IOWorkLoop::free()
  158 {
  159     if (workThread) {
  160         IOInterruptState is;
  161 
  162         // If we are here then we must be trying to shut down this work loop
  163         // in this case disable all of the event source, mark the loop
  164         // as terminating and wakeup the work thread itself and return
  165         // Note: we hold the gate across the entire operation mainly for the 
  166         // benefit of our event sources so we can disable them cleanly.
  167         closeGate();
  168 
  169         disableAllEventSources();
  170 
  171         is = IOSimpleLockLockDisableInterrupt(workToDoLock);
  172         SETP(&fFlags, kLoopTerminate);
  173         thread_wakeup_one((void *) &workToDo);
  174         IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
  175 
  176         openGate();
  177     }
  178     else /* !workThread */ {
  179         IOEventSource *event, *next;
  180 
  181         for (event = eventChain; event; event = next) {
  182             next = event->getNext();
  183             event->setWorkLoop(0);
  184             event->setNext(0);
  185             event->release();
  186         }
  187         eventChain = 0;
  188 
  189         // Either we have a partial initialization to clean up
  190         // or the workThread itself is performing hari-kari.
  191         // Either way clean up all of our resources and return.
  192         
  193         if (controlG) {
  194             controlG->release();
  195             controlG = 0;
  196         }
  197 
  198         if (workToDoLock) {
  199             IOSimpleLockFree(workToDoLock);
  200             workToDoLock = 0;
  201         }
  202 
  203         if (gateLock) {
  204             IORecursiveLockFree(gateLock);
  205             gateLock = 0;
  206         }
  207         if (reserved) {
  208             IODelete(reserved, ExpansionData, 1);
  209             reserved = 0;
  210         }
  211 
  212         super::free();
  213     }
  214 }
  215 
  216 IOReturn IOWorkLoop::addEventSource(IOEventSource *newEvent)
  217 {
  218     return controlG->runCommand((void *) mAddEvent, (void *) newEvent);
  219 }
  220     
  221 IOReturn IOWorkLoop::removeEventSource(IOEventSource *toRemove)
  222 {
  223     return controlG->runCommand((void *) mRemoveEvent, (void *) toRemove);
  224 }
  225 
  226 void IOWorkLoop::enableAllEventSources() const
  227 {
  228     IOEventSource *event;
  229 
  230     for (event = eventChain; event; event = event->getNext())
  231         event->enable();
  232 }
  233 
  234 void IOWorkLoop::disableAllEventSources() const
  235 {
  236     IOEventSource *event;
  237 
  238     for (event = eventChain; event; event = event->getNext())
  239         if (event != controlG)  // Don't disable the control gate
  240             event->disable();
  241 }
  242 
  243 void IOWorkLoop::enableAllInterrupts() const
  244 {
  245     IOEventSource *event;
  246 
  247     for (event = eventChain; event; event = event->getNext())
  248         if (OSDynamicCast(IOInterruptEventSource, event))
  249             event->enable();
  250 }
  251 
  252 void IOWorkLoop::disableAllInterrupts() const
  253 {
  254     IOEventSource *event;
  255 
  256     for (event = eventChain; event; event = event->getNext())
  257         if (OSDynamicCast(IOInterruptEventSource, event))
  258             event->disable();
  259 }
  260 
  261 #if KDEBUG
  262 #define IOTimeClientS()                                                 \
  263 do {                                                                    \
  264     IOTimeStampStart(IODBG_WORKLOOP(IOWL_CLIENT),                       \
  265                      (unsigned int) this, (unsigned int) event);        \
  266 } while(0)
  267 
  268 #define IOTimeClientE()                                                 \
  269 do {                                                                    \
  270     IOTimeStampEnd(IODBG_WORKLOOP(IOWL_CLIENT),                         \
  271                    (unsigned int) this, (unsigned int) event);          \
  272 } while(0)
  273 
  274 #define IOTimeWorkS()                                                   \
  275 do {                                                                    \
  276     IOTimeStampStart(IODBG_WORKLOOP(IOWL_WORK), (unsigned int) this);   \
  277 } while(0)
  278 
  279 #define IOTimeWorkE()                                                   \
  280 do {                                                                    \
  281     IOTimeStampEnd(IODBG_WORKLOOP(IOWL_WORK),(unsigned int) this);      \
  282 } while(0)
  283 
  284 #else /* !KDEBUG */
  285 
  286 #define IOTimeClientS()
  287 #define IOTimeClientE()
  288 #define IOTimeWorkS()
  289 #define IOTimeWorkE()
  290 
  291 #endif /* KDEBUG */
  292 
  293 /* virtual */ bool IOWorkLoop::runEventSources()
  294 {
  295     bool res = false;
  296     closeGate();
  297     if (ISSETP(&fFlags, kLoopTerminate))
  298         goto abort;
  299 
  300     IOTimeWorkS();
  301     bool more;
  302     do {
  303         CLRP(&fFlags, kLoopRestart);
  304         workToDo = more = false;
  305         for (IOEventSource *evnt = eventChain; evnt; evnt = evnt->getNext()) {
  306 
  307             IOTimeClientS();
  308             more |= evnt->checkForWork();
  309             IOTimeClientE();
  310 
  311             if (ISSETP(&fFlags, kLoopTerminate))
  312                 goto abort;
  313             else if (fFlags & kLoopRestart) {
  314                 more = true;
  315                 break;
  316             }
  317         }
  318     } while (more);
  319 
  320     res = true;
  321     IOTimeWorkE();
  322 
  323 abort:
  324     openGate();
  325     return res;
  326 }
  327 
  328 /* virtual */ void IOWorkLoop::threadMain()
  329 {
  330 restartThread:
  331     do {
  332         if ( !runEventSources() )
  333             goto exitThread;
  334 
  335         IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
  336         if ( !ISSETP(&fFlags, kLoopTerminate) && !workToDo) {
  337             assert_wait((void *) &workToDo, false);
  338             IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
  339             thread_continue_t cptr = NULL;
  340             if (!reserved || !(kPreciousStack & reserved->options))
  341                 cptr = OSMemberFunctionCast(
  342                         thread_continue_t, this, &IOWorkLoop::threadMain);
  343             thread_block_parameter(cptr, this);
  344             goto restartThread;
  345             /* NOTREACHED */
  346         }
  347 
  348         // At this point we either have work to do or we need
  349         // to commit suicide.  But no matter 
  350         // Clear the simple lock and retore the interrupt state
  351         IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
  352     } while(workToDo);
  353 
  354 exitThread:
  355     workThread = 0;     // Say we don't have a loop and free ourselves
  356     free();
  357     IOExitThread();
  358 }
  359 
  360 IOThread IOWorkLoop::getThread() const
  361 {
  362     return workThread;
  363 }
  364 
  365 bool IOWorkLoop::onThread() const
  366 {
  367     return (IOThreadSelf() == workThread);
  368 }
  369 
  370 bool IOWorkLoop::inGate() const
  371 {
  372     return IORecursiveLockHaveLock(gateLock);
  373 }
  374 
  375 // Internal APIs used by event sources to control the thread
  376 void IOWorkLoop::signalWorkAvailable()
  377 {
  378     if (workToDoLock) {
  379         IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
  380         workToDo = true;
  381         thread_wakeup_one((void *) &workToDo);
  382         IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
  383     }
  384 }
  385 
  386 void IOWorkLoop::openGate()
  387 {
  388     IORecursiveLockUnlock(gateLock);
  389 }
  390 
  391 void IOWorkLoop::closeGate()
  392 {
  393     IORecursiveLockLock(gateLock);
  394 }
  395 
  396 bool IOWorkLoop::tryCloseGate()
  397 {
  398     return IORecursiveLockTryLock(gateLock) != 0;
  399 }
  400 
  401 int IOWorkLoop::sleepGate(void *event, UInt32 interuptibleType)
  402 {
  403     return IORecursiveLockSleep(gateLock, event, interuptibleType);
  404 }
  405 
  406 void IOWorkLoop::wakeupGate(void *event, bool oneThread)
  407 {
  408     IORecursiveLockWakeup(gateLock, event, oneThread);
  409 }
  410 
  411 IOReturn IOWorkLoop::runAction(Action inAction, OSObject *target,
  412                                   void *arg0, void *arg1,
  413                                   void *arg2, void *arg3)
  414 {
  415     IOReturn res;
  416 
  417     // closeGate is recursive so don't worry if we already hold the lock.
  418     closeGate();
  419     res = (*inAction)(target, arg0, arg1, arg2, arg3);
  420     openGate();
  421 
  422     return res;
  423 }
  424 
  425 IOReturn IOWorkLoop::_maintRequest(void *inC, void *inD, void *, void *)
  426 {
  427     maintCommandEnum command = (maintCommandEnum) (vm_address_t) inC;
  428     IOEventSource *inEvent = (IOEventSource *) inD;
  429     IOReturn res = kIOReturnSuccess;
  430 
  431     switch (command)
  432     {
  433     case mAddEvent:
  434         if (!inEvent->getWorkLoop()) {
  435             SETP(&fFlags, kLoopRestart);
  436 
  437             inEvent->retain();
  438             inEvent->setWorkLoop(this);
  439             inEvent->setNext(0);
  440     
  441             if (!eventChain)
  442                 eventChain = inEvent;
  443             else {
  444                 IOEventSource *event, *next;
  445     
  446                 for (event = eventChain; (next = event->getNext()); event = next)
  447                     ;
  448                 event->setNext(inEvent);
  449             }
  450         }
  451         break;
  452 
  453     case mRemoveEvent:
  454         if (inEvent->getWorkLoop()) {
  455             if (eventChain == inEvent)
  456                 eventChain = inEvent->getNext();
  457             else {
  458                 IOEventSource *event, *next;
  459     
  460                 event = eventChain;
  461                 while ((next = event->getNext()) && next != inEvent)
  462                     event = next;
  463     
  464                 if (!next) {
  465                     res = kIOReturnBadArgument;
  466                     break;
  467                 }
  468                 event->setNext(inEvent->getNext());
  469             }
  470     
  471             inEvent->setWorkLoop(0);
  472             inEvent->setNext(0);
  473             inEvent->release();
  474             SETP(&fFlags, kLoopRestart);
  475         }
  476         break;
  477 
  478     default:
  479         return kIOReturnUnsupported;
  480     }
  481 
  482     return res;
  483 }

Cache object: 567fad2532f0ffce528aa3cca59d0ae0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.