]>
git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOWorkLoop.cpp
74c7c5ed01e5b35443b53650d6a1f388e24aaeaf
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
34 1998-7-13 Godfrey van der Linden(gvdl)
37 #include <IOKit/IOWorkLoop.h>
38 #include <IOKit/IOEventSource.h>
39 #include <IOKit/IOInterruptEventSource.h>
40 #include <IOKit/IOCommandGate.h>
41 #include <IOKit/IOTimeStamp.h>
43 #define super OSObject
45 OSDefineMetaClassAndStructors(IOWorkLoop
, OSObject
);
47 // Block of unused functions intended for future use
48 OSMetaClassDefineReservedUsed(IOWorkLoop
, 0);
49 OSMetaClassDefineReservedUsed(IOWorkLoop
, 1);
51 OSMetaClassDefineReservedUnused(IOWorkLoop
, 2);
52 OSMetaClassDefineReservedUnused(IOWorkLoop
, 3);
53 OSMetaClassDefineReservedUnused(IOWorkLoop
, 4);
54 OSMetaClassDefineReservedUnused(IOWorkLoop
, 5);
55 OSMetaClassDefineReservedUnused(IOWorkLoop
, 6);
56 OSMetaClassDefineReservedUnused(IOWorkLoop
, 7);
58 enum IOWorkLoopState
{ kLoopRestart
= 0x1, kLoopTerminate
= 0x2 };
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; }
66 #define fFlags loopRestart
68 bool IOWorkLoop::init()
70 // The super init and gateLock allocation MUST be done first
74 if ( !(gateLock
= IORecursiveLockAlloc()) )
77 if ( !(workToDoLock
= IOSimpleLockAlloc()) )
80 controlG
= IOCommandGate::
81 commandGate(this, OSMemberFunctionCast(IOCommandGate::Action
,
82 this, &IOWorkLoop::_maintRequest
));
86 IOSimpleLockInit(workToDoLock
);
89 // Point the controlGate at the workLoop. Usually addEventSource
90 // does this automatically. The problem is in this case addEventSource
91 // uses the control gate and it has to be bootstrapped.
92 controlG
->setWorkLoop(this);
93 if (addEventSource(controlG
) != kIOReturnSuccess
)
97 OSMemberFunctionCast(IOThreadFunc
, this, &IOWorkLoop::threadMain
);
98 workThread
= IOCreateThread(cptr
, this);
106 IOWorkLoop::workLoop()
108 IOWorkLoop
*me
= new IOWorkLoop
;
110 if (me
&& !me
->init()) {
118 // Free is called twice:
119 // First when the atomic retainCount transitions from 1 -> 0
120 // Secondly when the work loop itself is commiting hari kari
121 // Hence the each leg of the free must be single threaded.
122 void IOWorkLoop::free()
127 // If we are here then we must be trying to shut down this work loop
128 // in this case disable all of the event source, mark the loop for
129 // as terminating and wakeup the work thread itself and return
130 // Note: we hold the gate across the entire operation mainly for the
131 // benefit of our event sources so we can disable them cleanly.
134 disableAllEventSources();
136 is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
137 SETP(&fFlags
, kLoopTerminate
);
138 thread_wakeup_one((void *) &workToDo
);
139 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
143 else /* !workThread */ {
144 IOEventSource
*event
, *next
;
146 for (event
= eventChain
; event
; event
= next
) {
147 next
= event
->getNext();
148 event
->setWorkLoop(0);
154 // Either we have a partial initialisation to clean up
155 // or we the workThread itself is performing hari-kari.
156 // either way clean up all of our resources and return.
164 IOSimpleLockFree(workToDoLock
);
169 IORecursiveLockFree(gateLock
);
177 IOReturn
IOWorkLoop::addEventSource(IOEventSource
*newEvent
)
179 return controlG
->runCommand((void *) mAddEvent
, (void *) newEvent
);
182 IOReturn
IOWorkLoop::removeEventSource(IOEventSource
*toRemove
)
184 return controlG
->runCommand((void *) mRemoveEvent
, (void *) toRemove
);
187 void IOWorkLoop::enableAllEventSources() const
189 IOEventSource
*event
;
191 for (event
= eventChain
; event
; event
= event
->getNext())
195 void IOWorkLoop::disableAllEventSources() const
197 IOEventSource
*event
;
199 for (event
= eventChain
; event
; event
= event
->getNext())
200 if (event
!= controlG
) // Don't disable the control gate
204 void IOWorkLoop::enableAllInterrupts() const
206 IOEventSource
*event
;
208 for (event
= eventChain
; event
; event
= event
->getNext())
209 if (OSDynamicCast(IOInterruptEventSource
, event
))
213 void IOWorkLoop::disableAllInterrupts() const
215 IOEventSource
*event
;
217 for (event
= eventChain
; event
; event
= event
->getNext())
218 if (OSDynamicCast(IOInterruptEventSource
, event
))
223 #define IOTimeClientS() \
225 IOTimeStampStart(IODBG_WORKLOOP(IOWL_CLIENT), \
226 (unsigned int) this, (unsigned int) event); \
229 #define IOTimeClientE() \
231 IOTimeStampEnd(IODBG_WORKLOOP(IOWL_CLIENT), \
232 (unsigned int) this, (unsigned int) event); \
235 #define IOTimeWorkS() \
237 IOTimeStampStart(IODBG_WORKLOOP(IOWL_WORK), (unsigned int) this); \
240 #define IOTimeWorkE() \
242 IOTimeStampEnd(IODBG_WORKLOOP(IOWL_WORK),(unsigned int) this); \
247 #define IOTimeClientS()
248 #define IOTimeClientE()
249 #define IOTimeWorkS()
250 #define IOTimeWorkE()
254 /* virtual */ bool IOWorkLoop::runEventSources()
258 if (ISSETP(&fFlags
, kLoopTerminate
))
264 CLRP(&fFlags
, kLoopRestart
);
265 workToDo
= more
= false;
266 for (IOEventSource
*evnt
= eventChain
; evnt
; evnt
= evnt
->getNext()) {
269 more
|= evnt
->checkForWork();
272 if (ISSETP(&fFlags
, kLoopTerminate
))
274 else if (fFlags
& kLoopRestart
) {
289 /* virtual */ void IOWorkLoop::threadMain()
292 if ( !runEventSources() )
295 IOInterruptState is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
296 if ( !ISSETP(&fFlags
, kLoopTerminate
) && !workToDo
) {
297 assert_wait((void *) &workToDo
, false);
298 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
300 thread_continue_t cptr
= OSMemberFunctionCast(
301 thread_continue_t
, this, &IOWorkLoop::threadMain
);
302 thread_block_parameter(cptr
, this);
306 // At this point we either have work to do or we need
307 // to commit suicide. But no matter
308 // Clear the simple lock and retore the interrupt state
309 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
313 workThread
= 0; // Say we don't have a loop and free ourselves
318 IOThread
IOWorkLoop::getThread() const
323 bool IOWorkLoop::onThread() const
325 return (IOThreadSelf() == workThread
);
328 bool IOWorkLoop::inGate() const
330 return IORecursiveLockHaveLock(gateLock
);
333 // Internal APIs used by event sources to control the thread
334 void IOWorkLoop::signalWorkAvailable()
337 IOInterruptState is
= IOSimpleLockLockDisableInterrupt(workToDoLock
);
339 thread_wakeup_one((void *) &workToDo
);
340 IOSimpleLockUnlockEnableInterrupt(workToDoLock
, is
);
344 void IOWorkLoop::openGate()
346 IORecursiveLockUnlock(gateLock
);
349 void IOWorkLoop::closeGate()
351 IORecursiveLockLock(gateLock
);
354 bool IOWorkLoop::tryCloseGate()
356 return IORecursiveLockTryLock(gateLock
) != 0;
359 int IOWorkLoop::sleepGate(void *event
, UInt32 interuptibleType
)
361 return IORecursiveLockSleep(gateLock
, event
, interuptibleType
);
364 void IOWorkLoop::wakeupGate(void *event
, bool oneThread
)
366 IORecursiveLockWakeup(gateLock
, event
, oneThread
);
369 IOReturn
IOWorkLoop::runAction(Action inAction
, OSObject
*target
,
370 void *arg0
, void *arg1
,
371 void *arg2
, void *arg3
)
375 // closeGate is recursive so don't worry if we already hold the lock.
377 res
= (*inAction
)(target
, arg0
, arg1
, arg2
, arg3
);
383 IOReturn
IOWorkLoop::_maintRequest(void *inC
, void *inD
, void *, void *)
385 maintCommandEnum command
= (maintCommandEnum
) (vm_address_t
) inC
;
386 IOEventSource
*inEvent
= (IOEventSource
*) inD
;
387 IOReturn res
= kIOReturnSuccess
;
392 if (!inEvent
->getWorkLoop()) {
393 SETP(&fFlags
, kLoopRestart
);
396 inEvent
->setWorkLoop(this);
400 eventChain
= inEvent
;
402 IOEventSource
*event
, *next
;
404 for (event
= eventChain
; (next
= event
->getNext()); event
= next
)
406 event
->setNext(inEvent
);
412 if (inEvent
->getWorkLoop()) {
413 if (eventChain
== inEvent
)
414 eventChain
= inEvent
->getNext();
416 IOEventSource
*event
, *next
;
419 while ((next
= event
->getNext()) && next
!= inEvent
)
423 res
= kIOReturnBadArgument
;
426 event
->setNext(inEvent
->getNext());
429 inEvent
->setWorkLoop(0);
432 SETP(&fFlags
, kLoopRestart
);
437 return kIOReturnUnsupported
;