Backed out 35 changesets (bug 941158, bug 972518, bug 959520, bug 986063, bug 948895...
[gecko.git] / content / media / MediaShutdownManager.h
blobceea4d76da8271e55e4d79f0381f9c5f780f71c2
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 #if !defined(MediaShutdownManager_h_)
8 #define MediaShutdownManager_h_
10 #include "nsIObserver.h"
11 #include "mozilla/Monitor.h"
12 #include "mozilla/RefPtr.h"
13 #include "mozilla/StaticPtr.h"
14 #include "nsIThread.h"
15 #include "nsCOMPtr.h"
16 #include "nsTHashtable.h"
17 #include "nsHashKeys.h"
19 namespace mozilla {
21 class MediaDecoder;
22 class StateMachineThread;
24 // The MediaShutdownManager manages shutting down the MediaDecoder
25 // infrastructure in response to an xpcom-shutdown notification. This happens
26 // when Gecko is shutting down in the middle of operation. This is tricky, as
27 // there are a number of moving parts that must be shutdown in a particular
28 // order. Additionally the xpcom-shutdown observer *must* block until all
29 // threads are shutdown, which is tricky since we have a number of threads
30 // here and their shutdown is asynchronous. We can't have each element of
31 // our pipeline listening for xpcom-shutdown, as if each observer blocks
32 // waiting for its threads to shutdown it will block other xpcom-shutdown
33 // notifications from firing, and shutdown of one part of the media pipeline
34 // (say the State Machine thread) may depend another part to be shutdown
35 // first (the MediaDecoder threads). Additionally we need to not interfere
36 // with shutdown in the the non-xpcom-shutdown case, where we need to be able
37 // to recreate the State Machine thread after it's been destroyed without
38 // affecting the shutdown of the old State Machine thread. The
39 // MediaShutdownManager encapsulates all these dependencies, and provides
40 // a single xpcom-shutdown listener for the MediaDecoder infrastructure, to
41 // ensure that no shutdown order dependencies leak out of the MediaDecoder
42 // stack. The MediaShutdownManager is a singleton.
44 // The MediaShutdownManager ensures that the MediaDecoder stack is shutdown
45 // before returning from its xpcom-shutdown observer by keeping track of all
46 // the active MediaDecoders, and upon xpcom-shutdown calling Shutdown() on
47 // every MediaDecoder and then spinning the main thread event loop until the
48 // State Machine thread has shutdown. Once the State Machine thread has been
49 // shutdown, the xpcom-shutdown observer returns.
51 // Note that calling the Unregister() functions may result in the singleton
52 // being deleted, so don't store references to the singleton, always use the
53 // singleton by derefing the referenced returned by
54 // MediaShutdownManager::Instance(), which ensures that the singleton is
55 // created when needed.
56 // i.e. like this:
57 // MediaShutdownManager::Instance()::Unregister(someDecoder);
58 // MediaShutdownManager::Instance()::Register(someOtherDecoder);
59 // Not like this:
60 // MediaShutdownManager& instance = MediaShutdownManager::Instance();
61 // instance.Unregister(someDecoder); // Warning! May delete instance!
62 // instance.Register(someOtherDecoder); // BAD! instance may be dangling!
63 class MediaShutdownManager : public nsIObserver {
64 public:
65 NS_DECL_ISUPPORTS
66 NS_DECL_NSIOBSERVER
68 // The MediaShutdownManager is a singleton, access its instance with
69 // this accessor.
70 static MediaShutdownManager& Instance();
72 // Notifies the MediaShutdownManager that it needs to track the shutdown
73 // of this MediaDecoder.
74 void Register(MediaDecoder* aDecoder);
76 // Notifies the MediaShutdownManager that a MediaDecoder that it was
77 // tracking has shutdown, and it no longer needs to be shutdown in the
78 // xpcom-shutdown listener.
79 void Unregister(MediaDecoder* aDecoder);
81 // Notifies the MediaShutdownManager of a state machine thread that
82 // must be tracked. Note that we track State Machine threads individually
83 // as their shutdown and the construction of a new state machine thread
84 // can interleave. This stores a strong ref to the state machine.
85 void Register(StateMachineThread* aThread);
87 // Notifies the MediaShutdownManager that a StateMachineThread that it was
88 // tracking has shutdown, and it no longer needs to be shutdown in the
89 // xpcom-shutdown listener. This drops the strong reference to the
90 // StateMachineThread, which may destroy it.
91 void Unregister(StateMachineThread* aThread);
93 private:
95 MediaShutdownManager();
96 virtual ~MediaShutdownManager();
98 void Shutdown();
100 // Ensures we have a shutdown listener if we need one, and removes the
101 // listener and destroys the singleton if we don't.
102 void EnsureCorrectShutdownObserverState();
104 static StaticRefPtr<MediaShutdownManager> sInstance;
106 // References to the MediaDecoder. The decoders unregister themselves
107 // in their Shutdown() method, so we'll drop the reference naturally when
108 // we're shutting down (in the non xpcom-shutdown case).
109 nsTHashtable<nsRefPtrHashKey<MediaDecoder>> mDecoders;
111 // References to the state machine threads that we're tracking shutdown
112 // of. Note that although there is supposed to be a single state machine,
113 // the construction and shutdown of these can interleave, so we must track
114 // individual instances of the state machine threads.
115 // These are strong references.
116 nsTHashtable<nsRefPtrHashKey<StateMachineThread>> mStateMachineThreads;
118 // True if we have an XPCOM shutdown observer.
119 bool mIsObservingShutdown;
121 bool mIsDoingXPCOMShutDown;
124 // A wrapper for the state machine thread. We must wrap this so that the
125 // state machine threads can shutdown independently from the
126 // StateMachineTracker, under the control of the MediaShutdownManager.
127 // The state machine thread is shutdown naturally when all decoders
128 // complete their shutdown. So if a new decoder is created just as the
129 // old state machine thread has shutdown, we need to be able to shutdown
130 // the old state machine thread independently of the StateMachineTracker
131 // creating a new state machine thread. Also if this happens we need to
132 // be able to force both state machine threads to shutdown in the
133 // MediaShutdownManager, which is why we maintain a set of state machine
134 // threads, even though there's supposed to only be one alive at once.
135 // This class does not enforce its own thread safety, the StateMachineTracker
136 // ensures thread safety when it uses the StateMachineThread.
137 class StateMachineThread {
138 public:
139 StateMachineThread();
140 ~StateMachineThread();
142 NS_INLINE_DECL_REFCOUNTING(StateMachineThread);
144 // Creates the wrapped thread.
145 nsresult Init();
147 // Returns a reference to the underlying thread. Don't shut this down
148 // directly, use StateMachineThread::Shutdown() instead.
149 nsIThread* GetThread();
151 // Dispatches an event to the main thread to shutdown the wrapped thread.
152 // The owner's (StateMachineTracker's) reference to the StateMachineThread
153 // can be dropped, the StateMachineThread will shutdown itself
154 // asynchronously.
155 void Shutdown();
157 // Processes events on the main thread event loop until this thread
158 // has been shutdown. Use this to block until the asynchronous shutdown
159 // has complete.
160 void SpinUntilShutdownComplete();
162 private:
163 void ShutdownThread();
164 nsCOMPtr<nsIThread> mThread;
167 } // namespace mozilla
169 #endif