diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 265c3c26a17e..7c52e07435b8 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -48,6 +48,7 @@ #include "mozilla/dom/Voicemail.h" #include "mozilla/dom/TVManager.h" #include "mozilla/dom/VRDevice.h" +#include "mozilla/dom/workers/RuntimeService.h" #include "mozilla/Hal.h" #include "nsISiteSpecificUserAgent.h" #include "mozilla/ClearOnShutdown.h" @@ -750,6 +751,17 @@ Navigator::JavaEnabled(ErrorResult& aRv) return mimeType && mimeType->GetEnabledPlugin(); } +uint64_t +Navigator::HardwareConcurrency() +{ + workers::RuntimeService* rts = workers::RuntimeService::GetOrCreateService(); + if (!rts) { + return 1; + } + + return rts->ClampedHardwareConcurrency(); +} + void Navigator::RefreshMIMEArray() { diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 17b40535a2ab..741641c0bcfd 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -219,6 +219,7 @@ public: } PowerManager* GetMozPower(ErrorResult& aRv); bool JavaEnabled(ErrorResult& aRv); + uint64_t HardwareConcurrency(); bool TaintEnabled() { return false; diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index bd23fcd3c5fe..73be72b8bbf6 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -326,6 +326,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1 [test_innersize_scrollport.html] [test_messagemanager_targetchain.html] [test_named_frames.html] +[test_navigator_hardwareConcurrency.html] [test_navigator_resolve_identity.html] [test_navigator_language.html] [test_noAudioNotification.html] diff --git a/dom/base/test/test_navigator_hardwareConcurrency.html b/dom/base/test/test_navigator_hardwareConcurrency.html new file mode 100644 index 000000000000..b48e640e62fd --- /dev/null +++ b/dom/base/test/test_navigator_hardwareConcurrency.html @@ -0,0 +1,24 @@ + + + + + Test for Navigator.hardwareConcurrency + + + + + +

