/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ;*; */ /* vim: set sw=2 ts=8 et tw=80 : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This is used to prevent adding tail pending requests after shutdown staticbool sShutdown = false;
// nsIRequestContext class RequestContext final : public nsIRequestContext, public nsITimerCallback, public nsINamed { public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIREQUESTCONTEXT
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSINAMED
explicit RequestContext(const uint64_t id);
private: virtual ~RequestContext();
void ProcessTailQueue(nsresult aResult); // Reschedules the timer if needed void ScheduleUnblock(); // Hard-reschedules the timer void RescheduleUntailTimer(TimeStamp const& now);
using PendingTailRequest = nsCOMPtr<nsIRequestTailUnblockCallback>; // Number of known opened non-tailed requets
uint32_t mNonTailRequests; // Queue of requests that have been tailed, when conditions are met // we call each of them to unblock and drop the reference
nsTArray<PendingTailRequest> mTailQueue; // Loosly scheduled timer, never scheduled further to the future than // mUntailAt time
nsCOMPtr<nsITimer> mUntailTimer; // Timestamp when the timer is expected to fire, // always less than or equal to mUntailAt
TimeStamp mTimerScheduledAt; // Timestamp when we want to actually untail queued requets based on // the number of request count change in the past; iff this timestamp // is set, we tail requests
TimeStamp mUntailAt;
// Timestamp of the navigation start time, set to Now() in BeginLoad(). // This is used to progressively lower the maximum delay time so that // we can't get to a situation when a number of repetitive requests // on the page causes forever tailing.
TimeStamp mBeginLoadTime;
// This member is true only between DOMContentLoaded notification and // next document load beginning for this request context. // Top level request contexts are recycled. bool mAfterDOMContentLoaded;
};
if (IsNeckoChild()) { // Tailing is not supported on the child process if (gNeckoChild) {
gNeckoChild->SendRequestContextLoadBegin(mID);
} return NS_OK;
}
if (IsNeckoChild()) { // Tailing is not supported on the child process if (gNeckoChild) {
gNeckoChild->SendRequestContextAfterDOMContentLoaded(mID);
} return NS_OK;
}
if (mAfterDOMContentLoaded) { // There is a possibility of a duplicate notification return NS_OK;
}
mAfterDOMContentLoaded = true;
// Conditions for the delay calculation has changed.
ScheduleUnblock(); return NS_OK;
}
if (!mBeginLoadTime.IsNull()) { // We decrease the maximum delay progressively with the time since the page // load begin. This seems like a reasonable and clear heuristic allowing us // to start loading tailed requests in a deterministic time after the load // has started.
if (!mAfterDOMContentLoaded) { // Before DOMContentLoaded notification we want to make sure that tailed // requests don't start when there is a short delay during which we may // not have any active requests on the page happening.
delay += quantum;
}
TimeStamp now = TimeStamp::NowLoRes();
mUntailAt = now + TimeDuration::FromMilliseconds(delay.value());
if (mTimerScheduledAt.IsNull() || mUntailAt < mTimerScheduledAt) {
LOG(("RequestContext %p timer would fire too late, rescheduling", this));
RescheduleUntailTimer(now);
}
}
TimeDuration interval = mUntailAt - now; if (!mTimerScheduledAt.IsNull() && mUntailAt < mTimerScheduledAt) { // When the number of untailed requests goes down, // let's half the interval, since it's likely we would // reschedule for a shorter time again very soon. // This will likely save rescheduling this timer.
interval = interval / int64_t(2);
mTimerScheduledAt = mUntailAt - interval;
} else {
mTimerScheduledAt = mUntailAt;
}
// Stop untail timer if all tail requests are canceled. if (removed && mTailQueue.IsEmpty()) { if (mUntailTimer) {
mUntailTimer->Cancel();
mUntailTimer = nullptr;
}
// Must drop to allow re-engage of the timer
mTimerScheduledAt = TimeStamp();
}
rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); if (NS_FAILED(rv)) { return rv;
}
obs->AddObserver(this, "content-document-interactive", false); if (NS_FAILED(rv)) { return rv;
}
return NS_OK;
}
void RequestContextService::Shutdown() {
MOZ_ASSERT(NS_IsMainThread()); // We need to do this to prevent the requests from being scheduled after // shutdown. for (constauto& data : mTable.Values()) {
data->CancelTailPendingRequests(NS_ERROR_ABORT);
}
mTable.Clear();
sShutdown = true;
}
if (!strcmp("content-document-interactive", topic)) {
nsCOMPtr<dom::Document> document(do_QueryInterface(subject));
MOZ_ASSERT(document); // We want this be triggered also for iframes, since those track their // own request context ids. if (!document) { return NS_OK;
}
nsIDocShell* ds = document->GetDocShell(); // XML documents don't always have a docshell assigned if (!ds) { return NS_OK;
}
nsCOMPtr<nsIDocumentLoader> dl(do_QueryInterface(ds)); if (!dl) { return NS_OK;
}
nsCOMPtr<nsILoadGroup> lg;
dl->GetLoadGroup(getter_AddRefs(lg)); if (!lg) { return NS_OK;
}
nsCOMPtr<nsIRequestContext> rc;
GetRequestContextFromLoadGroup(lg, getter_AddRefs(rc)); if (rc) {
rc->DOMContentLoaded();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.