Bug 1442178 - Do a busy wait of socket poll() shortly after network change detection, r=dragana

This commit is contained in:
Honza Bambas 2018-05-30 17:36:42 +03:00
Родитель dab22ca3b9
Коммит 8a9d38fe70
7 изменённых файлов: 94 добавлений и 5 удалений

Просмотреть файл

@ -1783,6 +1783,16 @@ pref("network.ftp.enabled", true);
// The max time to spend on xpcom events between two polls in ms.
pref("network.sts.max_time_for_events_between_two_polls", 100);
// The number of seconds we don't let poll() handing indefinitely after network
// link change has been detected so we can detect breakout of the pollable event.
// Expected in seconds, 0 to disable.
pref("network.sts.poll_busy_wait_period", 50);
// The number of seconds we cap poll() timeout to during the network link change
// detection period.
// Expected in seconds, 0 to disable.
pref("network.sts.poll_busy_wait_period_timeout", 7);
// During shutdown we limit PR_Close calls. If time exceeds this pref (in ms)
// let sockets just leak.
pref("network.sts.max_time_for_pr_close_during_shutdown", 5000);

Просмотреть файл

@ -48,6 +48,7 @@
#include "mozilla/net/DNS.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/net/NeckoParent.h"
#include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ServiceWorkerDescriptor.h"
@ -1554,12 +1555,30 @@ nsIOService::GetManageOfflineStatus(bool* aManage)
nsresult
nsIOService::OnNetworkLinkEvent(const char *data)
{
LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data));
if (!mNetworkLinkService)
return NS_ERROR_FAILURE;
if (IsNeckoChild()) {
// There is nothing IO service could do on the child process
// with this at the moment. Feel free to add functionality
// here at will, though.
return NS_OK;
}
if (mShutdown)
if (mShutdown) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCString dataAsString(data);
for (auto* cp : mozilla::dom::ContentParent::AllProcesses(mozilla::dom::ContentParent::eLive)) {
PNeckoParent* neckoParent = SingleManagedOrNull(cp->ManagedPNeckoParent());
if (!neckoParent) {
continue;
}
Unused << neckoParent->SendNetworkChangeNotification(dataAsString);
}
LOG(("nsIOService::OnNetworkLinkEvent data:%s\n", data));
if (!mNetworkLinkService) {
return NS_ERROR_FAILURE;
}
if (!mManageLinkStatus) {
LOG(("nsIOService::OnNetworkLinkEvent mManageLinkStatus=false\n"));
@ -1573,7 +1592,8 @@ nsIOService::OnNetworkLinkEvent(const char *data)
// but the status of the captive portal may have changed.
RecheckCaptivePortal();
return NS_OK;
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
}
if (!strcmp(data, NS_NETWORK_LINK_DATA_DOWN)) {
isUp = false;
} else if (!strcmp(data, NS_NETWORK_LINK_DATA_UP)) {
isUp = true;

Просмотреть файл

@ -51,6 +51,8 @@ static Atomic<PRThread*, Relaxed> gSocketThread;
#define SOCKET_LIMIT_MIN 50U
#define INTERVAL_PREF "network.activity.intervalMilliseconds"
#define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls"
#define POLL_BUSY_WAIT_PERIOD "network.sts.poll_busy_wait_period"
#define POLL_BUSY_WAIT_PERIOD_TIMEOUT "network.sts.poll_busy_wait_period_timeout"
#define TELEMETRY_PREF "toolkit.telemetry.enabled"
#define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown"
#define POLLABLE_EVENT_TIMEOUT "network.sts.pollable_event_timeout"
@ -141,6 +143,9 @@ nsSocketTransportService::nsSocketTransportService()
, mMaxTimePerPollIter(100)
, mTelemetryEnabledPref(false)
, mMaxTimeForPrClosePref(PR_SecondsToInterval(5))
, mLastNetworkLinkChangeTime(0)
, mNetworkLinkChangeBusyWaitPeriod(PR_SecondsToInterval(50))
, mNetworkLinkChangeBusyWaitTimeout(PR_SecondsToInterval(7))
, mSleepPhase(false)
, mProbedMaxCount(false)
#if defined(XP_WIN)
@ -541,6 +546,16 @@ nsSocketTransportService::Poll(TimeDuration *pollDuration,
pendingEvents ? PR_INTERVAL_NO_WAIT : PR_MillisecondsToInterval(25);
}
if ((ts - mLastNetworkLinkChangeTime) < mNetworkLinkChangeBusyWaitPeriod) {
// Being here means we are few seconds after a network change has
// been detected.
PRIntervalTime to = mNetworkLinkChangeBusyWaitTimeout;
if (to) {
pollTimeout = std::min(to, pollTimeout);
SOCKET_LOG((" timeout shorthened after network change event"));
}
}
TimeStamp pollStart;
if (mTelemetryEnabledPref) {
pollStart = TimeStamp::NowLoRes();
@ -619,6 +634,7 @@ nsSocketTransportService::Init()
obsSvc->AddObserver(this, NS_WIDGET_SLEEP_OBSERVER_TOPIC, true);
obsSvc->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, true);
obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
obsSvc->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
}
mInitialized = true;
@ -687,6 +703,7 @@ nsSocketTransportService::ShutdownThread()
obsSvc->RemoveObserver(this, NS_WIDGET_SLEEP_OBSERVER_TOPIC);
obsSvc->RemoveObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC);
obsSvc->RemoveObserver(this, "xpcom-shutdown-threads");
obsSvc->RemoveObserver(this, NS_NETWORK_LINK_TOPIC);
}
if (mAfterWakeUpTimer) {
@ -1336,6 +1353,18 @@ nsSocketTransportService::UpdatePrefs()
mMaxTimePerPollIter = maxTimePref;
}
int32_t pollBusyWaitPeriod;
rv = tmpPrefService->GetIntPref(POLL_BUSY_WAIT_PERIOD, &pollBusyWaitPeriod);
if (NS_SUCCEEDED(rv) && pollBusyWaitPeriod > 0) {
mNetworkLinkChangeBusyWaitPeriod = PR_SecondsToInterval(pollBusyWaitPeriod);
}
int32_t pollBusyWaitPeriodTimeout;
rv = tmpPrefService->GetIntPref(POLL_BUSY_WAIT_PERIOD_TIMEOUT, &pollBusyWaitPeriodTimeout);
if (NS_SUCCEEDED(rv) && pollBusyWaitPeriodTimeout > 0) {
mNetworkLinkChangeBusyWaitTimeout = PR_SecondsToInterval(pollBusyWaitPeriodTimeout);
}
bool telemetryPref = false;
rv = tmpPrefService->GetBoolPref(TELEMETRY_PREF,
&telemetryPref);
@ -1409,6 +1438,8 @@ nsSocketTransportService::Observe(nsISupports *subject,
const char *topic,
const char16_t *data)
{
SOCKET_LOG(("nsSocketTransportService::Observe topic=%s", topic));
if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
UpdatePrefs();
return NS_OK;
@ -1458,6 +1489,8 @@ nsSocketTransportService::Observe(nsISupports *subject,
}
} else if (!strcmp(topic, "xpcom-shutdown-threads")) {
ShutdownThread();
} else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
mLastNetworkLinkChangeTime = PR_IntervalNow();
}
return NS_OK;

