]>
git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOWorkLoop.cpp
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
29 1998-7-13 Godfrey van der Linden(gvdl)
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOEventSource.h>
34 #include <IOKit/IOInterruptEventSource.h>
35 #include <IOKit/IOCommandGate.h>
36 #include <IOKit/IOTimeStamp.h>
38 #define super OSObject
40 OSDefineMetaClassAndStructors(IOWorkLoop
, OSObject
);
42 // Block of unused functions intended for future use
43 OSMetaClassDefineReservedUsed(IOWorkLoop
, 0);
45 OSMetaClassDefineReservedUnused(IOWorkLoop
, 1);
46 OSMetaClassDefineReservedUnused(IOWorkLoop
, 2);
47 OSMetaClassDefineReservedUnused(IOWorkLoop
, 3);
48 OSMetaClassDefineReservedUnused(IOWorkLoop
, 4);
49 OSMetaClassDefineReservedUnused(IOWorkLoop
, 5);
50 OSMetaClassDefineReservedUnused(IOWorkLoop
, 6);
51 OSMetaClassDefineReservedUnused(IOWorkLoop
, 7);
53 enum IOWorkLoopState
{ kLoopRestart
= 0x1, kLoopTerminate
= 0x2 };
54 static inline void SETP(void *addr
, unsigned int flag
)
55 { unsigned int *num
= (unsigned int *) addr
; *num
|= flag
; }
56 static inline void CLRP(void *addr
, unsigned int flag
)
57 { unsigned int *num
= (unsigned int *) addr
; *num
&= ~flag
; }
58 static inline bool ISSETP(void *addr
, unsigned int flag
)
59 { unsigned int *num
= (unsigned int *) addr
; return (*num
& flag
) != 0; }
61 #define fFlags loopRestart
63 extern "C" extern void stack_privilege( thread_t thread
);
65 void IOWorkLoop::launchThreadMain(void *self
)
67 register thread_t mythread
= current_thread();
69 // Make sure that this thread always has a kernel stack
70 stack_privilege(mythread
);
71 thread_set_cont_arg((int) self
);
72 threadMainContinuation();
75 bool IOWorkLoop::init()
77 // The super init and gateLock allocation MUST be done first
81 if ( !(gateLock
= IORecursiveLockAlloc()) )
84 if ( !(workToDoLock
= IOSimpleLockAlloc()) )
87 controlG
= IOCommandGate::
88 commandGate(this, (IOCommandGate::Action
) &IOWorkLoop::_maintRequest
);
92 IOSimpleLockInit(workToDoLock
);
95 // Point the controlGate at the workLoop. Usually addEventSource
96 // does this automatically. The problem is in this case addEventSource
97 // uses the control gate and it has to be bootstrapped.
98 controlG
->setWorkLoop(this);
99 if (addEventSource(controlG
) != kIOReturnSuccess
)
102 workThread
= IOCreateThread(launchThreadMain
, (void *) this);
110 IOWorkLoop::workLoop()
112 IOWorkLoop
*me
= new IOWorkLoop
;
114 if (me
&& !me
->init()) {
122 // Free is called twice:
123 // First when the atomic retainCount transitions from 1 -> 0
124 // Secondly when the work loop itself is commiting hari kari
125 // Hence the each leg of the free must be single threaded.
126 void IOWorkLoop::free()
131 // If we are here then we must be trying to shut down this work loop
132 // in this case disable all of the event source, mark the loop for
133 // as terminating and wakeup the work thread itself and return
134 // Note: we hold the gate across the entire operation mainly for the
135 // benefit of our event sources so we can disable them cleanly.
138 disableAllEventSources();
140 is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
141 SETP(&fFlags
, kLoopTerminate
);
142 thread_wakeup_one((void *) &workToDo
);
143 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
147 else /* !workThread */ {
148 IOEventSource
*event
, *next
;
150 for (event
= eventChain
; event
; event
= next
) {
151 next
= event
->getNext();
152 event
->setWorkLoop(0);
158 // Either we have a partial initialisation to clean up
159 // or we the workThread itself is performing hari-kari.
160 // either way clean up all of our resources and return.
168 IOSimpleLockFree(workToDoLock
);
173 IORecursiveLockFree(gateLock
);
181 IOReturn
IOWorkLoop::addEventSource(IOEventSource
*newEvent
)
183 return controlG
->runCommand((void *) mAddEvent
, (void *) newEvent
);
186 IOReturn
IOWorkLoop::removeEventSource(IOEventSource
*toRemove
)
188 return controlG
->runCommand((void *) mRemoveEvent
, (void *) toRemove
);
191 void IOWorkLoop::enableAllEventSources() const
193 IOEventSource
*event
;
195 for (event
= eventChain
; event
; event
= event
->getNext())
199 void IOWorkLoop::disableAllEventSources() const
201 IOEventSource
*event
;
203 for (event
= eventChain
; event
; event
= event
->getNext())
204 if (event
!= controlG
) // Don't disable the control gate
208 void IOWorkLoop::enableAllInterrupts() const
210 IOEventSource
*event
;
212 for (event
= eventChain
; event
; event
= event
->getNext())
213 if (OSDynamicCast(IOInterruptEventSource
, event
))
217 void IOWorkLoop::disableAllInterrupts() const
219 IOEventSource
*event
;
221 for (event
= eventChain
; event
; event
= event
->getNext())
222 if (OSDynamicCast(IOInterruptEventSource
, event
))
227 #define IOTimeClientS() \
229 IOTimeStampStart(IODBG_WORKLOOP(IOWL_CLIENT), \
230 (unsigned int) this, (unsigned int) event); \
233 #define IOTimeClientE() \
235 IOTimeStampEnd(IODBG_WORKLOOP(IOWL_CLIENT), \
236 (unsigned int) this, (unsigned int) event); \
239 #define IOTimeWorkS() \
241 IOTimeStampStart(IODBG_WORKLOOP(IOWL_WORK), (unsigned int) this); \
244 #define IOTimeWorkE() \
246 IOTimeStampEnd(IODBG_WORKLOOP(IOWL_WORK),(unsigned int) this); \
251 #define IOTimeClientS()
252 #define IOTimeClientE()
253 #define IOTimeWorkS()
254 #define IOTimeWorkE()
258 void IOWorkLoop::threadMainContinuation()
261 self
= (IOWorkLoop
*) thread_get_cont_arg();
266 void IOWorkLoop::threadMain()
268 CLRP(&fFlags
, kLoopRestart
);
277 if (ISSETP(&fFlags
, kLoopTerminate
))
281 workToDo
= more
= false;
282 for (IOEventSource
*event
= eventChain
; event
; event
= event
->getNext()) {
285 more
|= event
->checkForWork();
288 if (ISSETP(&fFlags
, kLoopTerminate
))
290 else if (fFlags
& kLoopRestart
) {
291 CLRP(&fFlags
, kLoopRestart
);
301 is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
302 if ( !ISSETP(&fFlags
, kLoopTerminate
) && !workToDo
) {
303 assert_wait((void *) &workToDo
, false);
304 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
306 thread_set_cont_arg((int) this);
307 thread_block(&threadMainContinuation
);
311 // At this point we either have work to do or we need
312 // to commit suicide. But no matter
313 // Clear the simple lock and retore the interrupt state
314 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
322 workThread
= 0; // Say we don't have a loop and free ourselves
327 IOThread
IOWorkLoop::getThread() const
332 bool IOWorkLoop::onThread() const
334 return (IOThreadSelf() == workThread
);
337 bool IOWorkLoop::inGate() const
339 return IORecursiveLockHaveLock(gateLock
);
342 // Internal APIs used by event sources to control the thread
343 void IOWorkLoop::signalWorkAvailable()
346 IOInterruptState is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
348 thread_wakeup_one((void *) &workToDo
);
349 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
353 void IOWorkLoop::openGate()
355 IORecursiveLockUnlock(gateLock
);
358 void IOWorkLoop::closeGate()
360 IORecursiveLockLock(gateLock
);
363 bool IOWorkLoop::tryCloseGate()
365 return IORecursiveLockTryLock(gateLock
) != 0;
368 int IOWorkLoop::sleepGate(void *event
, UInt32 interuptibleType
)
370 return IORecursiveLockSleep(gateLock
, event
, interuptibleType
);
373 void IOWorkLoop::wakeupGate(void *event
, bool oneThread
)
375 IORecursiveLockWakeup(gateLock
, event
, oneThread
);
378 IOReturn
IOWorkLoop::runAction(Action inAction
, OSObject
*target
,
379 void *arg0
= 0, void *arg1
= 0,
380 void *arg2
= 0, void *arg3
= 0)
384 // closeGate is recursive so don't worry if we already hold the lock.
386 res
= (*inAction
)(target
, arg0
, arg1
, arg2
, arg3
);
392 IOReturn
IOWorkLoop::_maintRequest(void *inC
, void *inD
, void *, void *)
394 maintCommandEnum command
= (maintCommandEnum
) (vm_address_t
) inC
;
395 IOEventSource
*inEvent
= (IOEventSource
*) inD
;
396 IOReturn res
= kIOReturnSuccess
;
401 if (!inEvent
->getWorkLoop()) {
402 SETP(&fFlags
, kLoopRestart
);
405 inEvent
->setWorkLoop(this);
409 eventChain
= inEvent
;
411 IOEventSource
*event
, *next
;
413 for (event
= eventChain
; (next
= event
->getNext()); event
= next
)
415 event
->setNext(inEvent
);
421 if (inEvent
->getWorkLoop()) {
422 if (eventChain
== inEvent
)
423 eventChain
= inEvent
->getNext();
425 IOEventSource
*event
, *next
;
428 while ((next
= event
->getNext()) && next
!= inEvent
)
432 res
= kIOReturnBadArgument
;
435 event
->setNext(inEvent
->getNext());
438 inEvent
->setWorkLoop(0);
441 SETP(&fFlags
, kLoopRestart
);
446 return kIOReturnUnsupported
;