]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOWorkLoop.cpp
xnu-6153.41.3.tar.gz
[apple/xnu.git] / iokit / Kernel / IOWorkLoop.cpp
CommitLineData
1c79356b 1/*
6d2010ae 2 * Copyright (c) 1998-2010 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
b0d623f7
A
28
29#include <pexpert/pexpert.h>
1c79356b
A
30#include <IOKit/IOWorkLoop.h>
31#include <IOKit/IOEventSource.h>
32#include <IOKit/IOInterruptEventSource.h>
33#include <IOKit/IOCommandGate.h>
39037602 34#include <IOKit/IOCommandPool.h>
1c79356b 35#include <IOKit/IOTimeStamp.h>
060df5ea 36#include <IOKit/IOKitDebug.h>
2d21ac55 37#include <libkern/OSDebug.h>
4b17d6b6 38#include <kern/thread.h>
1c79356b
A
39
40#define super OSObject
41
42OSDefineMetaClassAndStructors(IOWorkLoop, OSObject);
43
44// Block of unused functions intended for future use
b0d623f7
A
45#if __LP64__
46OSMetaClassDefineReservedUnused(IOWorkLoop, 0);
47OSMetaClassDefineReservedUnused(IOWorkLoop, 1);
48OSMetaClassDefineReservedUnused(IOWorkLoop, 2);
49#else
0b4e3aa0 50OSMetaClassDefineReservedUsed(IOWorkLoop, 0);
0c530ab8 51OSMetaClassDefineReservedUsed(IOWorkLoop, 1);
b0d623f7
A
52OSMetaClassDefineReservedUsed(IOWorkLoop, 2);
53#endif
1c79356b
A
54OSMetaClassDefineReservedUnused(IOWorkLoop, 3);
55OSMetaClassDefineReservedUnused(IOWorkLoop, 4);
56OSMetaClassDefineReservedUnused(IOWorkLoop, 5);
57OSMetaClassDefineReservedUnused(IOWorkLoop, 6);
58OSMetaClassDefineReservedUnused(IOWorkLoop, 7);
59
60enum IOWorkLoopState { kLoopRestart = 0x1, kLoopTerminate = 0x2 };
0a7de745
A
61static inline void
62SETP(void *addr, unsigned int flag)
63{
64 unsigned char *num = (unsigned char *) addr; *num |= flag;
65}
66static inline void
67CLRP(void *addr, unsigned int flag)
68{
69 unsigned char *num = (unsigned char *) addr; *num &= ~flag;
70}
71static inline bool
72ISSETP(void *addr, unsigned int flag)
73{
74 unsigned char *num = (unsigned char *) addr; return (*num & flag) != 0;
75}
1c79356b
A
76
77#define fFlags loopRestart
78
0a7de745 79#define passiveEventChain reserved->passiveEventChain
6d2010ae
A
80
81#if IOKITSTATS
82
83#define IOStatisticsRegisterCounter() \
84do { \
85 reserved->counter = IOStatistics::registerWorkLoop(this); \
86} while(0)
87
88#define IOStatisticsUnregisterCounter() \
89do { \
90 if (reserved) \
0a7de745 91 IOStatistics::unregisterWorkLoop(reserved->counter); \
6d2010ae
A
92} while(0)
93
94#define IOStatisticsOpenGate() \
95do { \
96 IOStatistics::countWorkLoopOpenGate(reserved->counter); \
0a7de745 97 if (reserved->lockInterval) lockTime(); \
6d2010ae 98} while(0)
6d2010ae
A
99#define IOStatisticsCloseGate() \
100do { \
39037602 101 IOStatistics::countWorkLoopCloseGate(reserved->counter); \
0a7de745 102 if (reserved->lockInterval) reserved->lockTime = mach_absolute_time(); \
6d2010ae
A
103} while(0)
104
105#define IOStatisticsAttachEventSource() \
106do { \
107 IOStatistics::attachWorkLoopEventSource(reserved->counter, inEvent->reserved->counter); \
108} while(0)
109
110#define IOStatisticsDetachEventSource() \
111do { \
112 IOStatistics::detachWorkLoopEventSource(reserved->counter, inEvent->reserved->counter); \
113} while(0)
114
115#else
116
117#define IOStatisticsRegisterCounter()
118#define IOStatisticsUnregisterCounter()
119#define IOStatisticsOpenGate()
120#define IOStatisticsCloseGate()
121#define IOStatisticsAttachEventSource()
122#define IOStatisticsDetachEventSource()
123
124#endif /* IOKITSTATS */
b0d623f7 125
0a7de745
A
126bool
127IOWorkLoop::init()
1c79356b 128{
0a7de745
A
129 // The super init and gateLock allocation MUST be done first.
130 if (!super::init()) {
131 return false;
132 }
133
6d2010ae 134 // Allocate our ExpansionData if it hasn't been allocated already.
0a7de745
A
135 if (!reserved) {
136 reserved = IONew(ExpansionData, 1);
137 if (!reserved) {
138 return false;
139 }
140
141 bzero(reserved, sizeof(ExpansionData));
142 }
143
144 if (gateLock == NULL) {
145 if (!(gateLock = IORecursiveLockAlloc())) {
6d2010ae 146 return false;
0a7de745
A
147 }
148 }
149
150 if (workToDoLock == NULL) {
151 if (!(workToDoLock = IOSimpleLockAlloc())) {
152 return false;
153 }
154 IOSimpleLockInit(workToDoLock);
155 workToDo = false;
156 }
157
158 IOStatisticsRegisterCounter();
159
160 if (controlG == NULL) {
161 controlG = IOCommandGate::commandGate(
162 this,
163 OSMemberFunctionCast(
164 IOCommandGate::Action,
165 this,
166 &IOWorkLoop::_maintRequest));
167
168 if (!controlG) {
169 return false;
170 }
171 // Point the controlGate at the workLoop. Usually addEventSource
172 // does this automatically. The problem is in this case addEventSource
173 // uses the control gate and it has to be bootstrapped.
174 controlG->setWorkLoop(this);
175 if (addEventSource(controlG) != kIOReturnSuccess) {
176 return false;
177 }
178 }
179
180 if (workThread == NULL) {
181 thread_continue_t cptr = OSMemberFunctionCast(
182 thread_continue_t,
183 this,
184 &IOWorkLoop::threadMain);
185 if (KERN_SUCCESS != kernel_thread_start(cptr, this, &workThread)) {
186 return false;
187 }
6d2010ae 188 }
d190cdc3 189
0a7de745
A
190 (void) thread_set_tag(workThread, THREAD_TAG_IOWORKLOOP);
191 return true;
1c79356b
A
192}
193
194IOWorkLoop *
195IOWorkLoop::workLoop()
2d21ac55 196{
0a7de745 197 return IOWorkLoop::workLoopWithOptions(0);
2d21ac55
A
198}
199
200IOWorkLoop *
201IOWorkLoop::workLoopWithOptions(IOOptionBits options)
1c79356b 202{
6d2010ae 203 IOWorkLoop *me = new IOWorkLoop;
0a7de745 204
6d2010ae 205 if (me && options) {
0a7de745 206 me->reserved = IONew(ExpansionData, 1);
6d2010ae
A
207 if (!me->reserved) {
208 me->release();
cb323159 209 return NULL;
6d2010ae 210 }
0a7de745 211 bzero(me->reserved, sizeof(ExpansionData));
6d2010ae 212 me->reserved->options = options;
2d21ac55 213 }
0a7de745 214
6d2010ae
A
215 if (me && !me->init()) {
216 me->release();
cb323159 217 return NULL;
6d2010ae 218 }
0a7de745 219
6d2010ae 220 return me;
1c79356b
A
221}
222
223// Free is called twice:
224// First when the atomic retainCount transitions from 1 -> 0
225// Secondly when the work loop itself is commiting hari kari
226// Hence the each leg of the free must be single threaded.
0a7de745
A
227void
228IOWorkLoop::free()
1c79356b 229{
0a7de745
A
230 if (workThread) {
231 IOInterruptState is;
1c79356b 232
0a7de745
A
233 // If we are here then we must be trying to shut down this work loop
234 // in this case disable all of the event source, mark the loop
235 // as terminating and wakeup the work thread itself and return
236 // Note: we hold the gate across the entire operation mainly for the
237 // benefit of our event sources so we can disable them cleanly.
238 closeGate();
1c79356b 239
0a7de745 240 disableAllEventSources();
1c79356b 241
0a7de745
A
242 is = IOSimpleLockLockDisableInterrupt(workToDoLock);
243 SETP(&fFlags, kLoopTerminate);
244 thread_wakeup_thread((void *) &workToDo, workThread);
245 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
1c79356b 246
0a7de745
A
247 openGate();
248 } else { /* !workThread */
249 IOEventSource *event, *next;
1c79356b 250
0a7de745
A
251 for (event = eventChain; event; event = next) {
252 next = event->getNext();
cb323159
A
253 event->setWorkLoop(NULL);
254 event->setNext(NULL);
0a7de745
A
255 event->release();
256 }
cb323159 257 eventChain = NULL;
1c79356b 258
0a7de745
A
259 for (event = passiveEventChain; event; event = next) {
260 next = event->getNext();
cb323159
A
261 event->setWorkLoop(NULL);
262 event->setNext(NULL);
0a7de745
A
263 event->release();
264 }
cb323159 265 passiveEventChain = NULL;
0a7de745
A
266
267 // Either we have a partial initialization to clean up
268 // or the workThread itself is performing hari-kari.
269 // Either way clean up all of our resources and return.
270
271 if (controlG) {
cb323159 272 controlG->workLoop = NULL;
0a7de745 273 controlG->release();
cb323159 274 controlG = NULL;
0a7de745
A
275 }
276
277 if (workToDoLock) {
278 IOSimpleLockFree(workToDoLock);
cb323159 279 workToDoLock = NULL;
0a7de745
A
280 }
281
282 if (gateLock) {
283 IORecursiveLockFree(gateLock);
cb323159 284 gateLock = NULL;
0a7de745 285 }
1c79356b 286
0a7de745
A
287 IOStatisticsUnregisterCounter();
288
289 if (reserved) {
290 IODelete(reserved, ExpansionData, 1);
cb323159 291 reserved = NULL;
0a7de745
A
292 }
293
294 super::free();
295 }
1c79356b
A
296}
297
0a7de745
A
298IOReturn
299IOWorkLoop::addEventSource(IOEventSource *newEvent)
1c79356b 300{
0a7de745
A
301 if ((workThread)
302 && !thread_has_thread_name(workThread)
303 && (newEvent->owner)
304 && !OSDynamicCast(IOCommandPool, newEvent->owner)) {
305 thread_set_thread_name(workThread, newEvent->owner->getMetaClass()->getClassName());
306 }
39037602 307
0a7de745 308 return controlG->runCommand((void *) mAddEvent, (void *) newEvent);
1c79356b 309}
0a7de745
A
310
311IOReturn
312IOWorkLoop::removeEventSource(IOEventSource *toRemove)
1c79356b 313{
0a7de745 314 return controlG->runCommand((void *) mRemoveEvent, (void *) toRemove);
1c79356b
A
315}
316
0a7de745
A
317void
318IOWorkLoop::enableAllEventSources() const
1c79356b 319{
0a7de745 320 IOEventSource *event;
1c79356b 321
0a7de745
A
322 for (event = eventChain; event; event = event->getNext()) {
323 event->enable();
324 }
6d2010ae 325
0a7de745
A
326 for (event = passiveEventChain; event; event = event->getNext()) {
327 event->enable();
328 }
1c79356b
A
329}
330
0a7de745
A
331void
332IOWorkLoop::disableAllEventSources() const
1c79356b 333{
0a7de745 334 IOEventSource *event;
1c79356b 335
0a7de745 336 for (event = eventChain; event; event = event->getNext()) {
6d2010ae 337 event->disable();
0a7de745
A
338 }
339
6d2010ae 340 /* NOTE: controlG is in passiveEventChain since it's an IOCommandGate */
0a7de745
A
341 for (event = passiveEventChain; event; event = event->getNext()) {
342 if (event != controlG) { // Don't disable the control gate
343 event->disable();
344 }
345 }
1c79356b
A
346}
347
0a7de745
A
348void
349IOWorkLoop::enableAllInterrupts() const
1c79356b 350{
0a7de745
A
351 IOEventSource *event;
352
353 for (event = eventChain; event; event = event->getNext()) {
354 if (OSDynamicCast(IOInterruptEventSource, event)) {
355 event->enable();
356 }
357 }
1c79356b
A
358}
359
0a7de745
A
360void
361IOWorkLoop::disableAllInterrupts() const
1c79356b 362{
0a7de745
A
363 IOEventSource *event;
364
365 for (event = eventChain; event; event = event->getNext()) {
366 if (OSDynamicCast(IOInterruptEventSource, event)) {
367 event->disable();
368 }
369 }
1c79356b
A
370}
371
1c79356b 372
0a7de745
A
373/* virtual */ bool
374IOWorkLoop::runEventSources()
1c79356b 375{
0a7de745
A
376 bool res = false;
377 bool traceWL = (gIOKitTrace & kIOTraceWorkLoops) ? true : false;
378 bool traceES = (gIOKitTrace & kIOTraceEventSources) ? true : false;
379
380 closeGate();
381 if (ISSETP(&fFlags, kLoopTerminate)) {
6d2010ae 382 goto abort;
0a7de745
A
383 }
384
385 if (traceWL) {
5ba3f43e 386 IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_WORK), VM_KERNEL_ADDRHIDE(this));
0a7de745
A
387 }
388
389 bool more;
390 do {
6d2010ae
A
391 CLRP(&fFlags, kLoopRestart);
392 more = false;
393 IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
394 workToDo = false;
395 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
396 /* NOTE: only loop over event sources in eventChain. Bypass "passive" event sources for performance */
397 for (IOEventSource *evnt = eventChain; evnt; evnt = evnt->getNext()) {
0a7de745 398 if (traceES) {
5ba3f43e 399 IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_CLIENT), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(evnt));
0a7de745
A
400 }
401
6d2010ae 402 more |= evnt->checkForWork();
0a7de745
A
403
404 if (traceES) {
5ba3f43e 405 IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_CLIENT), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(evnt));
0a7de745
A
406 }
407
408 if (ISSETP(&fFlags, kLoopTerminate)) {
6d2010ae 409 goto abort;
0a7de745 410 } else if (fFlags & kLoopRestart) {
6d2010ae
A
411 more = true;
412 break;
413 }
414 }
0a7de745
A
415 } while (more);
416
417 res = true;
418
419 if (traceWL) {
5ba3f43e 420 IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_WORK), VM_KERNEL_ADDRHIDE(this));
0a7de745
A
421 }
422
0c530ab8 423abort:
0a7de745
A
424 openGate();
425 return res;
0c530ab8
A
426}
427
0a7de745
A
428/* virtual */ void
429IOWorkLoop::threadMain()
0c530ab8 430{
2d21ac55 431restartThread:
0a7de745
A
432 do {
433 if (!runEventSources()) {
434 goto exitThread;
435 }
436
437 IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
438 if (!ISSETP(&fFlags, kLoopTerminate) && !workToDo) {
439 assert_wait((void *) &workToDo, false);
440 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
441 thread_continue_t cptr = NULL;
442 if (!reserved || !(kPreciousStack & reserved->options)) {
443 cptr = OSMemberFunctionCast(
444 thread_continue_t, this, &IOWorkLoop::threadMain);
445 }
446 thread_block_parameter(cptr, this);
447 goto restartThread;
448 /* NOTREACHED */
449 }
1c79356b 450
0a7de745
A
451 // At this point we either have work to do or we need
452 // to commit suicide. But no matter
453 // Clear the simple lock and retore the interrupt state
454 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
455 } while (workToDo);
1c79356b
A
456
457exitThread:
0a7de745
A
458 closeGate();
459 thread_t thread = workThread;
cb323159 460 workThread = NULL; // Say we don't have a loop and free ourselves
0a7de745 461 openGate();
d9a64523 462
0a7de745 463 free();
b0d623f7 464
0a7de745
A
465 thread_deallocate(thread);
466 (void) thread_terminate(thread);
1c79356b
A
467}
468
0a7de745
A
469IOThread
470IOWorkLoop::getThread() const
1c79356b 471{
0a7de745 472 return workThread;
1c79356b
A
473}
474
0a7de745
A
475bool
476IOWorkLoop::onThread() const
1c79356b 477{
0a7de745 478 return IOThreadSelf() == workThread;
1c79356b
A
479}
480
0a7de745
A
481bool
482IOWorkLoop::inGate() const
1c79356b 483{
0a7de745 484 return IORecursiveLockHaveLock(gateLock);
1c79356b
A
485}
486
487// Internal APIs used by event sources to control the thread
0a7de745
A
488void
489IOWorkLoop::signalWorkAvailable()
1c79356b 490{
0a7de745
A
491 if (workToDoLock) {
492 IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
493 workToDo = true;
494 thread_wakeup_thread((void *) &workToDo, workThread);
495 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
496 }
1c79356b
A
497}
498
0a7de745
A
499void
500IOWorkLoop::openGate()
1c79356b 501{
0a7de745
A
502 IOStatisticsOpenGate();
503 IORecursiveLockUnlock(gateLock);
1c79356b
A
504}
505
0a7de745
A
506void
507IOWorkLoop::closeGate()
1c79356b 508{
0a7de745
A
509 IORecursiveLockLock(gateLock);
510 IOStatisticsCloseGate();
1c79356b
A
511}
512
0a7de745
A
513bool
514IOWorkLoop::tryCloseGate()
1c79356b 515{
0a7de745
A
516 bool res = (IORecursiveLockTryLock(gateLock) != 0);
517 if (res) {
518 IOStatisticsCloseGate();
519 }
520 return res;
1c79356b
A
521}
522
0a7de745
A
523int
524IOWorkLoop::sleepGate(void *event, UInt32 interuptibleType)
1c79356b 525{
0a7de745
A
526 int res;
527 IOStatisticsOpenGate();
528 res = IORecursiveLockSleep(gateLock, event, interuptibleType);
529 IOStatisticsCloseGate();
530 return res;
1c79356b
A
531}
532
0a7de745
A
533int
534IOWorkLoop::sleepGate(void *event, AbsoluteTime deadline, UInt32 interuptibleType)
b0d623f7 535{
0a7de745
A
536 int res;
537 IOStatisticsOpenGate();
538 res = IORecursiveLockSleepDeadline(gateLock, event, deadline, interuptibleType);
539 IOStatisticsCloseGate();
540 return res;
b0d623f7
A
541}
542
0a7de745
A
543void
544IOWorkLoop::wakeupGate(void *event, bool oneThread)
1c79356b 545{
0a7de745 546 IORecursiveLockWakeup(gateLock, event, oneThread);
1c79356b
A
547}
548
0a7de745
A
549static IOReturn
550IOWorkLoopActionToBlock(OSObject *owner,
551 void *arg0, void *arg1,
552 void *arg2, void *arg3)
d9a64523 553{
0a7de745 554 return ((IOWorkLoop::ActionBlock) arg0)();
d9a64523
A
555}
556
0a7de745
A
557IOReturn
558IOWorkLoop::runActionBlock(ActionBlock action)
d9a64523 559{
0a7de745 560 return runAction(&IOWorkLoopActionToBlock, this, action);
d9a64523
A
561}
562
0a7de745
A
563IOReturn
564IOWorkLoop::runAction(Action inAction, OSObject *target,
565 void *arg0, void *arg1,
566 void *arg2, void *arg3)
0b4e3aa0 567{
0a7de745 568 IOReturn res;
0b4e3aa0 569
0a7de745
A
570 // closeGate is recursive so don't worry if we already hold the lock.
571 closeGate();
572 res = (*inAction)(target, arg0, arg1, arg2, arg3);
573 openGate();
0b4e3aa0 574
0a7de745 575 return res;
0b4e3aa0
A
576}
577
0a7de745
A
578IOReturn
579IOWorkLoop::_maintRequest(void *inC, void *inD, void *, void *)
1c79356b 580{
0a7de745
A
581 maintCommandEnum command = (maintCommandEnum) (uintptr_t) inC;
582 IOEventSource *inEvent = (IOEventSource *) inD;
583 IOReturn res = kIOReturnSuccess;
584
585 switch (command) {
586 case mAddEvent:
587 if (!inEvent->getWorkLoop()) {
588 SETP(&fFlags, kLoopRestart);
589
590 inEvent->retain();
591 inEvent->setWorkLoop(this);
cb323159 592 inEvent->setNext(NULL);
0a7de745
A
593
594 /* Check if this is a passive or active event source being added */
595 if (eventSourcePerformsWork(inEvent)) {
596 if (!eventChain) {
597 eventChain = inEvent;
598 } else {
599 IOEventSource *event, *next;
600
601 for (event = eventChain; (next = event->getNext()); event = next) {
602 ;
603 }
604 event->setNext(inEvent);
605 }
606 } else {
607 if (!passiveEventChain) {
608 passiveEventChain = inEvent;
609 } else {
610 IOEventSource *event, *next;
611
612 for (event = passiveEventChain; (next = event->getNext()); event = next) {
613 ;
614 }
615 event->setNext(inEvent);
616 }
617 }
618 IOStatisticsAttachEventSource();
619 }
620 break;
6d2010ae 621
0a7de745
A
622 case mRemoveEvent:
623 if (inEvent->getWorkLoop()) {
624 IOStatisticsDetachEventSource();
1c79356b 625
0a7de745
A
626 if (eventSourcePerformsWork(inEvent)) {
627 if (eventChain == inEvent) {
6d2010ae 628 eventChain = inEvent->getNext();
0a7de745 629 } else {
cb323159 630 IOEventSource *event, *next = NULL;
0a7de745 631
6d2010ae 632 event = eventChain;
0a7de745
A
633 if (event) {
634 while ((next = event->getNext()) && (next != inEvent)) {
635 event = next;
636 }
637 }
638
6d2010ae
A
639 if (!next) {
640 res = kIOReturnBadArgument;
641 break;
642 }
643 event->setNext(inEvent->getNext());
644 }
0a7de745
A
645 } else {
646 if (passiveEventChain == inEvent) {
6d2010ae 647 passiveEventChain = inEvent->getNext();
0a7de745 648 } else {
cb323159 649 IOEventSource *event, *next = NULL;
0a7de745 650
6d2010ae 651 event = passiveEventChain;
0a7de745
A
652 if (event) {
653 while ((next = event->getNext()) && (next != inEvent)) {
654 event = next;
655 }
656 }
657
6d2010ae
A
658 if (!next) {
659 res = kIOReturnBadArgument;
660 break;
661 }
662 event->setNext(inEvent->getNext());
663 }
0a7de745
A
664 }
665
cb323159
A
666 inEvent->setWorkLoop(NULL);
667 inEvent->setNext(NULL);
0a7de745
A
668 inEvent->release();
669 SETP(&fFlags, kLoopRestart);
670 }
671 break;
1c79356b 672
0a7de745
A
673 default:
674 return kIOReturnUnsupported;
675 }
1c79356b 676
0a7de745 677 return res;
1c79356b 678}
6d2010ae
A
679
680bool
681IOWorkLoop::eventSourcePerformsWork(IOEventSource *inEventSource)
682{
0a7de745 683 bool result = true;
6d2010ae
A
684
685 /*
686 * The idea here is to see if the subclass of IOEventSource has overridden checkForWork().
687 * The assumption is that if you override checkForWork(), you need to be
688 * active and not passive.
689 *
690 * We picked a known quantity controlG that does not override
691 * IOEventSource::checkForWork(), namely the IOCommandGate associated with
692 * the workloop to which this event source is getting attached.
0a7de745 693 *
6d2010ae
A
694 * We do a pointer comparison on the offset in the vtable for inNewEvent against
695 * the offset in the vtable for inReferenceEvent. This works because
696 * IOCommandGate's slot for checkForWork() has the address of
697 * IOEventSource::checkForWork() in it.
0a7de745 698 *
6d2010ae
A
699 * Think of OSMemberFunctionCast yielding the value at the vtable offset for
700 * checkForWork() here. We're just testing to see if it's the same or not.
701 *
702 */
5ba3f43e 703
0a7de745
A
704 if (IOEventSource::kPassive & inEventSource->flags) {
705 result = false;
706 } else if (IOEventSource::kActive & inEventSource->flags) {
707 result = true;
708 } else if (controlG) {
709 void * ptr1;
710 void * ptr2;
711
6d2010ae
A
712 ptr1 = OSMemberFunctionCast(void*, inEventSource, &IOEventSource::checkForWork);
713 ptr2 = OSMemberFunctionCast(void*, controlG, &IOEventSource::checkForWork);
0a7de745
A
714
715 if (ptr1 == ptr2) {
6d2010ae 716 result = false;
0a7de745 717 }
6d2010ae 718 }
0a7de745
A
719
720 return result;
6d2010ae 721}
39037602
A
722
723void
724IOWorkLoop::lockTime(void)
725{
0a7de745
A
726 uint64_t time;
727 time = mach_absolute_time() - reserved->lockTime;
728 if (time > reserved->lockInterval) {
729 absolutetime_to_nanoseconds(time, &time);
730 if (kTimeLockPanics & reserved->options) {
731 panic("IOWorkLoop %p lock time %qd us", this, time / 1000ULL);
732 } else {
733 OSReportWithBacktrace("IOWorkLoop %p lock time %qd us", this, time / 1000ULL);
734 }
735 }
39037602
A
736}
737
738void
739IOWorkLoop::setMaximumLockTime(uint64_t interval, uint32_t options)
740{
0a7de745
A
741 IORecursiveLockLock(gateLock);
742 reserved->lockInterval = interval;
743 reserved->options = (reserved->options & ~kTimeLockPanics) | (options & kTimeLockPanics);
744 IORecursiveLockUnlock(gateLock);
39037602 745}