bool gCPUsRunning;
static thread_t gIOTerminateThread;
+static thread_t gIOTerminateWorkerThread;
static UInt32 gIOTerminateWork;
static OSArray * gIOTerminatePhase2List;
static OSArray * gIOStopList;
gIOStopProviderList = OSArray::withCapacity( 16 );
gIOFinalizeList = OSArray::withCapacity( 16 );
assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList );
+
+ // worker thread that is responsible for terminating / cleaning up threads
+ kernel_thread_start(&terminateThread, NULL, &gIOTerminateWorkerThread);
+ assert(gIOTerminateWorkerThread);
+ thread_set_thread_name(gIOTerminateWorkerThread, "IOServiceTerminateThread");
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
}
}
+// Must call this while holding gJobsLock
+void IOService::waitToBecomeTerminateThread(void)
+{
+ IOLockAssert(gJobsLock, kIOLockAssertOwned);
+ bool wait;
+ do {
+ wait = (gIOTerminateThread != THREAD_NULL);
+ if (wait) {
+ IOLockSleep(gJobsLock, &gIOTerminateThread, THREAD_UNINT);
+ }
+ } while (wait);
+ gIOTerminateThread = current_thread();
+}
+
// call with lockForArbitration
void IOService::scheduleTerminatePhase2( IOOptionBits options )
{
AbsoluteTime deadline;
uint64_t regID1;
int waitResult = THREAD_AWAKENED;
- bool wait, haveDeadline = false;
+ bool wait = false, haveDeadline = false;
if (!(__state[0] & kIOServiceInactiveState)) return;
if( (options & kIOServiceSynchronous)
&& (current_thread() != gIOTerminateThread)) {
- do {
- wait = (gIOTerminateThread != 0);
- if( wait) {
- // wait to become the terminate thread
- IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT);
- }
- } while( wait );
-
- gIOTerminateThread = current_thread();
+ waitToBecomeTerminateThread();
gIOTerminatePhase2List->setObject( this );
gIOTerminateWork++;
}
waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork,
deadline, THREAD_UNINT );
- if( waitResult == THREAD_TIMED_OUT) {
- IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous) timeout\n", getName(), getRegistryEntryID());
+ if(__improbable(waitResult == THREAD_TIMED_OUT)) {
+ panic("%s[0x%qx]::terminate(kIOServiceSynchronous) timeout\n", getName(), getRegistryEntryID());
}
}
} while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT)));
gIOTerminatePhase2List->setObject( this );
if( 0 == gIOTerminateWork++) {
- if( !gIOTerminateThread)
- kernel_thread_start(&terminateThread, (void *)(uintptr_t) options, &gIOTerminateThread);
- else
- IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
- }
+ assert(gIOTerminateWorkerThread);
+ IOLockWakeup(gJobsLock, (event_t)&gIOTerminateWork, /* one-thread */ false );
+ }
}
IOLockUnlock( gJobsLock );
release();
}
+__attribute__((__noreturn__))
void IOService::terminateThread( void * arg, wait_result_t waitResult )
{
- IOLockLock( gJobsLock );
-
- while (gIOTerminateWork)
- terminateWorker( (uintptr_t) arg );
+ // IOLockSleep re-acquires the lock on wakeup, so we only need to do this once
+ IOLockLock(gJobsLock);
+ while (true) {
+ if (gIOTerminateThread != gIOTerminateWorkerThread) {
+ waitToBecomeTerminateThread();
+ }
- thread_deallocate(gIOTerminateThread);
- gIOTerminateThread = 0;
- IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
+ while (gIOTerminateWork)
+ terminateWorker( (uintptr_t)arg );
- IOLockUnlock( gJobsLock );
+ gIOTerminateThread = 0;
+ IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
+ IOLockSleep(gJobsLock, &gIOTerminateWork, THREAD_UNINT);
+ }
}
void IOService::scheduleStop( IOService * provider )
gIOStopProviderList->tailQ( provider );
if( 0 == gIOTerminateWork++) {
- if( !gIOTerminateThread)
- kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread);
- else
- IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
+ assert(gIOTerminateWorkerThread);
+ IOLockWakeup(gJobsLock, (event_t)&gIOTerminateWork, /* one-thread */ false );
}
IOLockUnlock( gJobsLock );
{
IOLockLock( gJobsLock );
gIOFinalizeList->tailQ(this);
- if( 0 == gIOTerminateWork++)
- {
- if( !gIOTerminateThread)
- kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread);
- else
- IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
+ if( 0 == gIOTerminateWork++) {
+ assert(gIOTerminateWorkerThread);
+ IOLockWakeup(gJobsLock, (event_t)&gIOTerminateWork, /* one-thread */ false );
}
IOLockUnlock( gJobsLock );
}
OSString * str;
OSSet * set;
OSIterator * iter;
+ OSObject * obj;
OSArray * keys;
bool ok = true;
}
else if ((prop = table->getObject(gIOResourceMatchedKey)))
{
- keys = (OSArray *) copyProperty(gIOResourceMatchedKey);
+ obj = copyProperty(gIOResourceMatchedKey);
+ keys = OSDynamicCast(OSArray, obj);
ok = false;
if (keys)
{
// assuming OSSymbol
ok = ((-1U) != keys->getNextIndexOfObject(prop, 0));
- keys->release();
}
+ OSSafeReleaseNULL(obj);
}
return( ok );