int ImageHost::ChooseImageIndex() const { if (!GetCompositor() || mImages.IsEmpty()) { return -1; } TimeStamp now = GetCompositor()->GetCompositionTime(); if (now.IsNull()) { // Not in a composition, so just return the last image we composited // (if it's one of the current images). for (uint32_t i = 0; i < mImages.Length(); ++i) { if (mImages[i].mFrameID == mLastFrameID && mImages[i].mProducerID == mLastProducerID) { return i; } } return -1; } uint32_t result = 0; while (result + 1 < mImages.Length() && GetBiasedTime(mImages[result + 1].mTimeStamp, mBias) <= now) { ++result; } return result; }
TimeStamp FPSCounter::GetLatestTimeStamp() { TimeStamp timestamp = mFrameTimestamps[GetLatestReadIndex()]; MOZ_ASSERT(!timestamp.IsNull(), "Cannot use null timestamps"); return timestamp; }
DOMHighResTimeStamp nsPerformanceTiming::FetchStartHighRes() { if (!mFetchStart) { if (!nsContentUtils::IsPerformanceTimingEnabled() || !IsInitialized()) { return mZeroTime; } TimeStamp stamp; mChannel->GetAsyncOpen(&stamp); MOZ_ASSERT(!stamp.IsNull(), "The fetch start time stamp should always be " "valid if the performance timing is enabled"); mFetchStart = (!stamp.IsNull()) ? TimeStampToDOMHighRes(stamp) : 0.0; } return mFetchStart; }
NS_IMETHODIMP nsAppStartup::TrackStartupCrashEnd() { bool inSafeMode = false; nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID); if (xr) xr->GetInSafeMode(&inSafeMode); // return if we already ended or we're restarting into safe mode if (mStartupCrashTrackingEnded || (mIsSafeModeNecessary && !inSafeMode)) return NS_OK; mStartupCrashTrackingEnded = true; StartupTimeline::Record(StartupTimeline::STARTUP_CRASH_DETECTION_END); // Use the timestamp of XRE_main as an approximation for the lock file timestamp. // See MAX_STARTUP_BUFFER for the buffer time period. TimeStamp mainTime = StartupTimeline::Get(StartupTimeline::MAIN); TimeStamp now = TimeStamp::Now(); PRTime prNow = PR_Now(); nsresult rv; if (mainTime.IsNull()) { NS_WARNING("Could not get StartupTimeline::MAIN time."); } else { uint64_t lockFileTime = ComputeAbsoluteTimestamp(prNow, now, mainTime); rv = Preferences::SetInt(kPrefLastSuccess, (int32_t)(lockFileTime / PR_USEC_PER_SEC)); if (NS_FAILED(rv)) NS_WARNING("Could not set startup crash detection pref."); } if (inSafeMode && mIsSafeModeNecessary) { // On a successful startup in automatic safe mode, allow the user one more crash // in regular mode before returning to safe mode. int32_t maxResumedCrashes = 0; int32_t prefType; rv = Preferences::GetDefaultRootBranch()->GetPrefType(kPrefMaxResumedCrashes, &prefType); NS_ENSURE_SUCCESS(rv, rv); if (prefType == nsIPrefBranch::PREF_INT) { rv = Preferences::GetInt(kPrefMaxResumedCrashes, &maxResumedCrashes); NS_ENSURE_SUCCESS(rv, rv); } rv = Preferences::SetInt(kPrefRecentCrashes, maxResumedCrashes); NS_ENSURE_SUCCESS(rv, rv); } else if (!inSafeMode) { // clear the count of recent crashes after a succesful startup when not in safe mode rv = Preferences::ClearUser(kPrefRecentCrashes); if (NS_FAILED(rv)) NS_WARNING("Could not clear startup crash count."); } nsCOMPtr<nsIPrefService> prefs = Preferences::GetService(); rv = prefs->SavePrefFile(nullptr); // flush prefs to disk since we are tracking crashes return rv; }
DOMTimeMilliSec nsDOMNavigationTiming::TimeStampToDOM(TimeStamp aStamp) const { if (aStamp.IsNull()) { return 0; } TimeDuration duration = aStamp - mNavigationStartTimeStamp; return GetNavigationStart() + static_cast<int64_t>(duration.ToMilliseconds()); }
int32_t nsSocketTransportService::Poll(uint32_t *interval, TimeDuration *pollDuration) { PRPollDesc *pollList; uint32_t pollCount; PRIntervalTime pollTimeout; *pollDuration = 0; // If there are pending events for this thread then // DoPollIteration() should service the network without blocking. bool pendingEvents = false; mRawThread->HasPendingEvents(&pendingEvents); if (mPollList[0].fd) { mPollList[0].out_flags = 0; pollList = mPollList; pollCount = mActiveCount + 1; pollTimeout = pendingEvents ? PR_INTERVAL_NO_WAIT : PollTimeout(); } else { // no pollable event, so busy wait... pollCount = mActiveCount; if (pollCount) pollList = &mPollList[1]; else pollList = nullptr; pollTimeout = pendingEvents ? PR_INTERVAL_NO_WAIT : PR_MillisecondsToInterval(25); } PRIntervalTime ts = PR_IntervalNow(); TimeStamp pollStart; if (mTelemetryEnabledPref) { pollStart = TimeStamp::NowLoRes(); } SOCKET_LOG((" timeout = %i milliseconds\n", PR_IntervalToMilliseconds(pollTimeout))); int32_t rv = PR_Poll(pollList, pollCount, pollTimeout); PRIntervalTime passedInterval = PR_IntervalNow() - ts; if (mTelemetryEnabledPref && !pollStart.IsNull()) { *pollDuration = TimeStamp::NowLoRes() - pollStart; } SOCKET_LOG((" ...returned after %i milliseconds\n", PR_IntervalToMilliseconds(passedInterval))); *interval = PR_IntervalToSeconds(passedInterval); return rv; }
TimeStamp FPSCounter::GetNextTimeStamp() { TimeStamp timestamp = mFrameTimestamps[mIteratorIndex--]; MOZ_ASSERT(!timestamp.IsNull(), "Reading Invalid Timestamp Data"); if (mIteratorIndex == -1) { mIteratorIndex = kMaxFrames - 1; } return timestamp; }
static PLDHashOperator BackdateTimeStampsEnumerator(nsISupports *aKey, TimeStamp &aTimeStamp, void* aClosure) { TimeStamp *minTimeStamp = static_cast<TimeStamp*>(aClosure); if (!aTimeStamp.IsNull() && aTimeStamp > *minTimeStamp) { aTimeStamp = *minTimeStamp; } return PL_DHASH_NEXT; }
static ImageHost::Bias UpdateBias(const TimeStamp& aCompositionTime, const TimeStamp& aCompositedImageTime, const TimeStamp& aNextImageTime, // may be null ImageHost::Bias aBias) { if (aCompositedImageTime.IsNull()) { return ImageHost::BIAS_NONE; } TimeDuration threshold = TimeDuration::FromMilliseconds(1.0); if (aCompositionTime - aCompositedImageTime < threshold && aCompositionTime - aCompositedImageTime > -threshold) { // The chosen frame's time is very close to the composition time (probably // just before the current composition time, but due to previously set // negative bias, it could be just after the current composition time too). // If the inter-frame time is almost exactly equal to (a multiple of) // the inter-composition time, then we're in a dangerous situation because // jitter might cause frames to fall one side or the other of the // composition times, causing many frames to be skipped or duplicated. // Try to prevent that by adding a negative bias to the frame times during // the next composite; that should ensure the next frame's time is treated // as falling just before a composite time. return ImageHost::BIAS_NEGATIVE; } if (!aNextImageTime.IsNull() && aNextImageTime - aCompositionTime < threshold && aNextImageTime - aCompositionTime > -threshold) { // The next frame's time is very close to our composition time (probably // just after the current composition time, but due to previously set // positive bias, it could be just before the current composition time too). // We're in a dangerous situation because jitter might cause frames to // fall one side or the other of the composition times, causing many frames // to be skipped or duplicated. // Try to prevent that by adding a negative bias to the frame times during // the next composite; that should ensure the next frame's time is treated // as falling just before a composite time. return ImageHost::BIAS_POSITIVE; } return ImageHost::BIAS_NONE; }
int32_t nsSocketTransportService::Poll(bool wait, uint32_t *interval, TimeDuration *pollDuration) { PRPollDesc *pollList; uint32_t pollCount; PRIntervalTime pollTimeout; *pollDuration = 0; if (mPollList[0].fd) { mPollList[0].out_flags = 0; pollList = mPollList; pollCount = mActiveCount + 1; pollTimeout = PollTimeout(); } else { // no pollable event, so busy wait... pollCount = mActiveCount; if (pollCount) pollList = &mPollList[1]; else pollList = nullptr; pollTimeout = PR_MillisecondsToInterval(25); } if (!wait) pollTimeout = PR_INTERVAL_NO_WAIT; PRIntervalTime ts = PR_IntervalNow(); TimeStamp pollStart; if (mTelemetryEnabledPref) { pollStart = TimeStamp::NowLoRes(); } SOCKET_LOG((" timeout = %i milliseconds\n", PR_IntervalToMilliseconds(pollTimeout))); int32_t rv = PR_Poll(pollList, pollCount, pollTimeout); PRIntervalTime passedInterval = PR_IntervalNow() - ts; if (mTelemetryEnabledPref && !pollStart.IsNull()) { *pollDuration = TimeStamp::NowLoRes() - pollStart; } SOCKET_LOG((" ...returned after %i milliseconds\n", PR_IntervalToMilliseconds(passedInterval))); *interval = PR_IntervalToSeconds(passedInterval); return rv; }
bool KeyframeEffectReadOnly::CanThrottleTransformChanges(nsIFrame& aFrame) const { // If we know that the animation cannot cause overflow, // we can just disable flushes for this animation. // If we don't show scrollbars, we don't care about overflow. if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) == 0) { return true; } nsPresContext* presContext = GetPresContext(); // CanThrottleTransformChanges is only called as part of a refresh driver tick // in which case we expect to has a pres context. MOZ_ASSERT(presContext); TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh(); EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType); MOZ_ASSERT(effectSet, "CanThrottleTransformChanges is expected to be called" " on an effect in an effect set"); MOZ_ASSERT(mAnimation, "CanThrottleTransformChanges is expected to be called" " on an effect with a parent animation"); TimeStamp animationRuleRefreshTime = effectSet->AnimationRuleRefreshTime(mAnimation->CascadeLevel()); // If this animation can cause overflow, we can throttle some of the ticks. if (!animationRuleRefreshTime.IsNull() && (now - animationRuleRefreshTime) < OverflowRegionRefreshInterval()) { return true; } // If the nearest scrollable ancestor has overflow:hidden, // we don't care about overflow. nsIScrollableFrame* scrollable = nsLayoutUtils::GetNearestScrollableFrame(&aFrame); if (!scrollable) { return true; } ScrollbarStyles ss = scrollable->GetScrollbarStyles(); if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN && ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN && scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) { return true; } return false; }
// aID is a sub-identifier (in particular a specific MediaStramTrack) void AsyncLatencyLogger::WriteLog(LatencyLogIndex aIndex, uint64_t aID, int64_t aValue, TimeStamp aTimeStamp) { if (aTimeStamp.IsNull()) { MOZ_LOG(GetLatencyLog(), LogLevel::Debug, ("Latency: %s,%" PRIu64 ",%" PRId64 ",%" PRId64, LatencyLogIndex2Strings[aIndex], aID, GetTimeStamp(), aValue)); } else { MOZ_LOG(GetLatencyLog(), LogLevel::Debug, ("Latency: %s,%" PRIu64 ",%" PRId64 ",%" PRId64 ",%" PRId64, LatencyLogIndex2Strings[aIndex], aID, GetTimeStamp(), aValue, static_cast<int64_t>((aTimeStamp - gAsyncLogger->mStart).ToMilliseconds()))); } }
// aID is a sub-identifier (in particular a specific MediaStramTrack) void AsyncLatencyLogger::WriteLog(LatencyLogIndex aIndex, uint64_t aID, int64_t aValue, TimeStamp aTimeStamp) { if (aTimeStamp.IsNull()) { PR_LOG(GetLatencyLog(), PR_LOG_DEBUG, ("Latency: %s,%llu,%lld,%lld", LatencyLogIndex2Strings[aIndex], aID, GetTimeStamp(), aValue)); } else { PR_LOG(GetLatencyLog(), PR_LOG_DEBUG, ("Latency: %s,%llu,%lld,%lld,%lld", LatencyLogIndex2Strings[aIndex], aID, GetTimeStamp(), aValue, static_cast<int64_t>((aTimeStamp - gAsyncLogger->mStart).ToMilliseconds()))); } }
Nullable<TimeDuration> DocumentTimeline::ToTimelineTime( const TimeStamp& aTimeStamp) const { Nullable<TimeDuration> result; // Initializes to null if (aTimeStamp.IsNull()) { return result; } nsDOMNavigationTiming* timing = mDocument->GetNavigationTiming(); if (MOZ_UNLIKELY(!timing)) { return result; } result.SetValue(aTimeStamp - timing->GetNavigationStartTimeStamp() - mOriginTime); return result; }
void mozilla_sampler_responsiveness(const TimeStamp& aTime) { if (!sLastTracerEvent.IsNull()) { if (sResponsivenessLoc == 100) { for(size_t i = 0; i < 100-1; i++) { sResponsivenessTimes[i] = sResponsivenessTimes[i+1]; } sResponsivenessLoc--; } TimeDuration delta = aTime - sLastTracerEvent; sResponsivenessTimes[sResponsivenessLoc++] = delta.ToMilliseconds(); } sCurrentEventGeneration++; sLastTracerEvent = aTime; }
void LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp, EndTransactionFlags aFlags) { NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); NS_ASSERTION(!(aFlags & END_NO_COMPOSITE), "Shouldn't get END_NO_COMPOSITE here"); mInTransaction = false; mRenderStartTime = TimeStamp::Now(); if (!mIsCompositorReady) { return; } mIsCompositorReady = false; #ifdef MOZ_LAYERS_HAVE_LOG MOZ_LAYERS_LOG((" ----- (beginning paint)")); Log(); #endif if (mDestroyed) { NS_WARNING("Call on destroyed layer manager"); return; } // Set composition timestamp here because we need it in // ComputeEffectiveTransforms (so the correct video frame size is picked) and // also to compute invalid regions properly. mCompositor->SetCompositionTime(aTimeStamp); if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) { MOZ_ASSERT(!aTimeStamp.IsNull()); UpdateAndRender(); mCompositor->FlushPendingNotifyNotUsed(); } else { // Modified the layer tree. mGeometryChanged = true; } mCompositor->ClearTargetContext(); mTarget = nullptr; #ifdef MOZ_LAYERS_HAVE_LOG Log(); MOZ_LAYERS_LOG(("]----- EndTransaction")); #endif }
bool SpdyPushedStream3::IsOrphaned(TimeStamp now) { MOZ_ASSERT(!now.IsNull()); // if spdy is not transmitting, and is also not connected to a consumer // stream, and its been like that for too long then it is oprhaned if (mConsumerStream) return false; bool rv = ((now - mLastRead).ToSeconds() > 30.0); if (rv) { LOG3(("SpdyPushCache::IsOrphaned 0x%X IsOrphaned %3.2f\n", mStreamID, (now - mLastRead).ToSeconds())); } return rv; }
void mozilla_sampler_responsiveness(TimeStamp aTime) { if (!sLastTracerEvent.IsNull()) { if (sResponsivenessLoc == 100) { for(size_t i = 0; i < 100-1; i++) { sResponsivenessTimes[i] = sResponsivenessTimes[i+1]; } sResponsivenessLoc--; //for(size_t i = 0; i < 100; i++) { // sResponsivenessTimes[i] = 0; //} //sResponsivenessLoc = 0; } TimeDuration delta = aTime - sLastTracerEvent; sResponsivenessTimes[sResponsivenessLoc++] = delta.ToMilliseconds(); } sLastTracerEvent = aTime; }
bool CompositorParent::SetTestSampleTime(LayerTransactionParent* aLayerTree, const TimeStamp& aTime) { if (aTime.IsNull()) { return false; } mIsTesting = true; mTestTime = aTime; // Update but only if we were already scheduled to animate if (mCompositionManager && mCurrentCompositeTask) { AutoResolveRefLayers resolve(mCompositionManager); bool requestNextFrame = mCompositionManager->TransformShadowTree(aTime); if (!requestNextFrame) { CancelCurrentCompositeTask(); } } return true; }
bool Http2PushedStream::IsOrphaned(TimeStamp now) { MOZ_ASSERT(!now.IsNull()); // if session is not transmitting, and is also not connected to a consumer // stream, and its been like that for too long then it is oprhaned if (mConsumerStream || mDeferCleanupOnPush) { return false; } if (mOnPushFailed) { return true; } bool rv = ((now - mLastRead).ToSeconds() > 30.0); if (rv) { LOG3(("Http2PushedStream:IsOrphaned 0x%X IsOrphaned %3.2f\n", mStreamID, (now - mLastRead).ToSeconds())); } return rv; }
void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage, TimeStamp aTargetTime) { MutexAutoLock lock(mMutex); if (aIntrinsicSize != mIntrinsicSize) { mIntrinsicSize = aIntrinsicSize; mIntrinsicSizeChanged = true; } gfxIntSize oldFrameSize = mImageContainer->GetCurrentSize(); TimeStamp lastPaintTime = mImageContainer->GetPaintTime(); if (!lastPaintTime.IsNull() && !mPaintTarget.IsNull()) { mPaintDelay = lastPaintTime - mPaintTarget; } // When using the OMX decoder, destruction of the current image can indirectly // block on main thread I/O. If we let this happen while holding onto // |mImageContainer|'s lock, then when the main thread then tries to // composite it can then block on |mImageContainer|'s lock, causing a // deadlock. We use this hack to defer the destruction of the current image // until it is safe. nsRefPtr<Image> kungFuDeathGrip; kungFuDeathGrip = mImageContainer->LockCurrentImage(); mImageContainer->UnlockCurrentImage(); mImageContainer->SetCurrentImage(aImage); gfxIntSize newFrameSize = mImageContainer->GetCurrentSize(); if (oldFrameSize != newFrameSize) { mImageSizeChanged = true; mNeedInvalidation = true; } mPaintTarget = aTargetTime; }
void nsLoadGroup::TelemetryReportChannel(nsITimedChannel *aTimedChannel, bool aDefaultRequest) { nsresult rv; bool timingEnabled; rv = aTimedChannel->GetTimingEnabled(&timingEnabled); if (NS_FAILED(rv) || !timingEnabled) return; TimeStamp asyncOpen; rv = aTimedChannel->GetAsyncOpen(&asyncOpen); // We do not check !asyncOpen.IsNull() bellow, prevent ASSERTIONs this way if (NS_FAILED(rv) || asyncOpen.IsNull()) return; TimeStamp cacheReadStart; rv = aTimedChannel->GetCacheReadStart(&cacheReadStart); if (NS_FAILED(rv)) return; TimeStamp cacheReadEnd; rv = aTimedChannel->GetCacheReadEnd(&cacheReadEnd); if (NS_FAILED(rv)) return; TimeStamp domainLookupStart; rv = aTimedChannel->GetDomainLookupStart(&domainLookupStart); if (NS_FAILED(rv)) return; TimeStamp domainLookupEnd; rv = aTimedChannel->GetDomainLookupEnd(&domainLookupEnd); if (NS_FAILED(rv)) return; TimeStamp connectStart; rv = aTimedChannel->GetConnectStart(&connectStart); if (NS_FAILED(rv)) return; TimeStamp connectEnd; rv = aTimedChannel->GetConnectEnd(&connectEnd); if (NS_FAILED(rv)) return; TimeStamp requestStart; rv = aTimedChannel->GetRequestStart(&requestStart); if (NS_FAILED(rv)) return; TimeStamp responseStart; rv = aTimedChannel->GetResponseStart(&responseStart); if (NS_FAILED(rv)) return; TimeStamp responseEnd; rv = aTimedChannel->GetResponseEnd(&responseEnd); if (NS_FAILED(rv)) return; #define HTTP_REQUEST_HISTOGRAMS(prefix) \ if (!domainLookupStart.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_DNS_ISSUE_TIME, \ asyncOpen, domainLookupStart); \ } \ \ if (!domainLookupStart.IsNull() && !domainLookupEnd.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_DNS_LOOKUP_TIME, \ domainLookupStart, domainLookupEnd); \ } \ \ if (!connectStart.IsNull() && !connectEnd.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_TCP_CONNECTION, \ connectStart, connectEnd); \ } \ \ \ if (!requestStart.IsNull() && !responseEnd.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_OPEN_TO_FIRST_SENT, \ asyncOpen, requestStart); \ \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_FIRST_SENT_TO_LAST_RECEIVED, \ requestStart, responseEnd); \ \ if (cacheReadStart.IsNull() && !responseStart.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_OPEN_TO_FIRST_RECEIVED, \ asyncOpen, responseStart); \ } \ } \ \ if (!cacheReadStart.IsNull() && !cacheReadEnd.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_OPEN_TO_FIRST_FROM_CACHE, \ asyncOpen, cacheReadStart); \ \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_CACHE_READ_TIME, \ cacheReadStart, cacheReadEnd); \ \ if (!requestStart.IsNull() && !responseEnd.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_REVALIDATION, \ requestStart, responseEnd); \ } \ } \ \ if (!cacheReadEnd.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_COMPLETE_LOAD, \ asyncOpen, cacheReadEnd); \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_COMPLETE_LOAD_CACHED, \ asyncOpen, cacheReadEnd); \ } \ else if (!responseEnd.IsNull()) { \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_COMPLETE_LOAD, \ asyncOpen, responseEnd); \ Telemetry::AccumulateTimeDelta( \ Telemetry::HTTP_##prefix##_COMPLETE_LOAD_NET, \ asyncOpen, responseEnd); \ } if (aDefaultRequest) { HTTP_REQUEST_HISTOGRAMS(PAGE) } else {
NS_IMETHODIMP nsLoadGroup::RemoveRequest(nsIRequest *request, nsISupports* ctxt, nsresult aStatus) { NS_ENSURE_ARG_POINTER(request); nsresult rv; #if defined(PR_LOGGING) { nsAutoCString nameStr; request->GetName(nameStr); LOG(("LOADGROUP [%x]: Removing request %x %s status %x (count=%d).\n", this, request, nameStr.get(), aStatus, mRequests.entryCount-1)); } #endif // Make sure we have a owning reference to the request we're about // to remove. nsCOMPtr<nsIRequest> kungFuDeathGrip(request); // // Remove the request from the group. If this fails, it means that // the request was *not* in the group so do not update the foreground // count or it will get messed up... // RequestMapEntry *entry = static_cast<RequestMapEntry *> (PL_DHashTableOperate(&mRequests, request, PL_DHASH_LOOKUP)); if (PL_DHASH_ENTRY_IS_FREE(entry)) { LOG(("LOADGROUP [%x]: Unable to remove request %x. Not in group!\n", this, request)); return NS_ERROR_FAILURE; } PL_DHashTableRawRemove(&mRequests, entry); // Collect telemetry stats only when default request is a timed channel. // Don't include failed requests in the timing statistics. if (mDefaultLoadIsTimed && NS_SUCCEEDED(aStatus)) { nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(request); if (timedChannel) { // Figure out if this request was served from the cache ++mTimedRequests; TimeStamp timeStamp; rv = timedChannel->GetCacheReadStart(&timeStamp); if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) ++mCachedRequests; rv = timedChannel->GetAsyncOpen(&timeStamp); if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) { Telemetry::AccumulateTimeDelta( Telemetry::HTTP_SUBITEM_OPEN_LATENCY_TIME, mDefaultRequestCreationTime, timeStamp); } rv = timedChannel->GetResponseStart(&timeStamp); if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) { Telemetry::AccumulateTimeDelta( Telemetry::HTTP_SUBITEM_FIRST_BYTE_LATENCY_TIME, mDefaultRequestCreationTime, timeStamp); } TelemetryReportChannel(timedChannel, false); } } if (mRequests.entryCount == 0) { TelemetryReport(); } // Undo any group priority delta... if (mPriority != 0) RescheduleRequest(request, -mPriority); nsLoadFlags flags; rv = request->GetLoadFlags(&flags); if (NS_FAILED(rv)) return rv; if (!(flags & nsIRequest::LOAD_BACKGROUND)) { NS_ASSERTION(mForegroundCount > 0, "ForegroundCount messed up"); mForegroundCount -= 1; // Fire the OnStopRequest out to the observer... nsCOMPtr<nsIRequestObserver> observer = do_QueryReferent(mObserver); if (observer) { LOG(("LOADGROUP [%x]: Firing OnStopRequest for request %x." "(foreground count=%d).\n", this, request, mForegroundCount)); rv = observer->OnStopRequest(request, ctxt, aStatus); #if defined(PR_LOGGING) if (NS_FAILED(rv)) { LOG(("LOADGROUP [%x]: OnStopRequest for request %x FAILED.\n", this, request)); } #endif } // If that was the last request -> remove ourselves from loadgroup if (mForegroundCount == 0 && mLoadGroup) { mLoadGroup->RemoveRequest(this, nullptr, aStatus); } } return rv; }
void DecodedStream::SendVideo(bool aIsSameOrigin, const PrincipalHandle& aPrincipalHandle) { AssertOwnerThread(); if (!mInfo.HasVideo()) { return; } VideoSegment output; TrackID videoTrackId = mInfo.mVideo.mTrackId; AutoTArray<RefPtr<MediaData>, 10> video; SourceMediaStream* sourceStream = mData->mStream; // It's OK to hold references to the VideoData because VideoData // is ref-counted. mVideoQueue.GetElementsAfter(mData->mNextVideoTime, &video); // tracksStartTimeStamp might be null when the SourceMediaStream not yet // be added to MediaStreamGraph. TimeStamp tracksStartTimeStamp = sourceStream->GetStreamTracksStrartTimeStamp(); if (tracksStartTimeStamp.IsNull()) { tracksStartTimeStamp = TimeStamp::Now(); } for (uint32_t i = 0; i < video.Length(); ++i) { VideoData* v = video[i]->As<VideoData>(); if (mData->mNextVideoTime < v->mTime) { // Write last video frame to catch up. mLastVideoImage can be null here // which is fine, it just means there's no video. // TODO: |mLastVideoImage| should come from the last image rendered // by the state machine. This will avoid the black frame when capture // happens in the middle of playback (especially in th middle of a // video frame). E.g. if we have a video frame that is 30 sec long // and capture happens at 15 sec, we'll have to append a black frame // that is 15 sec long. WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage, v->mTime, mData->mNextVideoTime, mData->mLastVideoImageDisplaySize, tracksStartTimeStamp + TimeDuration::FromMicroseconds(v->mTime), &output, aPrincipalHandle); mData->mNextVideoTime = v->mTime; } if (mData->mNextVideoTime < v->GetEndTime()) { WriteVideoToMediaStream(sourceStream, v->mImage, v->GetEndTime(), mData->mNextVideoTime, v->mDisplay, tracksStartTimeStamp + TimeDuration::FromMicroseconds(v->GetEndTime()), &output, aPrincipalHandle); mData->mNextVideoTime = v->GetEndTime(); mData->mLastVideoImage = v->mImage; mData->mLastVideoImageDisplaySize = v->mDisplay; } } // Check the output is not empty. if (output.GetLastFrame()) { mData->mEOSVideoCompensation = ZeroDurationAtLastChunk(output); } if (!aIsSameOrigin) { output.ReplaceWithDisabled(); } if (output.GetDuration() > 0) { sourceStream->AppendToTrack(videoTrackId, &output); } if (mVideoQueue.IsFinished() && !mData->mHaveSentFinishVideo) { if (mData->mEOSVideoCompensation) { VideoSegment endSegment; // Calculate the deviation clock time from DecodedStream. int64_t deviation_usec = sourceStream->StreamTimeToMicroseconds(1); WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage, mData->mNextVideoTime + deviation_usec, mData->mNextVideoTime, mData->mLastVideoImageDisplaySize, tracksStartTimeStamp + TimeDuration::FromMicroseconds(mData->mNextVideoTime + deviation_usec), &endSegment, aPrincipalHandle); mData->mNextVideoTime += deviation_usec; MOZ_ASSERT(endSegment.GetDuration() > 0); if (!aIsSameOrigin) { endSegment.ReplaceWithDisabled(); } sourceStream->AppendToTrack(videoTrackId, &endSegment); } sourceStream->EndTrack(videoTrackId); mData->mHaveSentFinishVideo = true; } }
void ElementAnimations::EnsureStyleRuleFor(TimeStamp aRefreshTime, EventArray& aEventsToDispatch) { if (!mNeedsRefreshes) { // All of our animations are paused or completed. mStyleRuleRefreshTime = aRefreshTime; return; } // mStyleRule may be null and valid, if we have no style to apply. if (mStyleRuleRefreshTime.IsNull() || mStyleRuleRefreshTime != aRefreshTime) { mStyleRuleRefreshTime = aRefreshTime; mStyleRule = nsnull; // We'll set mNeedsRefreshes to true below in all cases where we need them. mNeedsRefreshes = false; // FIXME(spec): assume that properties in higher animations override // those in lower ones. // Therefore, we iterate from last animation to first. nsCSSPropertySet properties; for (PRUint32 animIdx = mAnimations.Length(); animIdx-- != 0; ) { ElementAnimation &anim = mAnimations[animIdx]; if (anim.mProperties.Length() == 0 || anim.mIterationDuration.ToMilliseconds() <= 0.0) { // No animation data. continue; } TimeDuration currentTimeDuration; if (anim.IsPaused()) { // FIXME: avoid recalculating every time currentTimeDuration = anim.mPauseStart - anim.mStartTime; } else { currentTimeDuration = aRefreshTime - anim.mStartTime; } // Set |currentIterationCount| to the (fractional) number of // iterations we've completed up to the current position. double currentIterationCount = currentTimeDuration / anim.mIterationDuration; bool dispatchStartOrIteration = false; if (currentIterationCount >= double(anim.mIterationCount)) { // Dispatch 'animationend' when needed. if (IsForElement() && anim.mLastNotification != ElementAnimation::LAST_NOTIFICATION_END) { anim.mLastNotification = ElementAnimation::LAST_NOTIFICATION_END; AnimationEventInfo ei(mElement, anim.mName, NS_ANIMATION_END, currentTimeDuration); aEventsToDispatch.AppendElement(ei); } if (!anim.FillsForwards()) { // No animation data. continue; } currentIterationCount = double(anim.mIterationCount); } else { if (!anim.IsPaused()) { mNeedsRefreshes = true; } if (currentIterationCount < 0.0) { if (!anim.FillsBackwards()) { // No animation data. continue; } currentIterationCount = 0.0; } else { dispatchStartOrIteration = !anim.IsPaused(); } } // Set |positionInIteration| to the position from 0% to 100% along // the keyframes. NS_ABORT_IF_FALSE(currentIterationCount >= 0.0, "must be positive"); PRUint32 whichIteration = int(currentIterationCount); if (whichIteration == anim.mIterationCount && whichIteration != 0) { // When the animation's iteration count is an integer (as it // normally is), we need to end at 100% of its last iteration // rather than 0% of the next one (unless it's zero). --whichIteration; } double positionInIteration = currentIterationCount - double(whichIteration); bool thisIterationReverse = false; switch (anim.mDirection) { case NS_STYLE_ANIMATION_DIRECTION_NORMAL: thisIterationReverse = false; break; case NS_STYLE_ANIMATION_DIRECTION_REVERSE: thisIterationReverse = true; break; case NS_STYLE_ANIMATION_DIRECTION_ALTERNATE: thisIterationReverse = (whichIteration & 1) == 1; break; case NS_STYLE_ANIMATION_DIRECTION_ALTERNATE_REVERSE: thisIterationReverse = (whichIteration & 1) == 0; break; } if (thisIterationReverse) { positionInIteration = 1.0 - positionInIteration; } // Dispatch 'animationstart' or 'animationiteration' when needed. if (IsForElement() && dispatchStartOrIteration && whichIteration != anim.mLastNotification) { // Notify 'animationstart' even if a negative delay puts us // past the first iteration. // Note that when somebody changes the animation-duration // dynamically, this will fire an extra iteration event // immediately in many cases. It's not clear to me if that's the // right thing to do. PRUint32 message = anim.mLastNotification == ElementAnimation::LAST_NOTIFICATION_NONE ? NS_ANIMATION_START : NS_ANIMATION_ITERATION; anim.mLastNotification = whichIteration; AnimationEventInfo ei(mElement, anim.mName, message, currentTimeDuration); aEventsToDispatch.AppendElement(ei); } NS_ABORT_IF_FALSE(0.0 <= positionInIteration && positionInIteration <= 1.0, "position should be in [0-1]"); for (PRUint32 propIdx = 0, propEnd = anim.mProperties.Length(); propIdx != propEnd; ++propIdx) { const AnimationProperty &prop = anim.mProperties[propIdx]; NS_ABORT_IF_FALSE(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key"); NS_ABORT_IF_FALSE(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0, "incorrect last to key"); if (properties.HasProperty(prop.mProperty)) { // A later animation already set this property. continue; } properties.AddProperty(prop.mProperty); NS_ABORT_IF_FALSE(prop.mSegments.Length() > 0, "property should not be in animations if it " "has no segments"); // FIXME: Maybe cache the current segment? const AnimationPropertySegment *segment = prop.mSegments.Elements(); while (segment->mToKey < positionInIteration) { NS_ABORT_IF_FALSE(segment->mFromKey < segment->mToKey, "incorrect keys"); ++segment; NS_ABORT_IF_FALSE(segment->mFromKey == (segment-1)->mToKey, "incorrect keys"); } NS_ABORT_IF_FALSE(segment->mFromKey < segment->mToKey, "incorrect keys"); NS_ABORT_IF_FALSE(segment - prop.mSegments.Elements() < prop.mSegments.Length(), "ran off end"); if (!mStyleRule) { // Allocate the style rule now that we know we have animation data. mStyleRule = new css::AnimValuesStyleRule(); } double positionInSegment = (positionInIteration - segment->mFromKey) / (segment->mToKey - segment->mFromKey); double valuePosition = segment->mTimingFunction.GetValue(positionInSegment); nsStyleAnimation::Value *val = mStyleRule->AddEmptyValue(prop.mProperty); #ifdef DEBUG bool result = #endif nsStyleAnimation::Interpolate(prop.mProperty, segment->mFromValue, segment->mToValue, valuePosition, *val); NS_ABORT_IF_FALSE(result, "interpolate must succeed now"); } } } }
NS_IMETHODIMP nsSocketTransportService::Run() { PR_SetCurrentThreadName("Socket Thread"); #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { NuwaMarkCurrentThread(nullptr, nullptr); } #endif SOCKET_LOG(("STS thread init\n")); #if !defined(MOZILLA_XPCOMRT_API) psm::InitializeSSLServerCertVerificationThreads(); #endif // !defined(MOZILLA_XPCOMRT_API) gSocketThread = PR_GetCurrentThread(); // add thread event to poll list (mThreadEvent may be nullptr) mPollList[0].fd = mThreadEvent; mPollList[0].in_flags = PR_POLL_READ; mPollList[0].out_flags = 0; nsIThread *thread = NS_GetCurrentThread(); // hook ourselves up to observe event processing for this thread nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(thread); 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; thread->HasPendingEvents(&pendingEvents); numberOfPendingEvents = 0; numberOfPendingEventsLastCycle = 0; if (mTelemetryEnabledPref) { startOfCycleForLastCycleCalc = TimeStamp::NowLoRes(); startOfNextIteration = TimeStamp::NowLoRes(); } pollDuration = 0; do { if (mTelemetryEnabledPref) { pollCycleStart = TimeStamp::NowLoRes(); } // If there are pending events for this thread then // DoPollIteration() should service the network without blocking. DoPollIteration(!pendingEvents, &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; } // If nothing was pending before the poll, it might be now if (!pendingEvents) { thread->HasPendingEvents(&pendingEvents); } if (pendingEvents) { if (!mServingPendingQueue) { nsresult rv = Dispatch(NS_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(thread); numberOfPendingEvents++; pendingEvents = false; thread->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(thread); gSocketThread = nullptr; #if !defined(MOZILLA_XPCOMRT_API) psm::StopSSLServerCertVerificationThreads(); #endif // !defined(MOZILLA_XPCOMRT_API) SOCKET_LOG(("STS thread exit\n")); return NS_OK; }
void TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadline) { MOZ_DIAGNOSTIC_ASSERT(!aNow.IsNull()); MOZ_DIAGNOSTIC_ASSERT(!aTargetDeadline.IsNull()); MOZ_ASSERT_IF(mWindow.IsFrozen(), mWindow.IsSuspended()); if (mWindow.IsSuspended()) { return; } // Limit the overall time spent in RunTimeout() to reduce jank. uint32_t totalTimeLimitMS = std::max(1u, gMaxConsecutiveCallbacksMilliseconds); const TimeDuration totalTimeLimit = TimeDuration::Min(TimeDuration::FromMilliseconds(totalTimeLimitMS), TimeDuration::Max(TimeDuration(), mExecutionBudget)); // Allow up to 25% of our total time budget to be used figuring out which // timers need to run. This is the initial loop in this method. const TimeDuration initialTimeLimit = TimeDuration::FromMilliseconds(totalTimeLimit.ToMilliseconds() / 4); // Ammortize overhead from from calling TimeStamp::Now() in the initial // loop, though, by only checking for an elapsed limit every N timeouts. const uint32_t kNumTimersPerInitialElapsedCheck = 100; // Start measuring elapsed time immediately. We won't potentially expire // the time budget until at least one Timeout has run, though. TimeStamp now(aNow); TimeStamp start = now; uint32_t firingId = CreateFiringId(); auto guard = MakeScopeExit([&] { DestroyFiringId(firingId); }); // Make sure that the window and the script context don't go away as // a result of running timeouts nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(&mWindow); // Silence the static analysis error about windowKungFuDeathGrip. Accessing // members of mWindow here is safe, because the lifetime of TimeoutManager is // the same as the lifetime of the containing nsGlobalWindow. Unused << windowKungFuDeathGrip; // A native timer has gone off. See which of our timeouts need // servicing TimeStamp deadline; if (aTargetDeadline > now) { // The OS timer fired early (which can happen due to the timers // having lower precision than TimeStamp does). Set |deadline| to // be the time when the OS timer *should* have fired so that any // timers that *should* have fired *will* be fired now. deadline = aTargetDeadline; } else { deadline = now; } TimeStamp nextDeadline; uint32_t numTimersToRun = 0; // The timeout list is kept in deadline order. Discover the latest timeout // whose deadline has expired. On some platforms, native timeout events fire // "early", but we handled that above by setting deadline to aTargetDeadline // if the timer fired early. So we can stop walking if we get to timeouts // whose When() is greater than deadline, since once that happens we know // nothing past that point is expired. { // Use a nested scope in order to make sure the strong references held by // the iterator are freed after the loop. OrderedTimeoutIterator expiredIter(mNormalTimeouts, mTrackingTimeouts); while (true) { Timeout* timeout = expiredIter.Next(); if (!timeout || totalTimeLimit.IsZero() || timeout->When() > deadline) { if (timeout) { nextDeadline = timeout->When(); } break; } if (IsInvalidFiringId(timeout->mFiringId)) { // Mark any timeouts that are on the list to be fired with the // firing depth so that we can reentrantly run timeouts timeout->mFiringId = firingId; numTimersToRun += 1; // Run only a limited number of timers based on the configured maximum. if (numTimersToRun % kNumTimersPerInitialElapsedCheck == 0) { now = TimeStamp::Now(); TimeDuration elapsed(now - start); if (elapsed >= initialTimeLimit) { nextDeadline = timeout->When(); break; } } } expiredIter.UpdateIterator(); } } now = TimeStamp::Now(); // Wherever we stopped in the timer list, schedule the executor to // run for the next unexpired deadline. Note, this *must* be done // before we start executing any content script handlers. If one // of them spins the event loop the executor must already be scheduled // in order for timeouts to fire properly. if (!nextDeadline.IsNull()) { // Note, we verified the window is not suspended at the top of // method and the window should not have been suspended while // executing the loop above since it doesn't call out to js. MOZ_DIAGNOSTIC_ASSERT(!mWindow.IsSuspended()); MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(nextDeadline, now)); } // Maybe the timeout that the event was fired for has been deleted // and there are no others timeouts with deadlines that make them // eligible for execution yet. Go away. if (!numTimersToRun) { return; } // Now we need to search the normal and tracking timer list at the same // time to run the timers in the scheduled order. // We stop iterating each list when we go past the last expired timeout from // that list that we have observed above. That timeout will either be the // next item after the last timeout we looked at or nullptr if we have // exhausted the entire list while looking for the last expired timeout. { // Use a nested scope in order to make sure the strong references held by // the iterator are freed after the loop. OrderedTimeoutIterator runIter(mNormalTimeouts, mTrackingTimeouts); while (true) { RefPtr<Timeout> timeout = runIter.Next(); if (!timeout) { // We have run out of timeouts! break; } runIter.UpdateIterator(); // We should only execute callbacks for the set of expired Timeout // objects we computed above. if (timeout->mFiringId != firingId) { // If the FiringId does not match, but is still valid, then this is // a TImeout for another RunTimeout() on the call stack. Just // skip it. if (IsValidFiringId(timeout->mFiringId)) { continue; } // If, however, the FiringId is invalid then we have reached Timeout // objects beyond the list we calculated above. This can happen // if the Timeout just beyond our last expired Timeout is cancelled // by one of the callbacks we've just executed. In this case we // should just stop iterating. We're done. else { break; } } MOZ_ASSERT_IF(mWindow.IsFrozen(), mWindow.IsSuspended()); if (mWindow.IsSuspended()) { break; } // The timeout is on the list to run at this depth, go ahead and // process it. // Get the script context (a strong ref to prevent it going away) // for this timeout and ensure the script language is enabled. nsCOMPtr<nsIScriptContext> scx = mWindow.GetContextInternal(); if (!scx) { // No context means this window was closed or never properly // initialized for this language. This timer will never fire // so just remove it. timeout->remove(); continue; } // This timeout is good to run bool timeout_was_cleared = mWindow.RunTimeoutHandler(timeout, scx); MOZ_LOG(gLog, LogLevel::Debug, ("Run%s(TimeoutManager=%p, timeout=%p, tracking=%d) returned %d\n", timeout->mIsInterval ? "Interval" : "Timeout", this, timeout.get(), int(timeout->mIsTracking), !!timeout_was_cleared)); if (timeout_was_cleared) { // Make sure the iterator isn't holding any Timeout objects alive. runIter.Clear(); // Since ClearAllTimeouts() was called the lists should be empty. MOZ_DIAGNOSTIC_ASSERT(!HasTimeouts()); return; } // If we need to reschedule a setInterval() the delay should be // calculated based on when its callback started to execute. So // save off the last time before updating our "now" timestamp to // account for its callback execution time. TimeStamp lastCallbackTime = now; now = TimeStamp::Now(); // If we have a regular interval timer, we re-schedule the // timeout, accounting for clock drift. bool needsReinsertion = RescheduleTimeout(timeout, lastCallbackTime, now); // Running a timeout can cause another timeout to be deleted, so // we need to reset the pointer to the following timeout. runIter.UpdateIterator(); timeout->remove(); if (needsReinsertion) { // Insert interval timeout onto the corresponding list sorted in // deadline order. AddRefs timeout. if (runIter.PickedTrackingIter()) { mTrackingTimeouts.Insert(timeout, mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining : Timeouts::SortBy::TimeWhen); } else { mNormalTimeouts.Insert(timeout, mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining : Timeouts::SortBy::TimeWhen); } } // Check to see if we have run out of time to execute timeout handlers. // If we've exceeded our time budget then terminate the loop immediately. TimeDuration elapsed = now - start; if (elapsed >= totalTimeLimit) { // We ran out of time. Make sure to schedule the executor to // run immediately for the next timer, if it exists. Its possible, // however, that the last timeout handler suspended the window. If // that happened then we must skip this step. if (!mWindow.IsSuspended()) { RefPtr<Timeout> timeout = runIter.Next(); if (timeout) { // If we ran out of execution budget we need to force a // reschedule. By cancelling the executor we will not run // immediately, but instead reschedule to the minimum // scheduling delay. if (mExecutionBudget < TimeDuration()) { mExecutor->Cancel(); } MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(timeout->When(), now)); } } break; } } } }
static PLDHashOperator CheckForGhostWindowsEnumerator(nsISupports *aKey, TimeStamp& aTimeStamp, void* aClosure) { CheckForGhostWindowsEnumeratorData *data = static_cast<CheckForGhostWindowsEnumeratorData*>(aClosure); nsWeakPtr weakKey = do_QueryInterface(aKey); nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(weakKey); if (!window) { // The window object has been destroyed. Stop tracking its weak ref in our // hashtable. return PL_DHASH_REMOVE; } // Avoid calling GetTop() if we have no outer window. Nothing will break if // we do, but it will spew debug output, which can cause our test logs to // overflow. nsCOMPtr<nsPIDOMWindow> top; if (window->GetOuterWindow()) { top = window->GetOuterWindow()->GetTop(); } if (top) { // The window is no longer detached, so we no longer want to track it. return PL_DHASH_REMOVE; } nsCOMPtr<nsIURI> uri = GetWindowURI(window); nsAutoCString domain; if (uri) { // GetBaseDomain works fine if |uri| is null, but it outputs a warning // which ends up overrunning the mochitest logs. data->tldService->GetBaseDomain(uri, 0, domain); } if (data->nonDetachedDomains->Contains(domain)) { // This window shares a domain with a non-detached window, so reset its // clock. aTimeStamp = TimeStamp(); } else { // This window does not share a domain with a non-detached window, so it // meets ghost criterion (2). if (aTimeStamp.IsNull()) { // This may become a ghost window later; start its clock. aTimeStamp = data->now; } else if ((data->now - aTimeStamp).ToSeconds() > data->ghostTimeout) { // This definitely is a ghost window, so add it to ghostWindowIDs, if // that is not null. if (data->ghostWindowIDs) { nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(window); if (pWindow) { data->ghostWindowIDs->PutEntry(pWindow->WindowID()); } } } } return PL_DHASH_NEXT; }
void LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp, EndTransactionFlags aFlags) { NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); NS_ASSERTION(!(aFlags & END_NO_COMPOSITE), "Shouldn't get END_NO_COMPOSITE here"); mInTransaction = false; if (!mIsCompositorReady) { return; } mIsCompositorReady = false; #ifdef MOZ_LAYERS_HAVE_LOG MOZ_LAYERS_LOG((" ----- (beginning paint)")); Log(); #endif if (mDestroyed) { NS_WARNING("Call on destroyed layer manager"); return; } // Set composition timestamp here because we need it in // ComputeEffectiveTransforms (so the correct video frame size is picked) and // also to compute invalid regions properly. mCompositor->SetCompositionTime(aTimeStamp); if (mRoot && mClonedLayerTreeProperties) { MOZ_ASSERT(!mTarget); nsIntRegion invalid = mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged); mClonedLayerTreeProperties = nullptr; mInvalidRegion.Or(mInvalidRegion, invalid); } else if (!mTarget) { mInvalidRegion.Or(mInvalidRegion, mRenderBounds); } if (mInvalidRegion.IsEmpty() && !mTarget) { // Composition requested, but nothing has changed. Don't do any work. return; } if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) { MOZ_ASSERT(!aTimeStamp.IsNull()); // The results of our drawing always go directly into a pixel buffer, // so we don't need to pass any global transform here. mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4()); nsIntRegion opaque; ApplyOcclusionCulling(mRoot, opaque); Render(); #ifdef MOZ_WIDGET_ANDROID RenderToPresentationSurface(); #endif mGeometryChanged = false; } else { // Modified layer tree mGeometryChanged = true; } mCompositor->ClearTargetContext(); mTarget = nullptr; #ifdef MOZ_LAYERS_HAVE_LOG Log(); MOZ_LAYERS_LOG(("]----- EndTransaction")); #endif }
NS_IMETHODIMP nsSocketTransportService::Run() { SOCKET_LOG(("STS thread init %d sockets\n", gMaxCount)); psm::InitializeSSLServerCertVerificationThreads(); gSocketThread = PR_GetCurrentThread(); { MutexAutoLock 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 { MutexAutoLock 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; }