LCOV - code coverage report
Current view: top level - docshell/base/timeline - TimelineConsumers.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 29 133 21.8 %
Date: 2017-07-14 16:53:18 Functions: 7 22 31.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "TimelineConsumers.h"
       8             : 
       9             : #include "mozilla/ClearOnShutdown.h"
      10             : #include "nsAppRunner.h" // for XRE_IsContentProcess, XRE_IsParentProcess
      11             : #include "nsDocShell.h"
      12             : 
      13             : namespace mozilla {
      14             : 
      15        1082 : NS_IMPL_ISUPPORTS(TimelineConsumers, nsIObserver);
      16             : 
      17           3 : StaticMutex TimelineConsumers::sMutex;
      18             : 
      19             : // Manually manage this singleton's lifetime and destroy it before shutdown.
      20             : // This avoids the leakchecker detecting false-positive memory leaks when
      21             : // using automatic memory management (i.e. statically instantiating this
      22             : // singleton inside the `Get` method), which would automatically destroy it on
      23             : // application shutdown, but too late for the leakchecker. Sigh...
      24           3 : StaticRefPtr<TimelineConsumers> TimelineConsumers::sInstance;
      25             : 
      26             : // This flag makes sure the singleton never gets instantiated while a shutdown
      27             : // is in progress. This can actually happen, and `ClearOnShutdown` doesn't work
      28             : // in these cases.
      29             : bool TimelineConsumers::sInShutdown = false;
      30             : 
      31             : already_AddRefed<TimelineConsumers>
      32         538 : TimelineConsumers::Get()
      33             : {
      34             :   // Using this class is not supported yet for other processes other than
      35             :   // parent or content. To avoid accidental checks to methods like `IsEmpty`,
      36             :   // which would probably always be true in those cases, assert here.
      37             :   // Remember, there will be different singletons available to each process.
      38         538 :   MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsParentProcess());
      39             : 
      40             :   // If we are shutting down, don't bother doing anything. Note: we can only
      41             :   // know whether or not we're in shutdown if we're instantiated.
      42         538 :   if (sInShutdown) {
      43           0 :     return nullptr;
      44             :   }
      45             : 
      46             :   // Note: We don't simply check `sInstance` for null-ness here, since otherwise
      47             :   // this can resurrect the TimelineConsumers pretty late during shutdown.
      48             :   // We won't know if we're in shutdown or not though, because the singleton
      49             :   // could have been destroyed or just never instantiated, so in the previous
      50             :   // conditional `sInShutdown` would be false.
      51             :   static bool firstTime = true;
      52         538 :   if (firstTime) {
      53           3 :     firstTime = false;
      54             : 
      55           6 :     StaticMutexAutoLock lock(sMutex);
      56           3 :     sInstance = new TimelineConsumers();
      57             : 
      58             :     // Make sure the initialization actually suceeds, otherwise don't allow
      59             :     // access by destroying the instance immediately.
      60           3 :     if (sInstance->Init()) {
      61           3 :       ClearOnShutdown(&sInstance);
      62             :     } else {
      63           0 :       sInstance->RemoveObservers();
      64           0 :       sInstance = nullptr;
      65             :     }
      66             :   }
      67             : 
      68        1076 :   RefPtr<TimelineConsumers> copy = sInstance.get();
      69         538 :   return copy.forget();
      70             : }
      71             : 
      72             : bool
      73           3 : TimelineConsumers::Init()
      74             : {
      75           6 :   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
      76           3 :   if (!obs) {
      77           0 :     return false;
      78             :   }
      79           3 :   if (NS_WARN_IF(NS_FAILED(
      80             :     obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)))) {
      81           0 :     return false;
      82             :   }
      83           3 :   return true;
      84             : }
      85             : 
      86             : bool
      87           0 : TimelineConsumers::RemoveObservers()
      88             : {
      89           0 :   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
      90           0 :   if (!obs) {
      91           0 :     return false;
      92             :   }
      93           0 :   if (NS_WARN_IF(NS_FAILED(
      94             :     obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)))) {
      95           0 :     return false;
      96             :   }
      97           0 :   return true;
      98             : }
      99             : 
     100             : nsresult
     101           0 : TimelineConsumers::Observe(nsISupports* aSubject,
     102             :                            const char* aTopic,
     103             :                            const char16_t* aData)
     104             : {
     105           0 :   if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     106           0 :     sInShutdown = true;
     107           0 :     RemoveObservers();
     108           0 :     return NS_OK;
     109             :   }
     110             : 
     111           0 :   MOZ_ASSERT(false, "TimelineConsumers got unexpected topic!");
     112             :   return NS_ERROR_UNEXPECTED;
     113             : }
     114             : 
     115           3 : TimelineConsumers::TimelineConsumers()
     116           3 :   : mActiveConsumers(0)
     117             : {
     118           3 : }
     119             : 
     120             : void
     121           0 : TimelineConsumers::AddConsumer(nsDocShell* aDocShell)
     122             : {
     123           0 :   MOZ_ASSERT(NS_IsMainThread());
     124           0 :   StaticMutexAutoLock lock(sMutex); // for `mActiveConsumers` and `mMarkersStores`.
     125             : 
     126           0 :   UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
     127           0 :   MOZ_ASSERT(!observed);
     128             : 
     129           0 :   mActiveConsumers++;
     130             : 
     131           0 :   ObservedDocShell* obsDocShell = new ObservedDocShell(aDocShell);
     132           0 :   MarkersStorage* storage = static_cast<MarkersStorage*>(obsDocShell);
     133             : 
     134           0 :   observed.reset(obsDocShell);
     135           0 :   mMarkersStores.insertFront(storage);
     136           0 : }
     137             : 
     138             : void
     139           0 : TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell)
     140             : {
     141           0 :   MOZ_ASSERT(NS_IsMainThread());
     142           0 :   StaticMutexAutoLock lock(sMutex); // for `mActiveConsumers` and `mMarkersStores`.
     143             : 
     144           0 :   UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
     145           0 :   MOZ_ASSERT(observed);
     146             : 
     147           0 :   mActiveConsumers--;
     148             : 
     149             :   // Clear all markers from the `mTimelineMarkers` store.
     150           0 :   observed.get()->ClearMarkers();
     151             :   // Remove self from the `mMarkersStores` store.
     152           0 :   observed.get()->remove();
     153             :   // Prepare for becoming a consumer later.
     154           0 :   observed.reset(nullptr);
     155           0 : }
     156             : 
     157             : bool
     158         320 : TimelineConsumers::HasConsumer(nsIDocShell* aDocShell)
     159             : {
     160         320 :   MOZ_ASSERT(NS_IsMainThread());
     161             :   return aDocShell
     162         320 :        ? aDocShell->GetRecordProfileTimelineMarkers()
     163         320 :        : false;
     164             : }
     165             : 
     166             : bool
     167          81 : TimelineConsumers::IsEmpty()
     168             : {
     169         162 :   StaticMutexAutoLock lock(sMutex); // for `mActiveConsumers`.
     170         162 :   return mActiveConsumers == 0;
     171             : }
     172             : 
     173             : void
     174           0 : TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
     175             :                                         const char* aName,
     176             :                                         MarkerTracingType aTracingType,
     177             :                                         MarkerStackRequest aStackRequest)
     178             : {
     179           0 :   MOZ_ASSERT(NS_IsMainThread());
     180           0 :   if (HasConsumer(aDocShell)) {
     181           0 :     aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTracingType, aStackRequest)));
     182             :   }
     183           0 : }
     184             : 
     185             : void
     186           0 : TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
     187             :                                         const char* aName,
     188             :                                         const TimeStamp& aTime,
     189             :                                         MarkerTracingType aTracingType,
     190             :                                         MarkerStackRequest aStackRequest)
     191             : {
     192           0 :   MOZ_ASSERT(NS_IsMainThread());
     193           0 :   if (HasConsumer(aDocShell)) {
     194           0 :     aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTime, aTracingType, aStackRequest)));
     195             :   }
     196           0 : }
     197             : 
     198             : void
     199           0 : TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
     200             :                                         UniquePtr<AbstractTimelineMarker>&& aMarker)
     201             : {
     202           0 :   MOZ_ASSERT(NS_IsMainThread());
     203           0 :   if (HasConsumer(aDocShell)) {
     204           0 :     aDocShell->mObserved->AddMarker(Move(aMarker));
     205             :   }
     206           0 : }
     207             : 
     208             : void
     209           0 : TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
     210             :                                         const char* aName,
     211             :                                         MarkerTracingType aTracingType,
     212             :                                         MarkerStackRequest aStackRequest)
     213             : {
     214           0 :   MOZ_ASSERT(NS_IsMainThread());
     215           0 :   AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTracingType, aStackRequest);
     216           0 : }
     217             : 
     218             : void
     219           0 : TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
     220             :                                         const char* aName,
     221             :                                         const TimeStamp& aTime,
     222             :                                         MarkerTracingType aTracingType,
     223             :                                         MarkerStackRequest aStackRequest)
     224             : {
     225           0 :   MOZ_ASSERT(NS_IsMainThread());
     226           0 :   AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTime, aTracingType, aStackRequest);
     227           0 : }
     228             : 
     229             : void
     230           0 : TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
     231             :                                         UniquePtr<AbstractTimelineMarker>&& aMarker)
     232             : {
     233           0 :   MOZ_ASSERT(NS_IsMainThread());
     234           0 :   AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), Move(aMarker));
     235           0 : }
     236             : 
     237             : void
     238           0 : TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
     239             :                                                     MarkerTracingType aTracingType,
     240             :                                                     MarkerStackRequest aStackRequest /* = STACK */)
     241             : {
     242           0 :   bool isMainThread = NS_IsMainThread();
     243           0 :   StaticMutexAutoLock lock(sMutex); // for `mMarkersStores`.
     244             : 
     245           0 :   for (MarkersStorage* storage = mMarkersStores.getFirst();
     246           0 :        storage != nullptr;
     247           0 :        storage = storage->getNext()) {
     248             :     UniquePtr<AbstractTimelineMarker> marker =
     249           0 :       MakeUnique<TimelineMarker>(aName, aTracingType, aStackRequest);
     250           0 :     if (isMainThread) {
     251           0 :       storage->AddMarker(Move(marker));
     252             :     } else {
     253           0 :       storage->AddOTMTMarker(Move(marker));
     254             :     }
     255             :   }
     256           0 : }
     257             : 
     258             : void
     259           0 : TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
     260             :                                                     const TimeStamp& aTime,
     261             :                                                     MarkerTracingType aTracingType,
     262             :                                                     MarkerStackRequest aStackRequest /* = STACK */)
     263             : {
     264           0 :   bool isMainThread = NS_IsMainThread();
     265           0 :   StaticMutexAutoLock lock(sMutex); // for `mMarkersStores`.
     266             : 
     267           0 :   for (MarkersStorage* storage = mMarkersStores.getFirst();
     268           0 :        storage != nullptr;
     269           0 :        storage = storage->getNext()) {
     270             :     UniquePtr<AbstractTimelineMarker> marker =
     271           0 :       MakeUnique<TimelineMarker>(aName, aTime, aTracingType, aStackRequest);
     272           0 :     if (isMainThread) {
     273           0 :       storage->AddMarker(Move(marker));
     274             :     } else {
     275           0 :       storage->AddOTMTMarker(Move(marker));
     276             :     }
     277             :   }
     278           0 : }
     279             : 
     280             : void
     281           0 : TimelineConsumers::AddMarkerForAllObservedDocShells(UniquePtr<AbstractTimelineMarker>& aMarker)
     282             : {
     283           0 :   bool isMainThread = NS_IsMainThread();
     284           0 :   StaticMutexAutoLock lock(sMutex); // for `mMarkersStores`.
     285             : 
     286           0 :   for (MarkersStorage* storage = mMarkersStores.getFirst();
     287           0 :        storage != nullptr;
     288           0 :        storage = storage->getNext()) {
     289           0 :     UniquePtr<AbstractTimelineMarker> clone = aMarker->Clone();
     290           0 :     if (isMainThread) {
     291           0 :       storage->AddMarker(Move(clone));
     292             :     } else {
     293           0 :       storage->AddOTMTMarker(Move(clone));
     294             :     }
     295             :   }
     296           0 : }
     297             : 
     298             : void
     299           0 : TimelineConsumers::PopMarkers(nsDocShell* aDocShell,
     300             :                               JSContext* aCx,
     301             :                               nsTArray<dom::ProfileTimelineMarker>& aStore)
     302             : {
     303           0 :   MOZ_ASSERT(NS_IsMainThread());
     304             : 
     305           0 :   if (!aDocShell || !aDocShell->mObserved) {
     306           0 :     return;
     307             :   }
     308             : 
     309           0 :   aDocShell->mObserved->PopMarkers(aCx, aStore);
     310             : }
     311             : 
     312             : } // namespace mozilla

Generated by: LCOV version 1.13