|
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 "MediaShutdownManager.h" |
|
8 #include "nsContentUtils.h" |
|
9 #include "mozilla/StaticPtr.h" |
|
10 #include "MediaDecoder.h" |
|
11 #include "SharedThreadPool.h" |
|
12 #include "prlog.h" |
|
13 |
|
14 namespace mozilla { |
|
15 |
|
16 #ifdef PR_LOGGING |
|
17 extern PRLogModuleInfo* gMediaDecoderLog; |
|
18 #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) |
|
19 #else |
|
20 #define DECODER_LOG(type, msg) |
|
21 #endif |
|
22 |
|
23 NS_IMPL_ISUPPORTS(MediaShutdownManager, nsIObserver) |
|
24 |
|
25 MediaShutdownManager::MediaShutdownManager() |
|
26 : mIsObservingShutdown(false), |
|
27 mIsDoingXPCOMShutDown(false) |
|
28 { |
|
29 MOZ_ASSERT(NS_IsMainThread()); |
|
30 MOZ_COUNT_CTOR(MediaShutdownManager); |
|
31 } |
|
32 |
|
33 MediaShutdownManager::~MediaShutdownManager() |
|
34 { |
|
35 MOZ_ASSERT(NS_IsMainThread()); |
|
36 MOZ_COUNT_DTOR(MediaShutdownManager); |
|
37 } |
|
38 |
|
39 // Note that we don't use ClearOnShutdown() on this StaticRefPtr, as that |
|
40 // may interfere with our shutdown listener. |
|
41 StaticRefPtr<MediaShutdownManager> MediaShutdownManager::sInstance; |
|
42 |
|
43 MediaShutdownManager& |
|
44 MediaShutdownManager::Instance() |
|
45 { |
|
46 MOZ_ASSERT(NS_IsMainThread()); |
|
47 if (!sInstance) { |
|
48 sInstance = new MediaShutdownManager(); |
|
49 } |
|
50 return *sInstance; |
|
51 } |
|
52 |
|
53 void |
|
54 MediaShutdownManager::EnsureCorrectShutdownObserverState() |
|
55 { |
|
56 MOZ_ASSERT(!mIsDoingXPCOMShutDown); |
|
57 bool needShutdownObserver = mDecoders.Count() > 0; |
|
58 if (needShutdownObserver != mIsObservingShutdown) { |
|
59 mIsObservingShutdown = needShutdownObserver; |
|
60 if (mIsObservingShutdown) { |
|
61 nsContentUtils::RegisterShutdownObserver(this); |
|
62 } else { |
|
63 nsContentUtils::UnregisterShutdownObserver(this); |
|
64 // Clear our singleton reference. This will probably delete |
|
65 // this instance, so don't deref |this| clearing sInstance. |
|
66 sInstance = nullptr; |
|
67 } |
|
68 } |
|
69 } |
|
70 |
|
71 void |
|
72 MediaShutdownManager::Register(MediaDecoder* aDecoder) |
|
73 { |
|
74 MOZ_ASSERT(NS_IsMainThread()); |
|
75 // Don't call Register() after you've Unregistered() all the decoders, |
|
76 // that's not going to work. |
|
77 MOZ_ASSERT(!mDecoders.Contains(aDecoder)); |
|
78 mDecoders.PutEntry(aDecoder); |
|
79 MOZ_ASSERT(mDecoders.Contains(aDecoder)); |
|
80 MOZ_ASSERT(mDecoders.Count() > 0); |
|
81 EnsureCorrectShutdownObserverState(); |
|
82 } |
|
83 |
|
84 void |
|
85 MediaShutdownManager::Unregister(MediaDecoder* aDecoder) |
|
86 { |
|
87 MOZ_ASSERT(NS_IsMainThread()); |
|
88 MOZ_ASSERT(mDecoders.Contains(aDecoder)); |
|
89 if (!mIsDoingXPCOMShutDown) { |
|
90 mDecoders.RemoveEntry(aDecoder); |
|
91 EnsureCorrectShutdownObserverState(); |
|
92 } |
|
93 } |
|
94 |
|
95 NS_IMETHODIMP |
|
96 MediaShutdownManager::Observe(nsISupports *aSubjet, |
|
97 const char *aTopic, |
|
98 const char16_t *someData) |
|
99 { |
|
100 MOZ_ASSERT(NS_IsMainThread()); |
|
101 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { |
|
102 Shutdown(); |
|
103 } |
|
104 return NS_OK; |
|
105 } |
|
106 |
|
107 static PLDHashOperator |
|
108 ShutdownMediaDecoder(nsRefPtrHashKey<MediaDecoder>* aEntry, void*) |
|
109 { |
|
110 aEntry->GetKey()->Shutdown(); |
|
111 return PL_DHASH_REMOVE; |
|
112 } |
|
113 |
|
114 void |
|
115 MediaShutdownManager::Shutdown() |
|
116 { |
|
117 MOZ_ASSERT(NS_IsMainThread()); |
|
118 MOZ_ASSERT(sInstance); |
|
119 |
|
120 DECODER_LOG(PR_LOG_DEBUG, ("MediaShutdownManager::Shutdown() start...")); |
|
121 |
|
122 // Mark that we're shutting down, so that Unregister(*) calls don't remove |
|
123 // hashtable entries. If Unregsiter(*) was to remove from the hash table, |
|
124 // the iterations over the hashtables below would be disrupted. |
|
125 mIsDoingXPCOMShutDown = true; |
|
126 |
|
127 // Iterate over the decoders and shut them down, and remove them from the |
|
128 // hashtable. |
|
129 mDecoders.EnumerateEntries(ShutdownMediaDecoder, nullptr); |
|
130 |
|
131 // Ensure all media shared thread pools are shutdown. This joins with all |
|
132 // threads in the state machine thread pool, the decoder thread pool, and |
|
133 // any others. |
|
134 SharedThreadPool::SpinUntilShutdown(); |
|
135 |
|
136 // Remove the MediaShutdownManager instance from the shutdown observer |
|
137 // list. |
|
138 nsContentUtils::UnregisterShutdownObserver(this); |
|
139 |
|
140 // Clear the singleton instance. The only remaining reference should be the |
|
141 // reference that the observer service used to call us with. The |
|
142 // MediaShutdownManager will be deleted once the observer service cleans |
|
143 // up after it finishes its notifications. |
|
144 sInstance = nullptr; |
|
145 |
|
146 DECODER_LOG(PR_LOG_DEBUG, ("MediaShutdownManager::Shutdown() end.")); |
|
147 } |
|
148 |
|
149 } // namespace mozilla |