]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOWorkLoop.cpp
xnu-7195.50.7.100.1.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
f427ee49
A
50OSMetaClassDefineReservedUsedX86(IOWorkLoop, 0);
51OSMetaClassDefineReservedUsedX86(IOWorkLoop, 1);
52OSMetaClassDefineReservedUsedX86(IOWorkLoop, 2);
b0d623f7 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
f427ee49
A
223void
224IOWorkLoop::releaseEventChain(LIBKERN_CONSUMED IOEventSource *eventChain)
225{
226 IOEventSource *event, *next;
227 for (event = eventChain; event; event = next) {
228 next = event->getNext();
229#ifdef __clang_analyzer__
230 // Unlike the usual IOKit memory management convention, IOWorkLoop
231 // manages the retain count for the IOEventSource instances in the
232 // the chain rather than have IOEventSource do that itself. This means
233 // it is safe to call release() on the result of getNext() while the
234 // chain is being torn down. However, the analyzer doesn't
235 // realize this. We add an extra retain under analysis to suppress
236 // an analyzer diagnostic about violations of the memory management rules.
237 if (next) {
238 next->retain();
239 }
240#endif
241 event->setWorkLoop(NULL);
242 event->setNext(NULL);
243 event->release();
244 }
245}
1c79356b
A
246// Free is called twice:
247// First when the atomic retainCount transitions from 1 -> 0
248// Secondly when the work loop itself is commiting hari kari
249// Hence the each leg of the free must be single threaded.
0a7de745
A
250void
251IOWorkLoop::free()
1c79356b 252{
0a7de745
A
253 if (workThread) {
254 IOInterruptState is;
1c79356b 255
0a7de745
A
256 // If we are here then we must be trying to shut down this work loop
257 // in this case disable all of the event source, mark the loop
258 // as terminating and wakeup the work thread itself and return
259 // Note: we hold the gate across the entire operation mainly for the
260 // benefit of our event sources so we can disable them cleanly.
261 closeGate();
1c79356b 262
0a7de745 263 disableAllEventSources();
1c79356b 264
0a7de745
A
265 is = IOSimpleLockLockDisableInterrupt(workToDoLock);
266 SETP(&fFlags, kLoopTerminate);
267 thread_wakeup_thread((void *) &workToDo, workThread);
268 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
1c79356b 269
0a7de745
A
270 openGate();
271 } else { /* !workThread */
f427ee49 272 releaseEventChain(eventChain);
cb323159 273 eventChain = NULL;
1c79356b 274
f427ee49 275 releaseEventChain(passiveEventChain);
cb323159 276 passiveEventChain = NULL;
0a7de745
A
277
278 // Either we have a partial initialization to clean up
279 // or the workThread itself is performing hari-kari.
280 // Either way clean up all of our resources and return.
281
282 if (controlG) {
cb323159 283 controlG->workLoop = NULL;
0a7de745 284 controlG->release();
cb323159 285 controlG = NULL;
0a7de745
A
286 }
287
288 if (workToDoLock) {
289 IOSimpleLockFree(workToDoLock);
cb323159 290 workToDoLock = NULL;
0a7de745
A
291 }
292
293 if (gateLock) {
294 IORecursiveLockFree(gateLock);
cb323159 295 gateLock = NULL;
0a7de745 296 }
1c79356b 297
0a7de745
A
298 IOStatisticsUnregisterCounter();
299
300 if (reserved) {
301 IODelete(reserved, ExpansionData, 1);
cb323159 302 reserved = NULL;
0a7de745
A
303 }
304
305 super::free();
306 }
1c79356b
A
307}
308
0a7de745
A
309IOReturn
310IOWorkLoop::addEventSource(IOEventSource *newEvent)
1c79356b 311{
0a7de745
A
312 if ((workThread)
313 && !thread_has_thread_name(workThread)
314 && (newEvent->owner)
315 && !OSDynamicCast(IOCommandPool, newEvent->owner)) {
316 thread_set_thread_name(workThread, newEvent->owner->getMetaClass()->getClassName());
317 }
39037602 318
0a7de745 319 return controlG->runCommand((void *) mAddEvent, (void *) newEvent);
1c79356b 320}
0a7de745
A
321
322IOReturn
323IOWorkLoop::removeEventSource(IOEventSource *toRemove)
1c79356b 324{
0a7de745 325 return controlG->runCommand((void *) mRemoveEvent, (void *) toRemove);
1c79356b
A
326}
327
0a7de745
A
328void
329IOWorkLoop::enableAllEventSources() const
1c79356b 330{
0a7de745 331 IOEventSource *event;
1c79356b 332
0a7de745
A
333 for (event = eventChain; event; event = event->getNext()) {
334 event->enable();
335 }
6d2010ae 336
0a7de745
A
337 for (event = passiveEventChain; event; event = event->getNext()) {
338 event->enable();
339 }
1c79356b
A
340}
341
0a7de745
A
342void
343IOWorkLoop::disableAllEventSources() const
1c79356b 344{
0a7de745 345 IOEventSource *event;
1c79356b 346
0a7de745 347 for (event = eventChain; event; event = event->getNext()) {
6d2010ae 348 event->disable();
0a7de745
A
349 }
350
6d2010ae 351 /* NOTE: controlG is in passiveEventChain since it's an IOCommandGate */
0a7de745
A
352 for (event = passiveEventChain; event; event = event->getNext()) {
353 if (event != controlG) { // Don't disable the control gate
354 event->disable();
355 }
356 }
1c79356b
A
357}
358
0a7de745
A
359void
360IOWorkLoop::enableAllInterrupts() const
1c79356b 361{
0a7de745
A
362 IOEventSource *event;
363
364 for (event = eventChain; event; event = event->getNext()) {
365 if (OSDynamicCast(IOInterruptEventSource, event)) {
366 event->enable();
367 }
368 }
1c79356b
A
369}
370
0a7de745
A
371void
372IOWorkLoop::disableAllInterrupts() const
1c79356b 373{
0a7de745
A
374 IOEventSource *event;
375
376 for (event = eventChain; event; event = event->getNext()) {
377 if (OSDynamicCast(IOInterruptEventSource, event)) {
378 event->disable();
379 }
380 }
1c79356b
A
381}
382
1c79356b 383
0a7de745
A
384/* virtual */ bool
385IOWorkLoop::runEventSources()
1c79356b 386{
0a7de745
A
387 bool res = false;
388 bool traceWL = (gIOKitTrace & kIOTraceWorkLoops) ? true : false;
389 bool traceES = (gIOKitTrace & kIOTraceEventSources) ? true : false;
390
391 closeGate();
392 if (ISSETP(&fFlags, kLoopTerminate)) {
6d2010ae 393 goto abort;
0a7de745
A
394 }
395
396 if (traceWL) {
5ba3f43e 397 IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_WORK), VM_KERNEL_ADDRHIDE(this));
0a7de745
A
398 }
399
400 bool more;
401 do {
6d2010ae
A
402 CLRP(&fFlags, kLoopRestart);
403 more = false;
404 IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
405 workToDo = false;
406 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
407 /* NOTE: only loop over event sources in eventChain. Bypass "passive" event sources for performance */
408 for (IOEventSource *evnt = eventChain; evnt; evnt = evnt->getNext()) {
0a7de745 409 if (traceES) {
5ba3f43e 410 IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_CLIENT), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(evnt));
0a7de745
A
411 }
412
6d2010ae 413 more |= evnt->checkForWork();
0a7de745
A
414
415 if (traceES) {
5ba3f43e 416 IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_CLIENT), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(evnt));
0a7de745
A
417 }
418
419 if (ISSETP(&fFlags, kLoopTerminate)) {
6d2010ae 420 goto abort;
0a7de745 421 } else if (fFlags & kLoopRestart) {
6d2010ae
A
422 more = true;
423 break;
424 }
425 }
0a7de745
A
426 } while (more);
427
428 res = true;
429
430 if (traceWL) {
5ba3f43e 431 IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_WORK), VM_KERNEL_ADDRHIDE(this));
0a7de745
A
432 }
433
0c530ab8 434abort:
0a7de745
A
435 openGate();
436 return res;
0c530ab8
A
437}
438
0a7de745
A
439/* virtual */ void
440IOWorkLoop::threadMain()
0c530ab8 441{
2d21ac55 442restartThread:
0a7de745
A
443 do {
444 if (!runEventSources()) {
445 goto exitThread;
446 }
447
448 IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
449 if (!ISSETP(&fFlags, kLoopTerminate) && !workToDo) {
450 assert_wait((void *) &workToDo, false);
451 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
452 thread_continue_t cptr = NULL;
453 if (!reserved || !(kPreciousStack & reserved->options)) {
454 cptr = OSMemberFunctionCast(
455 thread_continue_t, this, &IOWorkLoop::threadMain);
456 }
457 thread_block_parameter(cptr, this);
458 goto restartThread;
459 /* NOTREACHED */
460 }
1c79356b 461
0a7de745
A
462 // At this point we either have work to do or we need
463 // to commit suicide. But no matter
464 // Clear the simple lock and retore the interrupt state
465 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
466 } while (workToDo);
1c79356b
A
467
468exitThread:
0a7de745
A
469 closeGate();
470 thread_t thread = workThread;
cb323159 471 workThread = NULL; // Say we don't have a loop and free ourselves
0a7de745 472 openGate();
d9a64523 473
0a7de745 474 free();
b0d623f7 475
0a7de745
A
476 thread_deallocate(thread);
477 (void) thread_terminate(thread);
1c79356b
A
478}
479
0a7de745
A
480IOThread
481IOWorkLoop::getThread() const
1c79356b 482{
0a7de745 483 return workThread;
1c79356b
A
484}
485
0a7de745
A
486bool
487IOWorkLoop::onThread() const
1c79356b 488{
0a7de745 489 return IOThreadSelf() == workThread;
1c79356b
A
490}
491
0a7de745
A
492bool
493IOWorkLoop::inGate() const
1c79356b 494{
0a7de745 495 return IORecursiveLockHaveLock(gateLock);
1c79356b
A
496}
497
498// Internal APIs used by event sources to control the thread
0a7de745
A
499void
500IOWorkLoop::signalWorkAvailable()
1c79356b 501{
0a7de745
A
502 if (workToDoLock) {
503 IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
504 workToDo = true;
505 thread_wakeup_thread((void *) &workToDo, workThread);
506 IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
507 }
1c79356b
A
508}
509
0a7de745
A
510void
511IOWorkLoop::openGate()
1c79356b 512{
0a7de745
A
513 IOStatisticsOpenGate();
514 IORecursiveLockUnlock(gateLock);
1c79356b
A
515}
516
0a7de745
A
517void
518IOWorkLoop::closeGate()
1c79356b 519{
0a7de745
A
520 IORecursiveLockLock(gateLock);
521 IOStatisticsCloseGate();
1c79356b
A
522}
523
0a7de745
A
524bool
525IOWorkLoop::tryCloseGate()
1c79356b 526{
0a7de745
A
527 bool res = (IORecursiveLockTryLock(gateLock) != 0);
528 if (res) {
529 IOStatisticsCloseGate();
530 }
531 return res;
1c79356b
A
532}
533
0a7de745
A
534int
535IOWorkLoop::sleepGate(void *event, UInt32 interuptibleType)
1c79356b 536{
0a7de745
A
537 int res;
538 IOStatisticsOpenGate();
539 res = IORecursiveLockSleep(gateLock, event, interuptibleType);
540 IOStatisticsCloseGate();
541 return res;
1c79356b
A
542}
543
0a7de745
A
544int
545IOWorkLoop::sleepGate(void *event, AbsoluteTime deadline, UInt32 interuptibleType)
b0d623f7 546{
0a7de745
A
547 int res;
548 IOStatisticsOpenGate();
549 res = IORecursiveLockSleepDeadline(gateLock, event, deadline, interuptibleType);
550 IOStatisticsCloseGate();
551 return res;
b0d623f7
A
552}
553
0a7de745
A
554void
555IOWorkLoop::wakeupGate(void *event, bool oneThread)
1c79356b 556{
0a7de745 557 IORecursiveLockWakeup(gateLock, event, oneThread);
1c79356b
A
558}
559
0a7de745
A
560static IOReturn
561IOWorkLoopActionToBlock(OSObject *owner,
562 void *arg0, void *arg1,
563 void *arg2, void *arg3)
d9a64523 564{
0a7de745 565 return ((IOWorkLoop::ActionBlock) arg0)();
d9a64523
A
566}
567
0a7de745
A
568IOReturn
569IOWorkLoop::runActionBlock(ActionBlock action)
d9a64523 570{
0a7de745 571 return runAction(&IOWorkLoopActionToBlock, this, action);
d9a64523
A
572}
573
0a7de745
A
574IOReturn
575IOWorkLoop::runAction(Action inAction, OSObject *target,
576 void *arg0, void *arg1,
577 void *arg2, void *arg3)
0b4e3aa0 578{
0a7de745 579 IOReturn res;
0b4e3aa0 580
0a7de745
A
581 // closeGate is recursive so don't worry if we already hold the lock.
582 closeGate();
583 res = (*inAction)(target, arg0, arg1, arg2, arg3);
584 openGate();
0b4e3aa0 585
0a7de745 586 return res;
0b4e3aa0
A
587}
588
0a7de745
A
589IOReturn
590IOWorkLoop::_maintRequest(void *inC, void *inD, void *, void *)
1c79356b 591{
0a7de745
A
592 maintCommandEnum command = (maintCommandEnum) (uintptr_t) inC;
593 IOEventSource *inEvent = (IOEventSource *) inD;
594 IOReturn res = kIOReturnSuccess;
595
596 switch (command) {
597 case mAddEvent:
598 if (!inEvent->getWorkLoop()) {
599 SETP(&fFlags, kLoopRestart);
600
601 inEvent->retain();
602 inEvent->setWorkLoop(this);
cb323159 603 inEvent->setNext(NULL);
0a7de745
A
604
605 /* Check if this is a passive or active event source being added */
606 if (eventSourcePerformsWork(inEvent)) {
607 if (!eventChain) {
608 eventChain = inEvent;
609 } else {
610 IOEventSource *event, *next;
611
612 for (event = eventChain; (next = event->getNext()); event = next) {
613 ;
614 }
615 event->setNext(inEvent);
616 }
617 } else {
618 if (!passiveEventChain) {
619 passiveEventChain = inEvent;
620 } else {
621 IOEventSource *event, *next;
622
623 for (event = passiveEventChain; (next = event->getNext()); event = next) {
624 ;
625 }
626 event->setNext(inEvent);
627 }
628 }
629 IOStatisticsAttachEventSource();
630 }
631 break;
6d2010ae 632
0a7de745
A
633 case mRemoveEvent:
634 if (inEvent->getWorkLoop()) {
635 IOStatisticsDetachEventSource();
1c79356b 636
0a7de745
A
637 if (eventSourcePerformsWork(inEvent)) {
638 if (eventChain == inEvent) {
6d2010ae 639 eventChain = inEvent->getNext();
0a7de745 640 } else {
cb323159 641 IOEventSource *event, *next = NULL;
0a7de745 642
6d2010ae 643 event = eventChain;
0a7de745
A
644 if (event) {
645 while ((next = event->getNext()) && (next != inEvent)) {
646 event = next;
647 }
648 }
649
6d2010ae
A
650 if (!next) {
651 res = kIOReturnBadArgument;
652 break;
653 }
654 event->setNext(inEvent->getNext());
655 }
0a7de745
A
656 } else {
657 if (passiveEventChain == inEvent) {
6d2010ae 658 passiveEventChain = inEvent->getNext();
0a7de745 659 } else {
cb323159 660 IOEventSource *event, *next = NULL;
0a7de745 661
6d2010ae 662 event = passiveEventChain;
0a7de745
A
663 if (event) {
664 while ((next = event->getNext()) && (next != inEvent)) {
665 event = next;
666 }
667 }
668
6d2010ae
A
669 if (!next) {
670 res = kIOReturnBadArgument;
671 break;
672 }
673 event->setNext(inEvent->getNext());
674 }
0a7de745
A
675 }
676
cb323159
A
677 inEvent->setWorkLoop(NULL);
678 inEvent->setNext(NULL);
0a7de745
A
679 inEvent->release();
680 SETP(&fFlags, kLoopRestart);
681 }
682 break;
1c79356b 683
0a7de745
A
684 default:
685 return kIOReturnUnsupported;
686 }
1c79356b 687
0a7de745 688 return res;
1c79356b 689}
6d2010ae
A
690
691bool
692IOWorkLoop::eventSourcePerformsWork(IOEventSource *inEventSource)
693{
0a7de745 694 bool result = true;
6d2010ae
A
695
696 /*
697 * The idea here is to see if the subclass of IOEventSource has overridden checkForWork().
698 * The assumption is that if you override checkForWork(), you need to be
699 * active and not passive.
700 *
701 * We picked a known quantity controlG that does not override
702 * IOEventSource::checkForWork(), namely the IOCommandGate associated with
703 * the workloop to which this event source is getting attached.
0a7de745 704 *
6d2010ae
A
705 * We do a pointer comparison on the offset in the vtable for inNewEvent against
706 * the offset in the vtable for inReferenceEvent. This works because
707 * IOCommandGate's slot for checkForWork() has the address of
708 * IOEventSource::checkForWork() in it.
0a7de745 709 *
6d2010ae
A
710 * Think of OSMemberFunctionCast yielding the value at the vtable offset for
711 * checkForWork() here. We're just testing to see if it's the same or not.
712 *
713 */
5ba3f43e 714
0a7de745
A
715 if (IOEventSource::kPassive & inEventSource->flags) {
716 result = false;
717 } else if (IOEventSource::kActive & inEventSource->flags) {
718 result = true;
719 } else if (controlG) {
720 void * ptr1;
721 void * ptr2;
722
6d2010ae
A
723 ptr1 = OSMemberFunctionCast(void*, inEventSource, &IOEventSource::checkForWork);
724 ptr2 = OSMemberFunctionCast(void*, controlG, &IOEventSource::checkForWork);
0a7de745
A
725
726 if (ptr1 == ptr2) {
6d2010ae 727 result = false;
0a7de745 728 }
6d2010ae 729 }
0a7de745
A
730
731 return result;
6d2010ae 732}
39037602
A
733
734void
735IOWorkLoop::lockTime(void)
736{
0a7de745
A
737 uint64_t time;
738 time = mach_absolute_time() - reserved->lockTime;
739 if (time > reserved->lockInterval) {
740 absolutetime_to_nanoseconds(time, &time);
741 if (kTimeLockPanics & reserved->options) {
742 panic("IOWorkLoop %p lock time %qd us", this, time / 1000ULL);
743 } else {
744 OSReportWithBacktrace("IOWorkLoop %p lock time %qd us", this, time / 1000ULL);
745 }
746 }
39037602
A
747}
748
749void
750IOWorkLoop::setMaximumLockTime(uint64_t interval, uint32_t options)
751{
0a7de745
A
752 IORecursiveLockLock(gateLock);
753 reserved->lockInterval = interval;
754 reserved->options = (reserved->options & ~kTimeLockPanics) | (options & kTimeLockPanics);
755 IORecursiveLockUnlock(gateLock);
39037602 756}