Просмотреть файл

@ -254,6 +254,15 @@ private:
Atomic<int32_t, Relaxed> mMaxTimePerPollIter;
Atomic<bool, Relaxed> mTelemetryEnabledPref;
Atomic<PRIntervalTime, Relaxed> mMaxTimeForPrClosePref;
// Timestamp of the last network link change event, tracked
// also on child processes.
Atomic<PRIntervalTime, Relaxed> mLastNetworkLinkChangeTime;
// Preference for how long we do busy wait after network link
// change has been detected.
Atomic<PRIntervalTime, Relaxed> mNetworkLinkChangeBusyWaitPeriod;
// Preference for the value of timeout for poll() we use during
// the network link change event period.
Atomic<PRIntervalTime, Relaxed> mNetworkLinkChangeBusyWaitTimeout;
// Between a computer going to sleep and waking up the PR_*** telemetry
// will be corrupted - so do not record it.

Просмотреть файл

@ -32,6 +32,7 @@
#include "nsIOService.h"
#include "nsINetworkPredictor.h"
#include "nsINetworkPredictorVerifier.h"
#include "nsINetworkLinkService.h"
#include "mozilla/ipc/URIUtils.h"
#include "nsNetUtil.h"
@ -450,6 +451,17 @@ NeckoChild::RecvSpeculativeConnectRequest()
return IPC_OK();
}
mozilla::ipc::IPCResult
NeckoChild::RecvNetworkChangeNotification(nsCString const& type)
{
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC,
NS_ConvertUTF8toUTF16(type).get());
}
return IPC_OK();
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -95,6 +95,7 @@ protected:
virtual mozilla::ipc::IPCResult RecvPredOnPredictDNS(const URIParams& aURI) override;
virtual mozilla::ipc::IPCResult RecvSpeculativeConnectRequest() override;
virtual mozilla::ipc::IPCResult RecvNetworkChangeNotification(nsCString const& type) override;
};
/**

Просмотреть файл

@ -147,6 +147,10 @@ child:
async SpeculativeConnectRequest();
// Using high priority to deliver this notification possibly sooner than we
// enter poll() on the child process with infinite timeout.
prio(high) async NetworkChangeNotification(nsCString type);
async PTransportProvider();
both: