]>
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 * 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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
27 1998-7-13 Godfrey van der Linden(gvdl)
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>
36 #define super OSObject
38 OSDefineMetaClassAndStructors(IOWorkLoop
, OSObject
);
40 // Block of unused functions intended for future use
41 OSMetaClassDefineReservedUsed(IOWorkLoop
, 0);
43 OSMetaClassDefineReservedUnused(IOWorkLoop
, 1);
44 OSMetaClassDefineReservedUnused(IOWorkLoop
, 2);
45 OSMetaClassDefineReservedUnused(IOWorkLoop
, 3);
46 OSMetaClassDefineReservedUnused(IOWorkLoop
, 4);
47 OSMetaClassDefineReservedUnused(IOWorkLoop
, 5);
48 OSMetaClassDefineReservedUnused(IOWorkLoop
, 6);
49 OSMetaClassDefineReservedUnused(IOWorkLoop
, 7);
51 enum IOWorkLoopState
{ kLoopRestart
= 0x1, kLoopTerminate
= 0x2 };
52 static inline void SETP(void *addr
, unsigned int flag
)
53 { unsigned int *num
= (unsigned int *) addr
; *num
|= flag
; }
54 static inline void CLRP(void *addr
, unsigned int flag
)
55 { unsigned int *num
= (unsigned int *) addr
; *num
&= ~flag
; }
56 static inline bool ISSETP(void *addr
, unsigned int flag
)
57 { unsigned int *num
= (unsigned int *) addr
; return (*num
& flag
) != 0; }
59 #define fFlags loopRestart
61 bool IOWorkLoop::init()
63 // The super init and gateLock allocation MUST be done first
67 if ( !(gateLock
= IORecursiveLockAlloc()) )
70 if ( !(workToDoLock
= IOSimpleLockAlloc()) )
73 controlG
= IOCommandGate::
74 commandGate(this, (IOCommandGate::Action
) &IOWorkLoop::_maintRequest
);
78 IOSimpleLockInit(workToDoLock
);
81 // Point the controlGate at the workLoop. Usually addEventSource
82 // does this automatically. The problem is in this case addEventSource
83 // uses the control gate and it has to be bootstrapped.
84 controlG
->setWorkLoop(this);
85 if (addEventSource(controlG
) != kIOReturnSuccess
)
88 workThread
= IOCreateThread((thread_continue_t
)threadMainContinuation
, this);
96 IOWorkLoop::workLoop()
98 IOWorkLoop
*me
= new IOWorkLoop
;
100 if (me
&& !me
->init()) {
108 // Free is called twice:
109 // First when the atomic retainCount transitions from 1 -> 0
110 // Secondly when the work loop itself is commiting hari kari
111 // Hence the each leg of the free must be single threaded.
112 void IOWorkLoop::free()
117 // If we are here then we must be trying to shut down this work loop
118 // in this case disable all of the event source, mark the loop for
119 // as terminating and wakeup the work thread itself and return
120 // Note: we hold the gate across the entire operation mainly for the
121 // benefit of our event sources so we can disable them cleanly.
124 disableAllEventSources();
126 is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
127 SETP(&fFlags
, kLoopTerminate
);
128 thread_wakeup_one((void *) &workToDo
);
129 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
133 else /* !workThread */ {
134 IOEventSource
*event
, *next
;
136 for (event
= eventChain
; event
; event
= next
) {
137 next
= event
->getNext();
138 event
->setWorkLoop(0);
144 // Either we have a partial initialisation to clean up
145 // or we the workThread itself is performing hari-kari.
146 // either way clean up all of our resources and return.
154 IOSimpleLockFree(workToDoLock
);
159 IORecursiveLockFree(gateLock
);
167 IOReturn
IOWorkLoop::addEventSource(IOEventSource
*newEvent
)
169 return controlG
->runCommand((void *) mAddEvent
, (void *) newEvent
);
172 IOReturn
IOWorkLoop::removeEventSource(IOEventSource
*toRemove
)
174 return controlG
->runCommand((void *) mRemoveEvent
, (void *) toRemove
);
177 void IOWorkLoop::enableAllEventSources() const
179 IOEventSource
*event
;
181 for (event
= eventChain
; event
; event
= event
->getNext())
185 void IOWorkLoop::disableAllEventSources() const
187 IOEventSource
*event
;
189 for (event
= eventChain
; event
; event
= event
->getNext())
190 if (event
!= controlG
) // Don't disable the control gate
194 void IOWorkLoop::enableAllInterrupts() const
196 IOEventSource
*event
;
198 for (event
= eventChain
; event
; event
= event
->getNext())
199 if (OSDynamicCast(IOInterruptEventSource
, event
))
203 void IOWorkLoop::disableAllInterrupts() const
205 IOEventSource
*event
;
207 for (event
= eventChain
; event
; event
= event
->getNext())
208 if (OSDynamicCast(IOInterruptEventSource
, event
))
213 #define IOTimeClientS() \
215 IOTimeStampStart(IODBG_WORKLOOP(IOWL_CLIENT), \
216 (unsigned int) this, (unsigned int) event); \
219 #define IOTimeClientE() \
221 IOTimeStampEnd(IODBG_WORKLOOP(IOWL_CLIENT), \
222 (unsigned int) this, (unsigned int) event); \
225 #define IOTimeWorkS() \
227 IOTimeStampStart(IODBG_WORKLOOP(IOWL_WORK), (unsigned int) this); \
230 #define IOTimeWorkE() \
232 IOTimeStampEnd(IODBG_WORKLOOP(IOWL_WORK),(unsigned int) this); \
237 #define IOTimeClientS()
238 #define IOTimeClientE()
239 #define IOTimeWorkS()
240 #define IOTimeWorkE()
244 void IOWorkLoop::threadMainContinuation(IOWorkLoop
*self
)
249 void IOWorkLoop::threadMain()
251 CLRP(&fFlags
, kLoopRestart
);
260 if (ISSETP(&fFlags
, kLoopTerminate
))
264 workToDo
= more
= false;
265 for (IOEventSource
*event
= eventChain
; event
; event
= event
->getNext()) {
268 more
|= event
->checkForWork();
271 if (ISSETP(&fFlags
, kLoopTerminate
))
273 else if (fFlags
& kLoopRestart
) {
274 CLRP(&fFlags
, kLoopRestart
);
284 is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
285 if ( !ISSETP(&fFlags
, kLoopTerminate
) && !workToDo
) {
286 assert_wait((void *) &workToDo
, false);
287 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
289 thread_block_parameter((thread_continue_t
)threadMainContinuation
, this);
293 // At this point we either have work to do or we need
294 // to commit suicide. But no matter
295 // Clear the simple lock and retore the interrupt state
296 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
304 workThread
= 0; // Say we don't have a loop and free ourselves
309 IOThread
IOWorkLoop::getThread() const
314 bool IOWorkLoop::onThread() const
316 return (IOThreadSelf() == workThread
);
319 bool IOWorkLoop::inGate() const
321 return IORecursiveLockHaveLock(gateLock
);
324 // Internal APIs used by event sources to control the thread
325 void IOWorkLoop::signalWorkAvailable()
328 IOInterruptState is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
330 thread_wakeup_one((void *) &workToDo
);
331 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
335 void IOWorkLoop::openGate()
337 IORecursiveLockUnlock(gateLock
);
340 void IOWorkLoop::closeGate()
342 IORecursiveLockLock(gateLock
);
345 bool IOWorkLoop::tryCloseGate()
347 return IORecursiveLockTryLock(gateLock
) != 0;
350 int IOWorkLoop::sleepGate(void *event
, UInt32 interuptibleType
)
352 return IORecursiveLockSleep(gateLock
, event
, interuptibleType
);
355 void IOWorkLoop::wakeupGate(void *event
, bool oneThread
)
357 IORecursiveLockWakeup(gateLock
, event
, oneThread
);
360 IOReturn
IOWorkLoop::runAction(Action inAction
, OSObject
*target
,
361 void *arg0
, void *arg1
,
362 void *arg2
, void *arg3
)
366 // closeGate is recursive so don't worry if we already hold the lock.
368 res
= (*inAction
)(target
, arg0
, arg1
, arg2
, arg3
);
374 IOReturn
IOWorkLoop::_maintRequest(void *inC
, void *inD
, void *, void *)
376 maintCommandEnum command
= (maintCommandEnum
) (vm_address_t
) inC
;
377 IOEventSource
*inEvent
= (IOEventSource
*) inD
;
378 IOReturn res
= kIOReturnSuccess
;
383 if (!inEvent
->getWorkLoop()) {
384 SETP(&fFlags
, kLoopRestart
);
387 inEvent
->setWorkLoop(this);
391 eventChain
= inEvent
;
393 IOEventSource
*event
, *next
;
395 for (event
= eventChain
; (next
= event
->getNext()); event
= next
)
397 event
->setNext(inEvent
);
403 if (inEvent
->getWorkLoop()) {
404 if (eventChain
== inEvent
)
405 eventChain
= inEvent
->getNext();
407 IOEventSource
*event
, *next
;
410 while ((next
= event
->getNext()) && next
!= inEvent
)
414 res
= kIOReturnBadArgument
;
417 event
->setNext(inEvent
->getNext());
420 inEvent
->setWorkLoop(0);
423 SETP(&fFlags
, kLoopRestart
);
428 return kIOReturnUnsupported
;