]>
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 * 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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
26 1998-7-13 Godfrey van der Linden(gvdl)
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>
35 #define super OSObject
37 OSDefineMetaClassAndStructors(IOWorkLoop
, OSObject
);
39 // Block of unused functions intended for future use
40 OSMetaClassDefineReservedUsed(IOWorkLoop
, 0);
42 OSMetaClassDefineReservedUnused(IOWorkLoop
, 1);
43 OSMetaClassDefineReservedUnused(IOWorkLoop
, 2);
44 OSMetaClassDefineReservedUnused(IOWorkLoop
, 3);
45 OSMetaClassDefineReservedUnused(IOWorkLoop
, 4);
46 OSMetaClassDefineReservedUnused(IOWorkLoop
, 5);
47 OSMetaClassDefineReservedUnused(IOWorkLoop
, 6);
48 OSMetaClassDefineReservedUnused(IOWorkLoop
, 7);
50 enum IOWorkLoopState
{ kLoopRestart
= 0x1, kLoopTerminate
= 0x2 };
51 static inline void SETP(void *addr
, unsigned int flag
)
52 { unsigned int *num
= (unsigned int *) addr
; *num
|= flag
; }
53 static inline void CLRP(void *addr
, unsigned int flag
)
54 { unsigned int *num
= (unsigned int *) addr
; *num
&= ~flag
; }
55 static inline bool ISSETP(void *addr
, unsigned int flag
)
56 { unsigned int *num
= (unsigned int *) addr
; return (*num
& flag
) != 0; }
58 #define fFlags loopRestart
60 extern "C" extern void stack_privilege( thread_t thread
);
62 void IOWorkLoop::launchThreadMain(void *self
)
64 register thread_t mythread
= current_thread();
66 // Make sure that this thread always has a kernel stack
67 stack_privilege(mythread
);
68 thread_set_cont_arg((int) self
);
69 threadMainContinuation();
72 bool IOWorkLoop::init()
74 // The super init and gateLock allocation MUST be done first
78 if ( !(gateLock
= IORecursiveLockAlloc()) )
81 if ( !(workToDoLock
= IOSimpleLockAlloc()) )
84 controlG
= IOCommandGate::
85 commandGate(this, (IOCommandGate::Action
) &IOWorkLoop::_maintRequest
);
89 IOSimpleLockInit(workToDoLock
);
92 // Point the controlGate at the workLoop. Usually addEventSource
93 // does this automatically. The problem is in this case addEventSource
94 // uses the control gate and it has to be bootstrapped.
95 controlG
->setWorkLoop(this);
96 if (addEventSource(controlG
) != kIOReturnSuccess
)
99 workThread
= IOCreateThread(launchThreadMain
, (void *) this);
107 IOWorkLoop::workLoop()
109 IOWorkLoop
*me
= new IOWorkLoop
;
111 if (me
&& !me
->init()) {
119 // Free is called twice:
120 // First when the atomic retainCount transitions from 1 -> 0
121 // Secondly when the work loop itself is commiting hari kari
122 // Hence the each leg of the free must be single threaded.
123 void IOWorkLoop::free()
128 // If we are here then we must be trying to shut down this work loop
129 // in this case disable all of the event source, mark the loop for
130 // as terminating and wakeup the work thread itself and return
131 // Note: we hold the gate across the entire operation mainly for the
132 // benefit of our event sources so we can disable them cleanly.
135 disableAllEventSources();
137 is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
138 SETP(&fFlags
, kLoopTerminate
);
139 thread_wakeup_one((void *) &workToDo
);
140 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
144 else /* !workThread */ {
145 IOEventSource
*event
, *next
;
147 for (event
= eventChain
; event
; event
= next
) {
148 next
= event
->getNext();
149 event
->setWorkLoop(0);
155 // Either we have a partial initialisation to clean up
156 // or we the workThread itself is performing hari-kari.
157 // either way clean up all of our resources and return.
165 IOSimpleLockFree(workToDoLock
);
170 IORecursiveLockFree(gateLock
);
178 IOReturn
IOWorkLoop::addEventSource(IOEventSource
*newEvent
)
180 return controlG
->runCommand((void *) mAddEvent
, (void *) newEvent
);
183 IOReturn
IOWorkLoop::removeEventSource(IOEventSource
*toRemove
)
185 return controlG
->runCommand((void *) mRemoveEvent
, (void *) toRemove
);
188 void IOWorkLoop::enableAllEventSources() const
190 IOEventSource
*event
;
192 for (event
= eventChain
; event
; event
= event
->getNext())
196 void IOWorkLoop::disableAllEventSources() const
198 IOEventSource
*event
;
200 for (event
= eventChain
; event
; event
= event
->getNext())
201 if (event
!= controlG
) // Don't disable the control gate
205 void IOWorkLoop::enableAllInterrupts() const
207 IOEventSource
*event
;
209 for (event
= eventChain
; event
; event
= event
->getNext())
210 if (OSDynamicCast(IOInterruptEventSource
, event
))
214 void IOWorkLoop::disableAllInterrupts() const
216 IOEventSource
*event
;
218 for (event
= eventChain
; event
; event
= event
->getNext())
219 if (OSDynamicCast(IOInterruptEventSource
, event
))
224 #define IOTimeClientS() \
226 IOTimeStampStart(IODBG_WORKLOOP(IOWL_CLIENT), \
227 (unsigned int) this, (unsigned int) event); \
230 #define IOTimeClientE() \
232 IOTimeStampEnd(IODBG_WORKLOOP(IOWL_CLIENT), \
233 (unsigned int) this, (unsigned int) event); \
236 #define IOTimeWorkS() \
238 IOTimeStampStart(IODBG_WORKLOOP(IOWL_WORK), (unsigned int) this); \
241 #define IOTimeWorkE() \
243 IOTimeStampEnd(IODBG_WORKLOOP(IOWL_WORK),(unsigned int) this); \
248 #define IOTimeClientS()
249 #define IOTimeClientE()
250 #define IOTimeWorkS()
251 #define IOTimeWorkE()
255 void IOWorkLoop::threadMainContinuation()
258 self
= (IOWorkLoop
*) thread_get_cont_arg();
263 void IOWorkLoop::threadMain()
265 CLRP(&fFlags
, kLoopRestart
);
274 if (ISSETP(&fFlags
, kLoopTerminate
))
278 workToDo
= more
= false;
279 for (IOEventSource
*event
= eventChain
; event
; event
= event
->getNext()) {
282 more
|= event
->checkForWork();
285 if (ISSETP(&fFlags
, kLoopTerminate
))
287 else if (fFlags
& kLoopRestart
) {
288 CLRP(&fFlags
, kLoopRestart
);
298 is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
299 if ( !ISSETP(&fFlags
, kLoopTerminate
) && !workToDo
) {
300 assert_wait((void *) &workToDo
, false);
301 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
303 thread_set_cont_arg((int) this);
304 thread_block(&threadMainContinuation
);
308 // At this point we either have work to do or we need
309 // to commit suicide. But no matter
310 // Clear the simple lock and retore the interrupt state
311 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
319 workThread
= 0; // Say we don't have a loop and free ourselves
324 IOThread
IOWorkLoop::getThread() const
329 bool IOWorkLoop::onThread() const
331 return (IOThreadSelf() == workThread
);
334 bool IOWorkLoop::inGate() const
336 return IORecursiveLockHaveLock(gateLock
);
339 // Internal APIs used by event sources to control the thread
340 void IOWorkLoop::signalWorkAvailable()
343 IOInterruptState is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
345 thread_wakeup_one((void *) &workToDo
);
346 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
350 void IOWorkLoop::openGate()
352 IORecursiveLockUnlock(gateLock
);
355 void IOWorkLoop::closeGate()
357 IORecursiveLockLock(gateLock
);
360 bool IOWorkLoop::tryCloseGate()
362 return IORecursiveLockTryLock(gateLock
) != 0;
365 int IOWorkLoop::sleepGate(void *event
, UInt32 interuptibleType
)
367 return IORecursiveLockSleep(gateLock
, event
, interuptibleType
);
370 void IOWorkLoop::wakeupGate(void *event
, bool oneThread
)
372 IORecursiveLockWakeup(gateLock
, event
, oneThread
);
375 IOReturn
IOWorkLoop::runAction(Action inAction
, OSObject
*target
,
376 void *arg0
= 0, void *arg1
= 0,
377 void *arg2
= 0, void *arg3
= 0)
381 // closeGate is recursive so don't worry if we already hold the lock.
383 res
= (*inAction
)(target
, arg0
, arg1
, arg2
, arg3
);
389 IOReturn
IOWorkLoop::_maintRequest(void *inC
, void *inD
, void *, void *)
391 maintCommandEnum command
= (maintCommandEnum
) (vm_address_t
) inC
;
392 IOEventSource
*inEvent
= (IOEventSource
*) inD
;
393 IOReturn res
= kIOReturnSuccess
;
398 if (!inEvent
->getWorkLoop()) {
399 SETP(&fFlags
, kLoopRestart
);
402 inEvent
->setWorkLoop(this);
406 eventChain
= inEvent
;
408 IOEventSource
*event
, *next
;
410 for (event
= eventChain
; (next
= event
->getNext()); event
= next
)
412 event
->setNext(inEvent
);
418 if (inEvent
->getWorkLoop()) {
419 if (eventChain
== inEvent
)
420 eventChain
= inEvent
->getNext();
422 IOEventSource
*event
, *next
;
425 while ((next
= event
->getNext()) && next
!= inEvent
)
429 res
= kIOReturnBadArgument
;
432 event
->setNext(inEvent
->getNext());
435 inEvent
->setWorkLoop(0);
438 SETP(&fFlags
, kLoopRestart
);
443 return kIOReturnUnsupported
;