Line data Source code
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/. */
6 :
7 : #include "mozilla/Logging.h"
8 : #include "mozilla/StaticPtr.h"
9 : #include "nsContentUtils.h"
10 :
11 : #include "MediaDecoder.h"
12 : #include "MediaShutdownManager.h"
13 :
14 : namespace mozilla {
15 :
16 : #undef LOGW
17 :
18 : extern LazyLogModule gMediaDecoderLog;
19 : #define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
20 : #define LOGW(...) NS_WARNING(nsPrintfCString(__VA_ARGS__).get())
21 :
22 0 : NS_IMPL_ISUPPORTS(MediaShutdownManager, nsIAsyncShutdownBlocker)
23 :
24 0 : MediaShutdownManager::MediaShutdownManager()
25 : {
26 0 : MOZ_ASSERT(NS_IsMainThread());
27 0 : MOZ_DIAGNOSTIC_ASSERT(sInitPhase == NotInited);
28 0 : }
29 :
30 0 : MediaShutdownManager::~MediaShutdownManager()
31 : {
32 0 : MOZ_ASSERT(NS_IsMainThread());
33 0 : }
34 :
35 : // Note that we don't use ClearOnShutdown() on this StaticRefPtr, as that
36 : // may interfere with our shutdown listener.
37 3 : StaticRefPtr<MediaShutdownManager> MediaShutdownManager::sInstance;
38 :
39 : MediaShutdownManager::InitPhase MediaShutdownManager::sInitPhase = MediaShutdownManager::NotInited;
40 :
41 : MediaShutdownManager&
42 0 : MediaShutdownManager::Instance()
43 : {
44 0 : MOZ_ASSERT(NS_IsMainThread());
45 : #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
46 0 : if (!sInstance) {
47 0 : MOZ_CRASH_UNSAFE_PRINTF("sInstance is null. sInitPhase=%d", int(sInitPhase));
48 : }
49 : #endif
50 0 : return *sInstance;
51 : }
52 :
53 : static nsCOMPtr<nsIAsyncShutdownClient>
54 0 : GetShutdownBarrier()
55 : {
56 0 : nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
57 0 : MOZ_RELEASE_ASSERT(svc);
58 :
59 0 : nsCOMPtr<nsIAsyncShutdownClient> barrier;
60 0 : nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(barrier));
61 0 : if (!barrier) {
62 : // We are probably in a content process. We need to do cleanup at
63 : // XPCOM shutdown in leakchecking builds.
64 0 : rv = svc->GetXpcomWillShutdown(getter_AddRefs(barrier));
65 : }
66 0 : MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
67 0 : MOZ_RELEASE_ASSERT(barrier);
68 0 : return barrier.forget();
69 : }
70 :
71 : void
72 0 : MediaShutdownManager::InitStatics()
73 : {
74 0 : MOZ_ASSERT(NS_IsMainThread());
75 0 : if (sInitPhase != NotInited) {
76 0 : return;
77 : }
78 :
79 0 : sInstance = new MediaShutdownManager();
80 0 : MOZ_DIAGNOSTIC_ASSERT(sInstance);
81 :
82 0 : nsresult rv = GetShutdownBarrier()->AddBlocker(
83 0 : sInstance, NS_LITERAL_STRING(__FILE__), __LINE__,
84 0 : NS_LITERAL_STRING("MediaShutdownManager shutdown"));
85 0 : if (NS_FAILED(rv)) {
86 0 : LOGW("Failed to add shutdown blocker! rv=%x", uint32_t(rv));
87 0 : sInitPhase = InitFailed;
88 0 : return;
89 : }
90 0 : sInitPhase = InitSucceeded;
91 : }
92 :
93 : void
94 0 : MediaShutdownManager::RemoveBlocker()
95 : {
96 0 : MOZ_ASSERT(NS_IsMainThread());
97 0 : MOZ_DIAGNOSTIC_ASSERT(sInitPhase == XPCOMShutdownStarted);
98 0 : MOZ_ASSERT(mDecoders.Count() == 0);
99 0 : GetShutdownBarrier()->RemoveBlocker(this);
100 : // Clear our singleton reference. This will probably delete
101 : // this instance, so don't deref |this| clearing sInstance.
102 0 : sInitPhase = XPCOMShutdownEnded;
103 0 : sInstance = nullptr;
104 0 : DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() end."));
105 0 : }
106 :
107 : nsresult
108 0 : MediaShutdownManager::Register(MediaDecoder* aDecoder)
109 : {
110 0 : MOZ_ASSERT(NS_IsMainThread());
111 0 : if (sInitPhase == InitFailed) {
112 0 : return NS_ERROR_NOT_INITIALIZED;
113 : }
114 0 : if (sInitPhase == XPCOMShutdownStarted) {
115 0 : return NS_ERROR_ABORT;
116 : }
117 : // Don't call Register() after you've Unregistered() all the decoders,
118 : // that's not going to work.
119 0 : MOZ_ASSERT(!mDecoders.Contains(aDecoder));
120 0 : mDecoders.PutEntry(aDecoder);
121 0 : MOZ_ASSERT(mDecoders.Contains(aDecoder));
122 0 : MOZ_ASSERT(mDecoders.Count() > 0);
123 0 : return NS_OK;
124 : }
125 :
126 : void
127 0 : MediaShutdownManager::Unregister(MediaDecoder* aDecoder)
128 : {
129 0 : MOZ_ASSERT(NS_IsMainThread());
130 0 : if (!mDecoders.Contains(aDecoder)) {
131 0 : return;
132 : }
133 0 : mDecoders.RemoveEntry(aDecoder);
134 0 : if (sInitPhase == XPCOMShutdownStarted && mDecoders.Count() == 0) {
135 0 : RemoveBlocker();
136 : }
137 : }
138 :
139 : NS_IMETHODIMP
140 0 : MediaShutdownManager::GetName(nsAString& aName)
141 : {
142 0 : aName = NS_LITERAL_STRING("MediaShutdownManager: shutdown");
143 0 : return NS_OK;
144 : }
145 :
146 : NS_IMETHODIMP
147 0 : MediaShutdownManager::GetState(nsIPropertyBag**)
148 : {
149 0 : return NS_OK;
150 : }
151 :
152 : NS_IMETHODIMP
153 0 : MediaShutdownManager::BlockShutdown(nsIAsyncShutdownClient*)
154 : {
155 0 : MOZ_ASSERT(NS_IsMainThread());
156 0 : MOZ_DIAGNOSTIC_ASSERT(sInitPhase == InitSucceeded);
157 0 : MOZ_DIAGNOSTIC_ASSERT(sInstance);
158 :
159 0 : DECODER_LOG(LogLevel::Debug, ("MediaShutdownManager::BlockShutdown() start..."));
160 :
161 : // Set this flag to ensure no Register() is allowed when Shutdown() begins.
162 0 : sInitPhase = XPCOMShutdownStarted;
163 :
164 0 : auto oldCount = mDecoders.Count();
165 0 : if (oldCount == 0) {
166 0 : RemoveBlocker();
167 0 : return NS_OK;
168 : }
169 :
170 : // Iterate over the decoders and shut them down.
171 0 : for (auto iter = mDecoders.Iter(); !iter.Done(); iter.Next()) {
172 0 : iter.Get()->GetKey()->NotifyXPCOMShutdown();
173 : // Check MediaDecoder::Shutdown doesn't call Unregister() synchronously in
174 : // order not to corrupt our hashtable traversal.
175 0 : MOZ_ASSERT(mDecoders.Count() == oldCount);
176 : }
177 :
178 0 : return NS_OK;
179 : }
180 :
181 : } // namespace mozilla
182 :
183 : // avoid redefined macro in unified build
184 : #undef LOGW
|