]>
git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOWorkLoop.cpp
2 * Copyright (c) 1998-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <pexpert/pexpert.h>
30 #include <IOKit/IOWorkLoop.h>
31 #include <IOKit/IOEventSource.h>
32 #include <IOKit/IOInterruptEventSource.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOTimeStamp.h>
35 #include <IOKit/IOKitDebug.h>
36 #include <libkern/OSDebug.h>
37 #include <kern/thread.h>
39 #define super OSObject
41 OSDefineMetaClassAndStructors(IOWorkLoop
, OSObject
);
43 // Block of unused functions intended for future use
45 OSMetaClassDefineReservedUnused(IOWorkLoop
, 0);
46 OSMetaClassDefineReservedUnused(IOWorkLoop
, 1);
47 OSMetaClassDefineReservedUnused(IOWorkLoop
, 2);
49 OSMetaClassDefineReservedUsed(IOWorkLoop
, 0);
50 OSMetaClassDefineReservedUsed(IOWorkLoop
, 1);
51 OSMetaClassDefineReservedUsed(IOWorkLoop
, 2);
53 OSMetaClassDefineReservedUnused(IOWorkLoop
, 3);
54 OSMetaClassDefineReservedUnused(IOWorkLoop
, 4);
55 OSMetaClassDefineReservedUnused(IOWorkLoop
, 5);
56 OSMetaClassDefineReservedUnused(IOWorkLoop
, 6);
57 OSMetaClassDefineReservedUnused(IOWorkLoop
, 7);
59 enum IOWorkLoopState
{ kLoopRestart
= 0x1, kLoopTerminate
= 0x2 };
60 static inline void SETP(void *addr
, unsigned int flag
)
61 { unsigned char *num
= (unsigned char *) addr
; *num
|= flag
; }
62 static inline void CLRP(void *addr
, unsigned int flag
)
63 { unsigned char *num
= (unsigned char *) addr
; *num
&= ~flag
; }
64 static inline bool ISSETP(void *addr
, unsigned int flag
)
65 { unsigned char *num
= (unsigned char *) addr
; return (*num
& flag
) != 0; }
67 #define fFlags loopRestart
69 #define passiveEventChain reserved->passiveEventChain
73 #define IOStatisticsRegisterCounter() \
75 reserved->counter = IOStatistics::registerWorkLoop(this); \
78 #define IOStatisticsUnregisterCounter() \
81 IOStatistics::unregisterWorkLoop(reserved->counter); \
84 #define IOStatisticsOpenGate() \
86 IOStatistics::countWorkLoopOpenGate(reserved->counter); \
89 #define IOStatisticsCloseGate() \
91 IOStatistics::countWorkLoopCloseGate(reserved->counter); \
94 #define IOStatisticsAttachEventSource() \
96 IOStatistics::attachWorkLoopEventSource(reserved->counter, inEvent->reserved->counter); \
99 #define IOStatisticsDetachEventSource() \
101 IOStatistics::detachWorkLoopEventSource(reserved->counter, inEvent->reserved->counter); \
106 #define IOStatisticsRegisterCounter()
107 #define IOStatisticsUnregisterCounter()
108 #define IOStatisticsOpenGate()
109 #define IOStatisticsCloseGate()
110 #define IOStatisticsAttachEventSource()
111 #define IOStatisticsDetachEventSource()
113 #endif /* IOKITSTATS */
115 bool IOWorkLoop::init()
117 // The super init and gateLock allocation MUST be done first.
118 if ( !super::init() )
121 // Allocate our ExpansionData if it hasn't been allocated already.
124 reserved
= IONew(ExpansionData
,1);
128 bzero(reserved
,sizeof(ExpansionData
));
132 OSBacktrace ( reserved
->allocationBacktrace
, sizeof ( reserved
->allocationBacktrace
) / sizeof ( reserved
->allocationBacktrace
[0] ) );
135 if ( gateLock
== NULL
) {
136 if ( !( gateLock
= IORecursiveLockAlloc()) )
140 if ( workToDoLock
== NULL
) {
141 if ( !(workToDoLock
= IOSimpleLockAlloc()) )
143 IOSimpleLockInit(workToDoLock
);
148 reserved
= IONew(ExpansionData
, 1);
149 reserved
->options
= 0;
152 IOStatisticsRegisterCounter();
154 if ( controlG
== NULL
) {
155 controlG
= IOCommandGate::commandGate(
157 OSMemberFunctionCast(
158 IOCommandGate::Action
,
160 &IOWorkLoop::_maintRequest
));
164 // Point the controlGate at the workLoop. Usually addEventSource
165 // does this automatically. The problem is in this case addEventSource
166 // uses the control gate and it has to be bootstrapped.
167 controlG
->setWorkLoop(this);
168 if (addEventSource(controlG
) != kIOReturnSuccess
)
172 if ( workThread
== NULL
) {
173 thread_continue_t cptr
= OSMemberFunctionCast(
176 &IOWorkLoop::threadMain
);
177 if (KERN_SUCCESS
!= kernel_thread_start(cptr
, this, &workThread
))
181 (void) thread_set_tag(workThread
, THREAD_TAG_IOWORKLOOP
);
186 IOWorkLoop::workLoop()
188 return IOWorkLoop::workLoopWithOptions(0);
192 IOWorkLoop::workLoopWithOptions(IOOptionBits options
)
194 IOWorkLoop
*me
= new IOWorkLoop
;
197 me
->reserved
= IONew(ExpansionData
,1);
202 bzero(me
->reserved
,sizeof(ExpansionData
));
203 me
->reserved
->options
= options
;
206 if (me
&& !me
->init()) {
214 // Free is called twice:
215 // First when the atomic retainCount transitions from 1 -> 0
216 // Secondly when the work loop itself is commiting hari kari
217 // Hence the each leg of the free must be single threaded.
218 void IOWorkLoop::free()
223 // If we are here then we must be trying to shut down this work loop
224 // in this case disable all of the event source, mark the loop
225 // as terminating and wakeup the work thread itself and return
226 // Note: we hold the gate across the entire operation mainly for the
227 // benefit of our event sources so we can disable them cleanly.
230 disableAllEventSources();
232 is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
233 SETP(&fFlags
, kLoopTerminate
);
234 thread_wakeup_one((void *) &workToDo
);
235 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
239 else /* !workThread */ {
240 IOEventSource
*event
, *next
;
242 for (event
= eventChain
; event
; event
= next
) {
243 next
= event
->getNext();
244 event
->setWorkLoop(0);
250 for (event
= passiveEventChain
; event
; event
= next
) {
251 next
= event
->getNext();
252 event
->setWorkLoop(0);
256 passiveEventChain
= 0;
258 // Either we have a partial initialization to clean up
259 // or the workThread itself is performing hari-kari.
260 // Either way clean up all of our resources and return.
268 IOSimpleLockFree(workToDoLock
);
273 IORecursiveLockFree(gateLock
);
277 IOStatisticsUnregisterCounter();
280 IODelete(reserved
, ExpansionData
, 1);
288 IOReturn
IOWorkLoop::addEventSource(IOEventSource
*newEvent
)
290 return controlG
->runCommand((void *) mAddEvent
, (void *) newEvent
);
293 IOReturn
IOWorkLoop::removeEventSource(IOEventSource
*toRemove
)
295 return controlG
->runCommand((void *) mRemoveEvent
, (void *) toRemove
);
298 void IOWorkLoop::enableAllEventSources() const
300 IOEventSource
*event
;
302 for (event
= eventChain
; event
; event
= event
->getNext())
305 for (event
= passiveEventChain
; event
; event
= event
->getNext())
309 void IOWorkLoop::disableAllEventSources() const
311 IOEventSource
*event
;
313 for (event
= eventChain
; event
; event
= event
->getNext())
316 /* NOTE: controlG is in passiveEventChain since it's an IOCommandGate */
317 for (event
= passiveEventChain
; event
; event
= event
->getNext())
318 if (event
!= controlG
) // Don't disable the control gate
322 void IOWorkLoop::enableAllInterrupts() const
324 IOEventSource
*event
;
326 for (event
= eventChain
; event
; event
= event
->getNext())
327 if (OSDynamicCast(IOInterruptEventSource
, event
))
331 void IOWorkLoop::disableAllInterrupts() const
333 IOEventSource
*event
;
335 for (event
= eventChain
; event
; event
= event
->getNext())
336 if (OSDynamicCast(IOInterruptEventSource
, event
))
341 /* virtual */ bool IOWorkLoop::runEventSources()
344 bool traceWL
= (gIOKitTrace
& kIOTraceWorkLoops
) ? true : false;
345 bool traceES
= (gIOKitTrace
& kIOTraceEventSources
) ? true : false;
348 if (ISSETP(&fFlags
, kLoopTerminate
))
352 IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_WORK
), (uintptr_t) this);
356 CLRP(&fFlags
, kLoopRestart
);
358 IOInterruptState is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
360 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
361 /* NOTE: only loop over event sources in eventChain. Bypass "passive" event sources for performance */
362 for (IOEventSource
*evnt
= eventChain
; evnt
; evnt
= evnt
->getNext()) {
365 IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_CLIENT
), (uintptr_t) this, (uintptr_t) evnt
);
367 more
|= evnt
->checkForWork();
370 IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_CLIENT
), (uintptr_t) this, (uintptr_t) evnt
);
372 if (ISSETP(&fFlags
, kLoopTerminate
))
374 else if (fFlags
& kLoopRestart
) {
384 IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_WORK
), (uintptr_t) this);
391 /* virtual */ void IOWorkLoop::threadMain()
395 if ( !runEventSources() )
398 IOInterruptState is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
399 if ( !ISSETP(&fFlags
, kLoopTerminate
) && !workToDo
) {
400 assert_wait((void *) &workToDo
, false);
401 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
402 thread_continue_t cptr
= NULL
;
403 if (!reserved
|| !(kPreciousStack
& reserved
->options
))
404 cptr
= OSMemberFunctionCast(
405 thread_continue_t
, this, &IOWorkLoop::threadMain
);
406 thread_block_parameter(cptr
, this);
411 // At this point we either have work to do or we need
412 // to commit suicide. But no matter
413 // Clear the simple lock and retore the interrupt state
414 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
418 thread_t thread
= workThread
;
419 workThread
= 0; // Say we don't have a loop and free ourselves
422 thread_deallocate(thread
);
423 (void) thread_terminate(thread
);
426 IOThread
IOWorkLoop::getThread() const
431 bool IOWorkLoop::onThread() const
433 return (IOThreadSelf() == workThread
);
436 bool IOWorkLoop::inGate() const
438 return IORecursiveLockHaveLock(gateLock
);
441 // Internal APIs used by event sources to control the thread
442 void IOWorkLoop::signalWorkAvailable()
445 IOInterruptState is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
447 thread_wakeup_one((void *) &workToDo
);
448 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
452 void IOWorkLoop::openGate()
454 IOStatisticsOpenGate();
455 IORecursiveLockUnlock(gateLock
);
458 void IOWorkLoop::closeGate()
460 IORecursiveLockLock(gateLock
);
461 IOStatisticsCloseGate();
464 bool IOWorkLoop::tryCloseGate()
466 bool res
= (IORecursiveLockTryLock(gateLock
) != 0);
468 IOStatisticsCloseGate();
473 int IOWorkLoop::sleepGate(void *event
, UInt32 interuptibleType
)
476 IOStatisticsOpenGate();
477 res
= IORecursiveLockSleep(gateLock
, event
, interuptibleType
);
478 IOStatisticsCloseGate();
482 int IOWorkLoop::sleepGate(void *event
, AbsoluteTime deadline
, UInt32 interuptibleType
)
485 IOStatisticsOpenGate();
486 res
= IORecursiveLockSleepDeadline(gateLock
, event
, deadline
, interuptibleType
);
487 IOStatisticsCloseGate();
491 void IOWorkLoop::wakeupGate(void *event
, bool oneThread
)
493 IORecursiveLockWakeup(gateLock
, event
, oneThread
);
496 IOReturn
IOWorkLoop::runAction(Action inAction
, OSObject
*target
,
497 void *arg0
, void *arg1
,
498 void *arg2
, void *arg3
)
502 // closeGate is recursive so don't worry if we already hold the lock.
504 res
= (*inAction
)(target
, arg0
, arg1
, arg2
, arg3
);
510 IOReturn
IOWorkLoop::_maintRequest(void *inC
, void *inD
, void *, void *)
512 maintCommandEnum command
= (maintCommandEnum
) (uintptr_t) inC
;
513 IOEventSource
*inEvent
= (IOEventSource
*) inD
;
514 IOReturn res
= kIOReturnSuccess
;
519 if (!inEvent
->getWorkLoop()) {
520 SETP(&fFlags
, kLoopRestart
);
523 inEvent
->setWorkLoop(this);
526 /* Check if this is a passive or active event source being added */
527 if (eventSourcePerformsWork(inEvent
)) {
530 eventChain
= inEvent
;
532 IOEventSource
*event
, *next
;
534 for (event
= eventChain
; (next
= event
->getNext()); event
= next
)
536 event
->setNext(inEvent
);
543 if (!passiveEventChain
)
544 passiveEventChain
= inEvent
;
546 IOEventSource
*event
, *next
;
548 for (event
= passiveEventChain
; (next
= event
->getNext()); event
= next
)
550 event
->setNext(inEvent
);
555 IOStatisticsAttachEventSource();
560 if (inEvent
->getWorkLoop()) {
561 IOStatisticsDetachEventSource();
563 if (eventSourcePerformsWork(inEvent
)) {
564 if (eventChain
== inEvent
)
565 eventChain
= inEvent
->getNext();
567 IOEventSource
*event
, *next
;
570 while ((next
= event
->getNext()) && next
!= inEvent
)
574 res
= kIOReturnBadArgument
;
577 event
->setNext(inEvent
->getNext());
581 if (passiveEventChain
== inEvent
)
582 passiveEventChain
= inEvent
->getNext();
584 IOEventSource
*event
, *next
;
586 event
= passiveEventChain
;
587 while ((next
= event
->getNext()) && next
!= inEvent
)
591 res
= kIOReturnBadArgument
;
594 event
->setNext(inEvent
->getNext());
598 inEvent
->setWorkLoop(0);
601 SETP(&fFlags
, kLoopRestart
);
606 return kIOReturnUnsupported
;
613 IOWorkLoop::eventSourcePerformsWork(IOEventSource
*inEventSource
)
618 * The idea here is to see if the subclass of IOEventSource has overridden checkForWork().
619 * The assumption is that if you override checkForWork(), you need to be
620 * active and not passive.
622 * We picked a known quantity controlG that does not override
623 * IOEventSource::checkForWork(), namely the IOCommandGate associated with
624 * the workloop to which this event source is getting attached.
626 * We do a pointer comparison on the offset in the vtable for inNewEvent against
627 * the offset in the vtable for inReferenceEvent. This works because
628 * IOCommandGate's slot for checkForWork() has the address of
629 * IOEventSource::checkForWork() in it.
631 * Think of OSMemberFunctionCast yielding the value at the vtable offset for
632 * checkForWork() here. We're just testing to see if it's the same or not.
639 ptr1
= OSMemberFunctionCast(void*, inEventSource
, &IOEventSource::checkForWork
);
640 ptr2
= OSMemberFunctionCast(void*, controlG
, &IOEventSource::checkForWork
);