+ +
+
+ + diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index 8f649210e66f..ec9b202301e5 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -12,6 +12,7 @@ * http://www.w3.org/2012/sysapps/runtime/#extension-to-the-navigator-interface-1 * https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#navigator-interface-extension * http://www.w3.org/TR/beacon/#sec-beacon-method + * https://html.spec.whatwg.org/#navigatorconcurrenthardware * * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and * Opera Software ASA. You are granted a license to use, reproduce @@ -29,6 +30,7 @@ Navigator implements NavigatorOnLine; Navigator implements NavigatorContentUtils; Navigator implements NavigatorStorageUtils; Navigator implements NavigatorFeatures; +Navigator implements NavigatorConcurrentHardware; [NoInterfaceObject, Exposed=(Window,Worker)] interface NavigatorID { @@ -476,3 +478,8 @@ partial interface Navigator { DOMRequest mozPay(any jwts); }; #endif + +[NoInterfaceObject, Exposed=(Window,Worker)] +interface NavigatorConcurrentHardware { + readonly attribute unsigned long long hardwareConcurrency; +}; diff --git a/dom/webidl/WorkerNavigator.webidl b/dom/webidl/WorkerNavigator.webidl index 1b5118eae965..faa715fd9c10 100644 --- a/dom/webidl/WorkerNavigator.webidl +++ b/dom/webidl/WorkerNavigator.webidl @@ -11,3 +11,4 @@ WorkerNavigator implements NavigatorID; WorkerNavigator implements NavigatorLanguage; WorkerNavigator implements NavigatorOnLine; WorkerNavigator implements NavigatorDataStore; +WorkerNavigator implements NavigatorConcurrentHardware; diff --git a/dom/workers/Navigator.cpp b/dom/workers/Navigator.cpp index 9d6ab860f100..18ed152a8f00 100644 --- a/dom/workers/Navigator.cpp +++ b/dom/workers/Navigator.cpp @@ -399,4 +399,13 @@ WorkerNavigator::GetUserAgent(nsString& aUserAgent, ErrorResult& aRv) const runnable->Dispatch(aRv); } +uint64_t +WorkerNavigator::HardwareConcurrency() const +{ + RuntimeService* rts = RuntimeService::GetService(); + MOZ_ASSERT(rts); + + return rts->ClampedHardwareConcurrency(); +} + END_WORKERS_NAMESPACE diff --git a/dom/workers/Navigator.h b/dom/workers/Navigator.h index 00ef5d9a61cf..c4bdb6271d2b 100644 --- a/dom/workers/Navigator.h +++ b/dom/workers/Navigator.h @@ -112,6 +112,8 @@ public: const nsAString& aName, const nsAString& aOwner, ErrorResult& aRv); + + uint64_t HardwareConcurrency() const; }; END_WORKERS_NAMESPACE diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 95d67fc65392..398d9eed5ec9 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -26,6 +26,7 @@ #include "GeckoProfiler.h" #include "jsfriendapi.h" #include "mozilla/ArrayUtils.h" +#include "mozilla/Atomics.h" #include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" @@ -68,6 +69,7 @@ #include "WorkerRunnable.h" #include "WorkerScope.h" #include "WorkerThread.h" +#include "prsystem.h" using namespace mozilla; using namespace mozilla::dom; @@ -2452,6 +2454,28 @@ RuntimeService::SendOfflineStatusChangeEventToAllWorkers(bool aIsOffline) BROADCAST_ALL_WORKERS(OfflineStatusChangeEvent, aIsOffline); } +uint32_t +RuntimeService::ClampedHardwareConcurrency() const +{ + // This needs to be atomic, because multiple workers, and even mainthread, + // could race to initialize it at once. + static Atomic clampedHardwareConcurrency; + + // No need to loop here: if compareExchange fails, that just means that some + // other worker has initialized numberOfProcessors, so we're good to go. + if (!clampedHardwareConcurrency) { + int32_t numberOfProcessors = PR_GetNumberOfProcessors(); + if (numberOfProcessors <= 0) { + numberOfProcessors = 1; // Must be one there somewhere + } + uint32_t clampedValue = std::min(uint32_t(numberOfProcessors), + gMaxWorkersPerDomain); + clampedHardwareConcurrency.compareExchange(0, clampedValue); + } + + return clampedHardwareConcurrency; +} + // nsISupports NS_IMPL_ISUPPORTS(RuntimeService, nsIObserver) diff --git a/dom/workers/RuntimeService.h b/dom/workers/RuntimeService.h index 2bfef45907ee..c640a9d5706d 100644 --- a/dom/workers/RuntimeService.h +++ b/dom/workers/RuntimeService.h @@ -249,6 +249,8 @@ public: void SendOfflineStatusChangeEventToAllWorkers(bool aIsOffline); + uint32_t ClampedHardwareConcurrency() const; + private: RuntimeService(); ~RuntimeService(); diff --git a/dom/workers/moz.build b/dom/workers/moz.build index f791cfb2278f..7cff244c08b5 100644 --- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -21,6 +21,7 @@ EXPORTS.mozilla.dom += [ ] EXPORTS.mozilla.dom.workers += [ + 'RuntimeService.h', 'ServiceWorkerManager.h', 'WorkerDebuggerManager.h', 'Workers.h', diff --git a/dom/workers/test/mochitest.ini b/dom/workers/test/mochitest.ini index c1ed89b09218..cd0bb2da084a 100644 --- a/dom/workers/test/mochitest.ini +++ b/dom/workers/test/mochitest.ini @@ -258,3 +258,4 @@ skip-if = (os == "win") || (os == "mac") || toolkit == 'android' #bug 798220 [test_sharedWorker_ports.html] [test_sharedWorker_lifetime.html] [test_fileReader.html] +[test_navigator_workers_hardwareConcurrency.html] diff --git a/dom/workers/test/navigator_worker.js b/dom/workers/test/navigator_worker.js index 2af41014bec2..8e564fde8608 100644 --- a/dom/workers/test/navigator_worker.js +++ b/dom/workers/test/navigator_worker.js @@ -15,6 +15,7 @@ var supportedProps = [ "onLine", "language", "languages", + "hardwareConcurrency", ]; self.onmessage = function(event) { diff --git a/dom/workers/test/test_navigator_workers_hardwareConcurrency.html b/dom/workers/test/test_navigator_workers_hardwareConcurrency.html new file mode 100644 index 000000000000..6fbbc75a9260 --- /dev/null +++ b/dom/workers/test/test_navigator_workers_hardwareConcurrency.html @@ -0,0 +1,30 @@ + + + + + Test for Navigator.hardwareConcurrency + + + + + +

+ +
+
+ +