1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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/. */
7 #include "MediaShutdownManager.h"
9 #include "MediaDecoder.h"
10 #include "mozilla/Logging.h"
11 #include "mozilla/media/MediaUtils.h"
12 #include "mozilla/Services.h"
13 #include "mozilla/StaticPtr.h"
19 extern LazyLogModule gMediaDecoderLog
;
20 #define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
21 #define LOGW(...) NS_WARNING(nsPrintfCString(__VA_ARGS__).get())
23 NS_IMPL_ISUPPORTS(MediaShutdownManager
, nsIAsyncShutdownBlocker
)
25 MediaShutdownManager::MediaShutdownManager() {
26 MOZ_ASSERT(NS_IsMainThread());
27 MOZ_DIAGNOSTIC_ASSERT(sInitPhase
== NotInited
);
30 MediaShutdownManager::~MediaShutdownManager() { MOZ_ASSERT(NS_IsMainThread()); }
32 // Note that we don't use ClearOnShutdown() on this StaticRefPtr, as that
33 // may interfere with our shutdown listener.
34 StaticRefPtr
<MediaShutdownManager
> MediaShutdownManager::sInstance
;
36 MediaShutdownManager::InitPhase
MediaShutdownManager::sInitPhase
=
37 MediaShutdownManager::NotInited
;
39 MediaShutdownManager
& MediaShutdownManager::Instance() {
40 MOZ_ASSERT(NS_IsMainThread());
41 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
43 MOZ_CRASH_UNSAFE_PRINTF("sInstance is null. sInitPhase=%d",
50 void MediaShutdownManager::InitStatics() {
51 MOZ_ASSERT(NS_IsMainThread());
52 if (sInitPhase
!= NotInited
) {
56 sInstance
= new MediaShutdownManager();
57 MOZ_DIAGNOSTIC_ASSERT(sInstance
);
59 nsCOMPtr
<nsIAsyncShutdownClient
> barrier
= media::GetShutdownBarrier();
62 LOGW("Failed to get barrier, cannot add shutdown blocker!");
63 sInitPhase
= InitFailed
;
68 barrier
->AddBlocker(sInstance
, NS_LITERAL_STRING_FROM_CSTRING(__FILE__
),
69 __LINE__
, u
"MediaShutdownManager shutdown"_ns
);
71 LOGW("Failed to add shutdown blocker! rv=%x", uint32_t(rv
));
72 sInitPhase
= InitFailed
;
75 sInitPhase
= InitSucceeded
;
78 void MediaShutdownManager::RemoveBlocker() {
79 MOZ_ASSERT(NS_IsMainThread());
80 MOZ_DIAGNOSTIC_ASSERT(sInitPhase
== XPCOMShutdownStarted
);
81 MOZ_ASSERT(mDecoders
.Count() == 0);
82 nsCOMPtr
<nsIAsyncShutdownClient
> barrier
= media::GetShutdownBarrier();
83 // xpcom should still be available because we blocked shutdown by having a
84 // blocker. Until it completely shuts down we should still be able to get
88 "Failed to get shutdown barrier, cannot remove shutdown blocker!");
89 barrier
->RemoveBlocker(this);
90 // Clear our singleton reference. This will probably delete
91 // this instance, so don't deref |this| clearing sInstance.
92 sInitPhase
= XPCOMShutdownEnded
;
94 DECODER_LOG(LogLevel::Debug
, ("MediaShutdownManager::BlockShutdown() end."));
97 nsresult
MediaShutdownManager::Register(MediaDecoder
* aDecoder
) {
98 MOZ_ASSERT(NS_IsMainThread());
99 if (sInitPhase
== InitFailed
) {
100 return NS_ERROR_NOT_INITIALIZED
;
102 if (sInitPhase
== XPCOMShutdownStarted
) {
103 return NS_ERROR_ABORT
;
105 // Don't call Register() after you've Unregistered() all the decoders,
106 // that's not going to work.
107 MOZ_ASSERT(!mDecoders
.Contains(aDecoder
));
108 mDecoders
.Insert(aDecoder
);
109 MOZ_ASSERT(mDecoders
.Contains(aDecoder
));
110 MOZ_ASSERT(mDecoders
.Count() > 0);
114 void MediaShutdownManager::Unregister(MediaDecoder
* aDecoder
) {
115 MOZ_ASSERT(NS_IsMainThread());
116 if (!mDecoders
.EnsureRemoved(aDecoder
)) {
119 if (sInitPhase
== XPCOMShutdownStarted
&& mDecoders
.Count() == 0) {
125 MediaShutdownManager::GetName(nsAString
& aName
) {
126 aName
= u
"MediaShutdownManager: shutdown"_ns
;
131 MediaShutdownManager::GetState(nsIPropertyBag
**) { return NS_OK
; }
134 MediaShutdownManager::BlockShutdown(nsIAsyncShutdownClient
*) {
135 MOZ_ASSERT(NS_IsMainThread());
136 MOZ_DIAGNOSTIC_ASSERT(sInitPhase
== InitSucceeded
);
137 MOZ_DIAGNOSTIC_ASSERT(sInstance
);
139 DECODER_LOG(LogLevel::Debug
,
140 ("MediaShutdownManager::BlockShutdown() start..."));
142 // Set this flag to ensure no Register() is allowed when Shutdown() begins.
143 sInitPhase
= XPCOMShutdownStarted
;
145 auto oldCount
= mDecoders
.Count();
151 // Iterate over the decoders and shut them down.
152 for (const auto& key
: mDecoders
) {
153 key
->NotifyXPCOMShutdown();
154 // Check MediaDecoder::Shutdown doesn't call Unregister() synchronously in
155 // order not to corrupt our hashtable traversal.
156 MOZ_ASSERT(mDecoders
.Count() == oldCount
);
162 } // namespace mozilla
164 // avoid redefined macro in unified build