diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5b7e03a92f09..a041c0f5919c 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1359,6 +1359,12 @@ pref("network.http.enforce-framing.http1", false); pref("network.ftp.data.qos", 0); pref("network.ftp.control.qos", 0); +// If this pref is false only one xpcom event will be served per poll +// iteration. This is the original behavior. +// If it is true multiple events will be served. +pref("network.sts.serve_multiple_events_per_poll_iteration", 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); // // 2147483647 == PR_INT32_MAX == ~2 GB diff --git a/netwerk/base/nsSocketTransportService2.cpp b/netwerk/base/nsSocketTransportService2.cpp index 2bdc7b8e55b3..cad179476578 100644 --- a/netwerk/base/nsSocketTransportService2.cpp +++ b/netwerk/base/nsSocketTransportService2.cpp @@ -40,6 +40,8 @@ PRThread *gSocketThread = nullptr; #define SOCKET_LIMIT_TARGET 550U #define SOCKET_LIMIT_MIN 50U #define BLIP_INTERVAL_PREF "network.activity.blipIntervalMilliseconds" +#define SERVE_MULTIPLE_EVENTS_PREF "network.sts.serve_multiple_events_per_poll_iteration" +#define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls" uint32_t nsSocketTransportService::gMaxCount; PRCallOnceType nsSocketTransportService::gMaxCountInitOnce; @@ -67,6 +69,9 @@ nsSocketTransportService::nsSocketTransportService() , mKeepaliveRetryIntervalS(1) , mKeepaliveProbeCount(kDefaultTCPKeepCount) , mKeepaliveEnabledPref(false) + , mServeMultipleEventsPerPollIter(true) + , mServingPendingQueue(false) + , mMaxTimePerPollIter(100) , mProbedMaxCount(false) { #if defined(PR_LOGGING) @@ -481,6 +486,8 @@ nsSocketTransportService::Init() tmpPrefService->AddObserver(KEEPALIVE_IDLE_TIME_PREF, this, false); tmpPrefService->AddObserver(KEEPALIVE_RETRY_INTERVAL_PREF, this, false); tmpPrefService->AddObserver(KEEPALIVE_PROBE_COUNT_PREF, this, false); + tmpPrefService->AddObserver(SERVE_MULTIPLE_EVENTS_PREF, this, false); + tmpPrefService->AddObserver(MAX_TIME_BETWEEN_TWO_POLLS, this, false); } UpdatePrefs(); @@ -686,6 +693,12 @@ nsSocketTransportService::AfterProcessNextEvent(nsIThreadInternal* thread, return NS_OK; } +void +nsSocketTransportService::MarkTheLastElementOfPendingQueue() +{ + mServingPendingQueue = false; +} + #ifdef MOZ_NUWA_PROCESS #include "ipc/Nuwa.h" #endif @@ -730,15 +743,39 @@ nsSocketTransportService::Run() // If there are pending events for this thread then // DoPollIteration() should service the network without blocking. DoPollIteration(!pendingEvents); - + // If nothing was pending before the poll, it might be now - if (!pendingEvents) + if (!pendingEvents) { thread->HasPendingEvents(&pendingEvents); + } if (pendingEvents) { - NS_ProcessNextEvent(thread); - pendingEvents = false; - thread->HasPendingEvents(&pendingEvents); + if (mServeMultipleEventsPerPollIter) { + 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; + } + } + TimeStamp eventQueueStart = TimeStamp::NowLoRes(); + do { + NS_ProcessNextEvent(thread); + pendingEvents = false; + thread->HasPendingEvents(&pendingEvents); + } while (pendingEvents && mServingPendingQueue && + ((TimeStamp::NowLoRes() - + eventQueueStart).ToMilliseconds() < + mMaxTimePerPollIter)); + } else { + NS_ProcessNextEvent(thread); + pendingEvents = false; + thread->HasPendingEvents(&pendingEvents); + } } } while (pendingEvents); @@ -982,6 +1019,20 @@ nsSocketTransportService::UpdatePrefs() mKeepaliveEnabledPref = keepaliveEnabled; OnKeepaliveEnabledPrefChange(); } + + bool serveMultiplePref = false; + rv = tmpPrefService->GetBoolPref(SERVE_MULTIPLE_EVENTS_PREF, + &serveMultiplePref); + if (NS_SUCCEEDED(rv)) { + mServeMultipleEventsPerPollIter = serveMultiplePref; + } + + int32_t maxTimePref; + rv = tmpPrefService->GetIntPref(MAX_TIME_BETWEEN_TWO_POLLS, + &maxTimePref); + if (NS_SUCCEEDED(rv) && maxTimePref >= 0) { + mMaxTimePerPollIter = maxTimePref; + } } return NS_OK; diff --git a/netwerk/base/nsSocketTransportService2.h b/netwerk/base/nsSocketTransportService2.h index 9bc550fe7d11..9e3fff893968 100644 --- a/netwerk/base/nsSocketTransportService2.h +++ b/netwerk/base/nsSocketTransportService2.h @@ -17,6 +17,7 @@ #include "nsIObserver.h" #include "mozilla/Mutex.h" #include "mozilla/net/DashboardTypes.h" +#include "mozilla/Atomics.h" class nsASocketHandler; struct PRPollDesc; @@ -217,6 +218,10 @@ private: // True if TCP keepalive is enabled globally. bool mKeepaliveEnabledPref; + bool mServeMultipleEventsPerPollIter; + mozilla::Atomic mServingPendingQueue; + int32_t mMaxTimePerPollIter; + void OnKeepaliveEnabledPrefChange(); void NotifyKeepaliveEnabledPrefChange(SocketContext *sock); @@ -233,6 +238,8 @@ private: void DetachSocketWithGuard(bool aGuardLocals, SocketContext *socketList, int32_t index); + + void MarkTheLastElementOfPendingQueue(); }; extern nsSocketTransportService *gSocketTransportService;