void CacheIOThread::LoopOneLevel(uint32_t aLevel) { eventtracer::AutoEventTracer tracer(this, eventtracer::eExec, eventtracer::eDone, sLevelTraceName[aLevel]); nsTArray<nsRefPtr<nsIRunnable> > events; events.SwapElements(mEventQueue[aLevel]); uint32_t length = events.Length(); bool returnEvents = false; uint32_t index; { MonitorAutoUnlock unlock(mMonitor); for (index = 0; index < length; ++index) { if (EventsPending(aLevel)) { // Somebody scheduled a new event on a lower level, break and harry // to execute it! Don't forget to return what we haven't exec. returnEvents = true; break; } events[index]->Run(); events[index] = nullptr; } } if (returnEvents) mEventQueue[aLevel].InsertElementsAt(0, events.Elements() + index, length - index); }
void CacheIOThread::LoopOneLevel(uint32_t aLevel) { EventQueue events; events.SwapElements(mEventQueue[aLevel]); EventQueue::size_type length = events.Length(); mCurrentlyExecutingLevel = aLevel; bool returnEvents = false; bool reportTelementry = true; EventQueue::size_type index; { MonitorAutoUnlock unlock(mMonitor); for (index = 0; index < length; ++index) { if (EventsPending(aLevel)) { // Somebody scheduled a new event on a lower level, break and harry // to execute it! Don't forget to return what we haven't exec. returnEvents = true; break; } if (reportTelementry) { reportTelementry = false; CacheIOTelemetry::Report(aLevel, length); } // Drop any previous flagging, only an event on the current level may set // this flag. mRerunCurrentEvent = false; events[index]->Run(); if (mRerunCurrentEvent) { // The event handler yields to higher priority events and wants to rerun. returnEvents = true; break; } // Release outside the lock. events[index] = nullptr; } } if (returnEvents) mEventQueue[aLevel].InsertElementsAt(0, events.Elements() + index, length - index); }
void CacheIOThread::LoopOneLevel(uint32_t aLevel) { eventtracer::AutoEventTracer tracer(this, eventtracer::eExec, eventtracer::eDone, sLevelTraceName[aLevel]); nsTArray<nsRefPtr<nsIRunnable> > events; events.SwapElements(mEventQueue[aLevel]); uint32_t length = events.Length(); mCurrentlyExecutingLevel = aLevel; bool returnEvents = false; uint32_t index; { MonitorAutoUnlock unlock(mMonitor); for (index = 0; index < length; ++index) { if (EventsPending(aLevel)) { // Somebody scheduled a new event on a lower level, break and harry // to execute it! Don't forget to return what we haven't exec. returnEvents = true; break; } // Drop any previous flagging, only an event on the current level may set // this flag. mRerunCurrentEvent = false; events[index]->Run(); if (mRerunCurrentEvent) { // The event handler yields to higher priority events and wants to rerun. returnEvents = true; break; } // Release outside the lock. events[index] = nullptr; } } if (returnEvents) mEventQueue[aLevel].InsertElementsAt(0, events.Elements() + index, length - index); }
bool CacheIOThread::YieldInternal() { if (!IsCurrentThread()) { NS_WARNING("Trying to yield to priority events on non-cache2 I/O thread? " "You probably do something wrong."); return false; } if (mCurrentlyExecutingLevel == XPCOM_LEVEL) { // Doesn't make any sense, since this handler is the one // that would be executed as the next one. return false; } if (!EventsPending(mCurrentlyExecutingLevel)) return false; mRerunCurrentEvent = true; return true; }
void CacheIOThread::ThreadFunc() { nsCOMPtr<nsIThreadInternal> threadInternal; { MonitorAutoLock lock(mMonitor); // This creates nsThread for this PRThread nsCOMPtr<nsIThread> xpcomThread = NS_GetCurrentThread(); threadInternal = do_QueryInterface(xpcomThread); if (threadInternal) threadInternal->SetObserver(this); mXPCOMThread = xpcomThread.forget().take(); lock.NotifyAll(); do { loopStart: // Reset the lowest level now, so that we can detect a new event on // a lower level (i.e. higher priority) has been scheduled while // executing any previously scheduled event. mLowestLevelWaiting = LAST_LEVEL; // Process xpcom events first while (mHasXPCOMEvents) { mHasXPCOMEvents = false; mCurrentlyExecutingLevel = XPCOM_LEVEL; MonitorAutoUnlock unlock(mMonitor); bool processedEvent; nsresult rv; do { nsIThread *thread = mXPCOMThread; rv = thread->ProcessNextEvent(false, &processedEvent); } while (NS_SUCCEEDED(rv) && processedEvent); } uint32_t level; for (level = 0; level < LAST_LEVEL; ++level) { if (!mEventQueue[level].Length()) { // no events on this level, go to the next level continue; } LoopOneLevel(level); // Go to the first (lowest) level again goto loopStart; } if (EventsPending()) continue; if (mShutdown) break; lock.Wait(PR_INTERVAL_NO_TIMEOUT); if (EventsPending()) continue; } while (true); MOZ_ASSERT(!EventsPending()); // This is for correct assertion on XPCOM events dispatch. mInsideLoop = false; } // lock if (threadInternal) threadInternal->SetObserver(nullptr); }
static bool_t EventsPending_m (VP_cl *self ) { return VP$EventsPending(self); }