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 "IPCBlobInputStreamThread.h"
8 :
9 : #include "mozilla/StaticMutex.h"
10 : #include "mozilla/SystemGroup.h"
11 : #include "mozilla/TaskCategory.h"
12 : #include "mozilla/ipc/BackgroundChild.h"
13 : #include "mozilla/ipc/PBackgroundChild.h"
14 : #include "nsIIPCBackgroundChildCreateCallback.h"
15 : #include "nsXPCOMPrivate.h"
16 :
17 : namespace mozilla {
18 :
19 : using namespace ipc;
20 :
21 : namespace dom {
22 :
23 : namespace {
24 :
25 3 : StaticMutex gIPCBlobThreadMutex;
26 3 : StaticRefPtr<IPCBlobInputStreamThread> gIPCBlobThread;
27 : bool gShutdownHasStarted = false;
28 :
29 0 : class ThreadInitializeRunnable final : public Runnable
30 : {
31 : public:
32 0 : ThreadInitializeRunnable() : Runnable("dom::ThreadInitializeRunnable") {}
33 :
34 : NS_IMETHOD
35 0 : Run() override
36 : {
37 0 : mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
38 0 : MOZ_ASSERT(gIPCBlobThread);
39 0 : gIPCBlobThread->Initialize();
40 0 : return NS_OK;
41 : }
42 : };
43 :
44 : class MigrateActorRunnable final : public Runnable
45 : , public nsIIPCBackgroundChildCreateCallback
46 : {
47 : public:
48 : NS_DECL_ISUPPORTS_INHERITED
49 :
50 0 : explicit MigrateActorRunnable(IPCBlobInputStreamChild* aActor)
51 0 : : Runnable("dom::MigrateActorRunnable")
52 0 : , mActor(aActor)
53 : {
54 0 : MOZ_ASSERT(mActor);
55 0 : }
56 :
57 : NS_IMETHOD
58 0 : Run() override
59 : {
60 0 : BackgroundChild::GetOrCreateForCurrentThread(this);
61 0 : return NS_OK;
62 : }
63 :
64 : void
65 0 : ActorFailed() override
66 : {
67 : // We cannot continue. We are probably shutting down.
68 0 : }
69 :
70 : void
71 0 : ActorCreated(mozilla::ipc::PBackgroundChild* aActor) override
72 : {
73 0 : MOZ_ASSERT(mActor->State() == IPCBlobInputStreamChild::eInactiveMigrating);
74 :
75 0 : if (aActor->SendPIPCBlobInputStreamConstructor(mActor, mActor->ID(),
76 0 : mActor->Size())) {
77 : // We need manually to increase the reference for this actor because the
78 : // IPC allocator method is not triggered. The Release() is called by IPDL
79 : // when the actor is deleted.
80 0 : mActor.get()->AddRef();
81 0 : mActor->Migrated();
82 : }
83 0 : }
84 :
85 : private:
86 0 : ~MigrateActorRunnable() = default;
87 :
88 : RefPtr<IPCBlobInputStreamChild> mActor;
89 : };
90 :
91 0 : NS_IMPL_ISUPPORTS_INHERITED(MigrateActorRunnable, Runnable,
92 : nsIIPCBackgroundChildCreateCallback)
93 :
94 : } // anonymous
95 :
96 0 : NS_IMPL_ISUPPORTS(IPCBlobInputStreamThread, nsIObserver)
97 :
98 : /* static */ bool
99 0 : IPCBlobInputStreamThread::IsOnFileEventTarget(nsIEventTarget* aEventTarget)
100 : {
101 0 : MOZ_ASSERT(aEventTarget);
102 :
103 0 : mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
104 0 : return gIPCBlobThread && aEventTarget == gIPCBlobThread->mThread;
105 : }
106 :
107 : /* static */ IPCBlobInputStreamThread*
108 0 : IPCBlobInputStreamThread::GetOrCreate()
109 : {
110 0 : mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
111 :
112 0 : if (gShutdownHasStarted) {
113 0 : return nullptr;
114 : }
115 :
116 0 : if (!gIPCBlobThread) {
117 0 : gIPCBlobThread = new IPCBlobInputStreamThread();
118 0 : gIPCBlobThread->Initialize();
119 : }
120 :
121 0 : return gIPCBlobThread;
122 : }
123 :
124 : void
125 0 : IPCBlobInputStreamThread::Initialize()
126 : {
127 0 : if (!NS_IsMainThread()) {
128 0 : RefPtr<Runnable> runnable = new ThreadInitializeRunnable();
129 0 : SystemGroup::Dispatch("IPCBlobInputStreamThread::Initialize",
130 : TaskCategory::Other,
131 0 : runnable.forget());
132 0 : return;
133 : }
134 :
135 0 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
136 0 : if (NS_WARN_IF(!obs)) {
137 0 : return;
138 : }
139 :
140 : nsresult rv =
141 0 : obs->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
142 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
143 0 : return;
144 : }
145 :
146 0 : nsCOMPtr<nsIThread> thread;
147 0 : rv = NS_NewNamedThread("DOM File", getter_AddRefs(thread));
148 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
149 0 : return;
150 : }
151 :
152 0 : mThread = thread;
153 :
154 0 : if (!mPendingActors.IsEmpty()) {
155 0 : for (uint32_t i = 0; i < mPendingActors.Length(); ++i) {
156 0 : MigrateActorInternal(mPendingActors[i]);
157 : }
158 :
159 0 : mPendingActors.Clear();
160 : }
161 : }
162 :
163 : NS_IMETHODIMP
164 0 : IPCBlobInputStreamThread::Observe(nsISupports* aSubject,
165 : const char* aTopic,
166 : const char16_t* aData)
167 : {
168 0 : MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
169 :
170 0 : mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
171 :
172 0 : if (mThread) {
173 0 : mThread->Shutdown();
174 0 : mThread = nullptr;
175 : }
176 :
177 0 : gShutdownHasStarted = true;
178 0 : gIPCBlobThread = nullptr;
179 :
180 0 : return NS_OK;
181 : }
182 :
183 : void
184 0 : IPCBlobInputStreamThread::MigrateActor(IPCBlobInputStreamChild* aActor)
185 : {
186 0 : MOZ_ASSERT(aActor->State() == IPCBlobInputStreamChild::eInactiveMigrating);
187 :
188 0 : mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
189 :
190 0 : if (gShutdownHasStarted) {
191 0 : return;
192 : }
193 :
194 0 : if (!mThread) {
195 : // The thread is not initialized yet.
196 0 : mPendingActors.AppendElement(aActor);
197 0 : return;
198 : }
199 :
200 0 : MigrateActorInternal(aActor);
201 : }
202 :
203 : void
204 0 : IPCBlobInputStreamThread::MigrateActorInternal(IPCBlobInputStreamChild* aActor)
205 : {
206 0 : RefPtr<Runnable> runnable = new MigrateActorRunnable(aActor);
207 0 : mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
208 0 : }
209 :
210 : } // dom namespace
211 : } // mozilla namespace
|