NS_IMETHODIMP STSThreadPoolListener::OnThreadCreated() { if (IsNuwaProcess()) { NuwaMarkCurrentThread(nullptr, nullptr); } return NS_OK; }
void ClosingService::ThreadFunc() { PR_SetCurrentThreadName("Closing Service"); #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { NuwaMarkCurrentThread(nullptr, nullptr); } #endif for (;;) { PRFileDesc *fd; { mozilla::MonitorAutoLock mon(mMonitor); while (!mShutdown && (mQueue.Length() == 0)) { mon.Wait(); } if (mShutdown) { // If we are in shutdown leak the rest of the sockets. for (uint32_t i = 0; i < mQueue.Length(); i++) { fd = mQueue[i]; // If the ClosingService layer is the first layer above // PR_NSPR_IO_LAYER we are not going to leak anything, but PR_Close // will not be called. PR_Free(fd); } mQueue.Clear(); return; } fd = mQueue[0]; mQueue.RemoveElementAt(0); } // Leave lock before closing socket. It can block for a long time and in // case we accidentally attach this layer twice this would cause deadlock. bool tcp = (PR_GetDescType(PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER)) == PR_DESC_SOCKET_TCP); PRIntervalTime closeStarted = PR_IntervalNow(); fd->methods->close(fd); // Post telemetry. if (tcp) { SendPRCloseTelemetry(closeStarted, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_NORMAL, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_SHUTDOWN, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_CONNECTIVITY_CHANGE, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_LINK_CHANGE, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_OFFLINE); } else { SendPRCloseTelemetry(closeStarted, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_NORMAL, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_SHUTDOWN, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_OFFLINE); } } }
NS_IMETHODIMP nsSocketTransportService::Run() { #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { NuwaMarkCurrentThread(nullptr, nullptr); } #endif SOCKET_LOG(("STS thread init %d sockets\n", gMaxCount)); psm::InitializeSSLServerCertVerificationThreads(); gSocketThread = PR_GetCurrentThread(); { DebugMutexAutoLock lock(mLock); mPollableEvent.reset(new PollableEvent()); // // NOTE: per bug 190000, this failure could be caused by Zone-Alarm // or similar software. // // NOTE: per bug 191739, this failure could also be caused by lack // of a loopback device on Windows and OS/2 platforms (it creates // a loopback socket pair on these platforms to implement a pollable // event object). if we can't create a pollable event, then we'll // have to "busy wait" to implement the socket event queue :-( // if (!mPollableEvent->Valid()) { mPollableEvent = nullptr; NS_WARNING("running socket transport thread without a pollable event"); SOCKET_LOG(("running socket transport thread without a pollable event")); } mPollList[0].fd = mPollableEvent ? mPollableEvent->PollableFD() : nullptr; mPollList[0].in_flags = PR_POLL_READ | PR_POLL_EXCEPT; mPollList[0].out_flags = 0; } mRawThread = NS_GetCurrentThread(); // hook ourselves up to observe event processing for this thread nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(mRawThread); threadInt->SetObserver(this); // make sure the pseudo random number generator is seeded on this thread srand(static_cast<unsigned>(PR_Now())); // For the calculation of the duration of the last cycle (i.e. the last for-loop // iteration before shutdown). TimeStamp startOfCycleForLastCycleCalc; int numberOfPendingEventsLastCycle; // For measuring of the poll iteration duration without time spent blocked // in poll(). TimeStamp pollCycleStart; // Time blocked in poll(). TimeDuration singlePollDuration; // For calculating the time needed for a new element to run. TimeStamp startOfIteration; TimeStamp startOfNextIteration; int numberOfPendingEvents; // If there is too many pending events queued, we will run some poll() // between them and the following variable is cumulative time spent // blocking in poll(). TimeDuration pollDuration; for (;;) { bool pendingEvents = false; numberOfPendingEvents = 0; numberOfPendingEventsLastCycle = 0; if (mTelemetryEnabledPref) { startOfCycleForLastCycleCalc = TimeStamp::NowLoRes(); startOfNextIteration = TimeStamp::NowLoRes(); } pollDuration = 0; do { if (mTelemetryEnabledPref) { pollCycleStart = TimeStamp::NowLoRes(); } DoPollIteration(&singlePollDuration); if (mTelemetryEnabledPref && !pollCycleStart.IsNull()) { Telemetry::Accumulate(Telemetry::STS_POLL_BLOCK_TIME, singlePollDuration.ToMilliseconds()); Telemetry::AccumulateTimeDelta( Telemetry::STS_POLL_CYCLE, pollCycleStart + singlePollDuration, TimeStamp::NowLoRes()); pollDuration += singlePollDuration; } mRawThread->HasPendingEvents(&pendingEvents); if (pendingEvents) { if (!mServingPendingQueue) { nsresult rv = Dispatch(NewRunnableMethod(this, &nsSocketTransportService::MarkTheLastElementOfPendingQueue), nsIEventTarget::DISPATCH_NORMAL); if (NS_FAILED(rv)) { NS_WARNING("Could not dispatch a new event on the " "socket thread."); } else { mServingPendingQueue = true; } if (mTelemetryEnabledPref) { startOfIteration = startOfNextIteration; // Everything that comes after this point will // be served in the next iteration. If no even // arrives, startOfNextIteration will be reset at the // beginning of each for-loop. startOfNextIteration = TimeStamp::NowLoRes(); } } TimeStamp eventQueueStart = TimeStamp::NowLoRes(); do { NS_ProcessNextEvent(mRawThread); numberOfPendingEvents++; pendingEvents = false; mRawThread->HasPendingEvents(&pendingEvents); } while (pendingEvents && mServingPendingQueue && ((TimeStamp::NowLoRes() - eventQueueStart).ToMilliseconds() < mMaxTimePerPollIter)); if (mTelemetryEnabledPref && !mServingPendingQueue && !startOfIteration.IsNull()) { Telemetry::AccumulateTimeDelta( Telemetry::STS_POLL_AND_EVENTS_CYCLE, startOfIteration + pollDuration, TimeStamp::NowLoRes()); Telemetry::Accumulate( Telemetry::STS_NUMBER_OF_PENDING_EVENTS, numberOfPendingEvents); numberOfPendingEventsLastCycle += numberOfPendingEvents; numberOfPendingEvents = 0; pollDuration = 0; } } } while (pendingEvents); bool goingOffline = false; // now that our event queue is empty, check to see if we should exit { DebugMutexAutoLock lock(mLock); if (mShuttingDown) { if (mTelemetryEnabledPref && !startOfCycleForLastCycleCalc.IsNull()) { Telemetry::Accumulate( Telemetry::STS_NUMBER_OF_PENDING_EVENTS_IN_THE_LAST_CYCLE, numberOfPendingEventsLastCycle); Telemetry::AccumulateTimeDelta( Telemetry::STS_POLL_AND_EVENT_THE_LAST_CYCLE, startOfCycleForLastCycleCalc, TimeStamp::NowLoRes()); } break; } if (mGoingOffline) { mGoingOffline = false; goingOffline = true; } } // Avoid potential deadlock if (goingOffline) Reset(true); } SOCKET_LOG(("STS shutting down thread\n")); // detach all sockets, including locals Reset(false); // Final pass over the event queue. This makes sure that events posted by // socket detach handlers get processed. NS_ProcessPendingEvents(mRawThread); gSocketThread = nullptr; psm::StopSSLServerCertVerificationThreads(); SOCKET_LOG(("STS thread exit\n")); return NS_OK; }
void ThreadMain(void*) { PR_SetCurrentThreadName("Hang Monitor"); #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { NuwaMarkCurrentThread(nullptr, nullptr); } #endif MonitorAutoLock lock(*gMonitor); // In order to avoid issues with the hang monitor incorrectly triggering // during a general system stop such as sleeping, the monitor thread must // run twice to trigger hang protection. PRIntervalTime lastTimestamp = 0; int waitCount = 0; #ifdef REPORT_CHROME_HANGS Telemetry::ProcessedStack stack; int32_t systemUptime = -1; int32_t firefoxUptime = -1; UniquePtr<HangAnnotations> annotations; #endif while (true) { if (gShutdown) { return; // Exit the thread } // avoid rereading the volatile value in this loop PRIntervalTime timestamp = gTimestamp; PRIntervalTime now = PR_IntervalNow(); if (timestamp != PR_INTERVAL_NO_WAIT && now < timestamp) { // 32-bit overflow, reset for another waiting period timestamp = 1; // lowest legal PRInterval value } if (timestamp != PR_INTERVAL_NO_WAIT && timestamp == lastTimestamp && gTimeout > 0) { ++waitCount; #ifdef REPORT_CHROME_HANGS // Capture the chrome-hang stack + Firefox & system uptimes after // the minimum hang duration has been reached (not when the hang ends) if (waitCount == 2) { GetChromeHangReport(stack, systemUptime, firefoxUptime); annotations = ChromeHangAnnotatorCallout(); } #else // This is the crash-on-hang feature. // See bug 867313 for the quirk in the waitCount comparison if (waitCount >= 2) { int32_t delay = int32_t(PR_IntervalToSeconds(now - timestamp)); if (delay >= gTimeout) { MonitorAutoUnlock unlock(*gMonitor); Crash(); } } #endif } else { #ifdef REPORT_CHROME_HANGS if (waitCount >= 2) { uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp); Telemetry::RecordChromeHang(hangDuration, stack, systemUptime, firefoxUptime, Move(annotations)); stack.Clear(); } #endif lastTimestamp = timestamp; waitCount = 0; } PRIntervalTime timeout; if (gTimeout <= 0) { timeout = PR_INTERVAL_NO_TIMEOUT; } else { timeout = PR_MillisecondsToInterval(gTimeout * 500); } lock.Wait(timeout); } }