#include <IOKit/IOEventSource.h>
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/IOCommandGate.h>
+#include <IOKit/IOCommandPool.h>
#include <IOKit/IOTimeStamp.h>
#include <IOKit/IOKitDebug.h>
#include <libkern/OSDebug.h>
+#include <kern/thread.h>
#define super OSObject
#define IOStatisticsOpenGate() \
do { \
IOStatistics::countWorkLoopOpenGate(reserved->counter); \
+ if (reserved->lockInterval) lockTime(); \
} while(0)
-
#define IOStatisticsCloseGate() \
do { \
- IOStatistics::countWorkLoopCloseGate(reserved->counter); \
+ IOStatistics::countWorkLoopCloseGate(reserved->counter); \
+ if (reserved->lockInterval) reserved->lockTime = mach_absolute_time(); \
} while(0)
#define IOStatisticsAttachEventSource() \
bzero(reserved,sizeof(ExpansionData));
}
-
-#if DEBUG
- OSBacktrace ( reserved->allocationBacktrace, sizeof ( reserved->allocationBacktrace ) / sizeof ( reserved->allocationBacktrace[0] ) );
-#endif
-
+
if ( gateLock == NULL ) {
if ( !( gateLock = IORecursiveLockAlloc()) )
return false;
workToDo = false;
}
- if (!reserved) {
- reserved = IONew(ExpansionData, 1);
- reserved->options = 0;
- }
-
IOStatisticsRegisterCounter();
if ( controlG == NULL ) {
return false;
}
+ (void) thread_set_tag(workThread, THREAD_TAG_IOWORKLOOP);
return true;
}
is = IOSimpleLockLockDisableInterrupt(workToDoLock);
SETP(&fFlags, kLoopTerminate);
- thread_wakeup_one((void *) &workToDo);
+ thread_wakeup_thread((void *) &workToDo, workThread);
IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
openGate();
// Either way clean up all of our resources and return.
if (controlG) {
+ controlG->workLoop = 0;
controlG->release();
controlG = 0;
}
IOReturn IOWorkLoop::addEventSource(IOEventSource *newEvent)
{
+ if ((workThread)
+ && !thread_has_thread_name(workThread)
+ && (newEvent->owner)
+ && !OSDynamicCast(IOCommandPool, newEvent->owner)) {
+ thread_set_thread_name(workThread, newEvent->owner->getMetaClass()->getClassName());
+ }
+
return controlG->runCommand((void *) mAddEvent, (void *) newEvent);
}
goto abort;
if (traceWL)
- IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_WORK), (uintptr_t) this);
+ IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_WORK), VM_KERNEL_ADDRHIDE(this));
bool more;
do {
for (IOEventSource *evnt = eventChain; evnt; evnt = evnt->getNext()) {
if (traceES)
- IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_CLIENT), (uintptr_t) this, (uintptr_t) evnt);
+ IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_CLIENT), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(evnt));
more |= evnt->checkForWork();
if (traceES)
- IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_CLIENT), (uintptr_t) this, (uintptr_t) evnt);
+ IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_CLIENT), VM_KERNEL_ADDRHIDE(this), VM_KERNEL_ADDRHIDE(evnt));
if (ISSETP(&fFlags, kLoopTerminate))
goto abort;
res = true;
if (traceWL)
- IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_WORK), (uintptr_t) this);
+ IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_WORK), VM_KERNEL_ADDRHIDE(this));
abort:
openGate();
if (workToDoLock) {
IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock);
workToDo = true;
- thread_wakeup_one((void *) &workToDo);
+ thread_wakeup_thread((void *) &workToDo, workThread);
IOSimpleLockUnlockEnableInterrupt(workToDoLock, is);
}
}
case mRemoveEvent:
if (inEvent->getWorkLoop()) {
+ IOStatisticsDetachEventSource();
+
if (eventSourcePerformsWork(inEvent)) {
if (eventChain == inEvent)
eventChain = inEvent->getNext();
else {
- IOEventSource *event, *next;
+ IOEventSource *event, *next = 0;
event = eventChain;
- while ((next = event->getNext()) && next != inEvent)
+ if (event) while ((next = event->getNext()) && (next != inEvent))
event = next;
if (!next) {
if (passiveEventChain == inEvent)
passiveEventChain = inEvent->getNext();
else {
- IOEventSource *event, *next;
+ IOEventSource *event, *next = 0;
event = passiveEventChain;
- while ((next = event->getNext()) && next != inEvent)
+ if (event) while ((next = event->getNext()) && (next != inEvent))
event = next;
if (!next) {
inEvent->setNext(0);
inEvent->release();
SETP(&fFlags, kLoopRestart);
- IOStatisticsDetachEventSource();
}
break;
* checkForWork() here. We're just testing to see if it's the same or not.
*
*/
- if (controlG) {
+
+ if (IOEventSource::kPassive & inEventSource->flags) result = false;
+ else if (IOEventSource::kActive & inEventSource->flags) result = true;
+ else if (controlG) {
void * ptr1;
void * ptr2;
return result;
}
+
+void
+IOWorkLoop::lockTime(void)
+{
+ uint64_t time;
+ time = mach_absolute_time() - reserved->lockTime;
+ if (time > reserved->lockInterval)
+ {
+ absolutetime_to_nanoseconds(time, &time);
+ if (kTimeLockPanics & reserved->options) panic("IOWorkLoop %p lock time %qd us", this, time / 1000ULL);
+ else OSReportWithBacktrace("IOWorkLoop %p lock time %qd us", this, time / 1000ULL);
+ }
+}
+
+void
+IOWorkLoop::setMaximumLockTime(uint64_t interval, uint32_t options)
+{
+ IORecursiveLockLock(gateLock);
+ reserved->lockInterval = interval;
+ reserved->options = (reserved->options & ~kTimeLockPanics) | (options & kTimeLockPanics);
+ IORecursiveLockUnlock(gateLock);
+}