Bug 1415779 P1 Add the ClientManager class. r=baku
authorBen Kelly <ben@wanderview.com>
Wed, 08 Nov 2017 21:19:59 -0800
changeset 444194 9e7aaf5d40a43df2e7adad1d4726b9032b08bce6
parent 444149 e368fe33afd342ed8540df982ce4ef0d37617940
child 444195 92dfd261775af060e831f6db5520e5eab5d39a6c
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1415779
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1415779 P1 Add the ClientManager class. r=baku
dom/clients/manager/ClientManager.cpp
dom/clients/manager/ClientManager.h
dom/clients/manager/ClientSourceChild.cpp
dom/clients/manager/moz.build
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientManager.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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/. */
+
+#include "ClientManager.h"
+
+#include "ClientManagerChild.h"
+#include "ClientManagerOpChild.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/workers/bindings/WorkerHolderToken.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+#include "prthread.h"
+
+namespace mozilla {
+namespace dom {
+
+using mozilla::ipc::BackgroundChild;
+using mozilla::ipc::PBackgroundChild;
+using mozilla::dom::workers::Closing;
+using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
+using mozilla::dom::workers::WorkerHolderToken;
+using mozilla::dom::workers::WorkerPrivate;
+
+namespace {
+
+uint32_t kBadThreadLocalIndex = -1;
+uint32_t sClientManagerThreadLocalIndex = kBadThreadLocalIndex;
+
+} // anonymous namespace
+
+ClientManager::ClientManager()
+{
+  PBackgroundChild* parentActor = BackgroundChild::GetOrCreateForCurrentThread();
+  if (NS_WARN_IF(!parentActor)) {
+    Shutdown();
+    return;
+  }
+
+  RefPtr<WorkerHolderToken> workerHolderToken;
+  if (!NS_IsMainThread()) {
+    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+    MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
+
+    workerHolderToken =
+      WorkerHolderToken::Create(workerPrivate, Closing,
+                                WorkerHolderToken::AllowIdleShutdownStart);
+    if (NS_WARN_IF(!workerHolderToken)) {
+      Shutdown();
+      return;
+    }
+  }
+
+  ClientManagerChild* actor = new ClientManagerChild(workerHolderToken);
+  PClientManagerChild *sentActor =
+    parentActor->SendPClientManagerConstructor(actor);
+  if (NS_WARN_IF(!sentActor)) {
+    Shutdown();
+    return;
+  }
+  MOZ_DIAGNOSTIC_ASSERT(sentActor == actor);
+
+  ActivateThing(actor);
+}
+
+ClientManager::~ClientManager()
+{
+  NS_ASSERT_OWNINGTHREAD(ClientManager);
+
+  Shutdown();
+
+  MOZ_DIAGNOSTIC_ASSERT(this == PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
+  PRStatus status =
+    PR_SetThreadPrivate(sClientManagerThreadLocalIndex, nullptr);
+  MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
+}
+
+void
+ClientManager::Shutdown()
+{
+  NS_ASSERT_OWNINGTHREAD(ClientManager);
+
+  if (IsShutdown()) {
+    return;
+  }
+
+  ShutdownThing();
+}
+
+already_AddRefed<ClientOpPromise>
+ClientManager::StartOp(const ClientOpConstructorArgs& aArgs,
+                       nsISerialEventTarget* aSerialEventTarget)
+{
+  RefPtr<ClientOpPromise::Private> promise =
+    new ClientOpPromise::Private(__func__);
+
+  // Hold a ref to the client until the remote operation completes.  Otherwise
+  // the ClientHandle might get de-refed and teardown the actor before we
+  // get an answer.
+  RefPtr<ClientManager> kungFuGrip = this;
+  promise->Then(aSerialEventTarget, __func__,
+                [kungFuGrip] (const ClientOpResult&) { },
+                [kungFuGrip] (nsresult) { });
+
+  MaybeExecute([aArgs, promise] (ClientManagerChild* aActor) {
+    ClientManagerOpChild* actor = new ClientManagerOpChild(aArgs, promise);
+    if (!aActor->SendPClientManagerOpConstructor(actor, aArgs)) {
+      // Constructor failure will reject promise via ActorDestroy()
+      return;
+    }
+  });
+
+  RefPtr<ClientOpPromise> ref = promise.get();
+  return ref.forget();
+}
+
+// static
+already_AddRefed<ClientManager>
+ClientManager::GetOrCreateForCurrentThread()
+{
+  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
+  RefPtr<ClientManager> cm =
+    static_cast<ClientManager*>(PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
+
+  if (!cm) {
+    cm = new ClientManager();
+
+    PRStatus status =
+      PR_SetThreadPrivate(sClientManagerThreadLocalIndex, cm.get());
+    MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
+  }
+
+  MOZ_ASSERT(cm);
+  return cm.forget();
+}
+
+WorkerPrivate*
+ClientManager::GetWorkerPrivate() const
+{
+  NS_ASSERT_OWNINGTHREAD(ClientManager);
+  MOZ_DIAGNOSTIC_ASSERT(GetActor());
+  return GetActor()->GetWorkerPrivate();
+}
+
+// static
+void
+ClientManager::Startup()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  PRStatus status =
+    PR_NewThreadPrivateIndex(&sClientManagerThreadLocalIndex, nullptr);
+  MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/clients/manager/ClientManager.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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/. */
+#ifndef _mozilla_dom_ClientManager_h
+#define _mozilla_dom_ClientManager_h
+
+#include "mozilla/dom/ClientOpPromise.h"
+#include "mozilla/dom/ClientThing.h"
+
+namespace mozilla {
+namespace ipc {
+class PBackgroundChild;
+} // namespace ipc
+namespace dom {
+
+class ClientManagerChild;
+class ClientOpConstructorArgs;
+
+namespace workers {
+class WorkerPrivate;
+} // workers namespace
+
+// The ClientManager provides a per-thread singleton interface workering
+// with the client subsystem.  It allows globals to create ClientSource
+// objects.  It allows other parts of the system to attach to this globals
+// by creating ClientHandle objects.  The ClientManager also provides
+// methods for querying the list of clients active in the system.
+class ClientManager final : public ClientThing<ClientManagerChild>
+{
+  friend class ClientManagerChild;
+
+  ClientManager();
+  ~ClientManager();
+
+  // Utility method to trigger a shutdown of the ClientManager.  This
+  // is called in various error conditions or when the last reference
+  // is dropped.
+  void
+  Shutdown();
+
+  // Utility method to perform an IPC operation.  This will create a
+  // PClientManagerOp actor tied to a MozPromise.  The promise will
+  // resolve or reject with the result of the remote operation.
+  already_AddRefed<ClientOpPromise>
+  StartOp(const ClientOpConstructorArgs& aArgs,
+          nsISerialEventTarget* aSerialEventTarget);
+
+  // Get or create the TLS singleton.  Currently this is only used
+  // internally and external code indirectly calls it by invoking
+  // static methods.
+  static already_AddRefed<ClientManager>
+  GetOrCreateForCurrentThread();
+
+  // Private methods called by ClientSource
+  mozilla::dom::workers::WorkerPrivate*
+  GetWorkerPrivate() const;
+
+public:
+  // Initialize the ClientManager at process start.  This
+  // does book-keeping like creating a TLS identifier, etc.
+  // This should only be called by process startup code.
+  static void
+  Startup();
+
+  NS_INLINE_DECL_REFCOUNTING(mozilla::dom::ClientManager)
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // _mozilla_dom_ClientManager_h
--- a/dom/clients/manager/ClientSourceChild.cpp
+++ b/dom/clients/manager/ClientSourceChild.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 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/. */
 
 #include "ClientSourceChild.h"
 
 #include "ClientSourceOpChild.h"
+#include "ClientThing.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::IPCResult;
 
--- a/dom/clients/manager/moz.build
+++ b/dom/clients/manager/moz.build
@@ -2,29 +2,31 @@
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS.mozilla.dom += [
   'ClientInfo.h',
   'ClientIPCUtils.h',
+  'ClientManager.h',
   'ClientManagerActors.h',
   'ClientOpenWindowOpActors.h',
   'ClientOpPromise.h',
   'ClientState.h',
   'ClientThing.h',
 ]
 
 UNIFIED_SOURCES += [
   'ClientHandleChild.cpp',
   'ClientHandleOpChild.cpp',
   'ClientHandleOpParent.cpp',
   'ClientHandleParent.cpp',
   'ClientInfo.cpp',
+  'ClientManager.cpp',
   'ClientManagerActors.cpp',
   'ClientManagerChild.cpp',
   'ClientManagerOpChild.cpp',
   'ClientManagerOpParent.cpp',
   'ClientManagerParent.cpp',
   'ClientNavigateOpChild.cpp',
   'ClientNavigateOpParent.cpp',
   'ClientOpenWindowOpActors.cpp',
@@ -47,16 +49,17 @@ IPDL_SOURCES += [
   'PClientOpenWindowOp.ipdl',
   'PClientSource.ipdl',
   'PClientSourceOp.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
+  '/dom/workers',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 MOCHITEST_MANIFESTS += [
 ]
 
 BROWSER_CHROME_MANIFESTS += [
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/Unused.h"
 #include "mozilla/TelemetryIPC.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
+#include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientOpenWindowOpActors.h"
 #include "mozilla/dom/ContentBridgeChild.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/VideoDecoderManagerChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
@@ -1149,16 +1150,18 @@ ContentChild::InitXPCOM(const XPCOMInitD
   BackgroundChild::Startup();
 
   PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
   if (NS_WARN_IF(!actorChild)) {
     MOZ_ASSERT_UNREACHABLE("PBackground init can't fail at this point");
     return;
   }
 
+  ClientManager::Startup();
+
   nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
   if (!svc) {
     NS_WARNING("Couldn't acquire console service");
     return;
   }
 
   mConsoleListener = new ConsoleListener(this);
   if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -29,16 +29,17 @@
 #include "mozilla/a11y/Compatibility.h"
 #endif
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/DataStorage.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
 #include "mozilla/docshell/OfflineCacheUpdateParent.h"
+#include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientOpenWindowOpActors.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileCreatorHelper.h"
 #include "mozilla/dom/FileSystemSecurity.h"
 #include "mozilla/dom/IPCBlobUtils.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
@@ -623,16 +624,17 @@ ContentParent::StartUp()
   }
 
   // Note: This reporter measures all ContentParents.
   RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
 
   mozilla::dom::time::InitializeDateCacheCleaner();
 
   BackgroundChild::Startup();
+  ClientManager::Startup();
 
   sDisableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS");
 
 #if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
   sSandboxBrokerPolicyFactory = MakeUnique<SandboxBrokerPolicyFactory>();
 #endif
 }