|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "base/process_util.h" |
|
6 #include "mozilla/Assertions.h" |
|
7 #include "mozilla/Atomics.h" |
|
8 #include "mozilla/ClearOnShutdown.h" |
|
9 #include "mozilla/DebugOnly.h" |
|
10 #include "mozilla/Services.h" |
|
11 #include "mozilla/StaticPtr.h" |
|
12 #include "mozilla/unused.h" |
|
13 #include "mozilla/dom/ContentChild.h" |
|
14 #include "mozilla/dom/ContentParent.h" |
|
15 #include "mozilla/ipc/ProtocolTypes.h" |
|
16 #include "BackgroundChild.h" |
|
17 #include "BackgroundChildImpl.h" |
|
18 #include "BackgroundParent.h" |
|
19 #include "BackgroundParentImpl.h" |
|
20 #include "GeckoProfiler.h" |
|
21 #include "nsAutoPtr.h" |
|
22 #include "nsCOMPtr.h" |
|
23 #include "nsIEventTarget.h" |
|
24 #include "nsIIPCBackgroundChildCreateCallback.h" |
|
25 #include "nsIObserver.h" |
|
26 #include "nsIObserverService.h" |
|
27 #include "nsIRunnable.h" |
|
28 #include "nsISupportsImpl.h" |
|
29 #include "nsIThread.h" |
|
30 #include "nsITimer.h" |
|
31 #include "nsTArray.h" |
|
32 #include "nsThreadUtils.h" |
|
33 #include "nsTraceRefcnt.h" |
|
34 #include "nsXULAppAPI.h" |
|
35 #include "nsXPCOMPrivate.h" |
|
36 #include "prthread.h" |
|
37 |
|
38 #ifdef RELEASE_BUILD |
|
39 #define THREADSAFETY_ASSERT MOZ_ASSERT |
|
40 #else |
|
41 #define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT |
|
42 #endif |
|
43 |
|
44 #define CRASH_IN_CHILD_PROCESS(_msg) \ |
|
45 do { \ |
|
46 if (IsMainProcess()) { \ |
|
47 MOZ_ASSERT(false, _msg); \ |
|
48 } else { \ |
|
49 MOZ_CRASH(_msg); \ |
|
50 } \ |
|
51 } \ |
|
52 while (0) |
|
53 |
|
54 using namespace mozilla; |
|
55 using namespace mozilla::ipc; |
|
56 |
|
57 using mozilla::dom::ContentChild; |
|
58 using mozilla::dom::ContentParent; |
|
59 |
|
60 namespace { |
|
61 |
|
62 // ----------------------------------------------------------------------------- |
|
63 // Utility Functions |
|
64 // ----------------------------------------------------------------------------- |
|
65 |
|
66 bool |
|
67 IsMainProcess() |
|
68 { |
|
69 static const bool isMainProcess = |
|
70 XRE_GetProcessType() == GeckoProcessType_Default; |
|
71 return isMainProcess; |
|
72 } |
|
73 |
|
74 bool |
|
75 IsChildProcess() |
|
76 { |
|
77 return !IsMainProcess(); |
|
78 } |
|
79 |
|
80 void |
|
81 AssertIsInMainProcess() |
|
82 { |
|
83 MOZ_ASSERT(IsMainProcess()); |
|
84 } |
|
85 |
|
86 void |
|
87 AssertIsInChildProcess() |
|
88 { |
|
89 MOZ_ASSERT(IsChildProcess()); |
|
90 } |
|
91 |
|
92 void |
|
93 AssertIsOnMainThread() |
|
94 { |
|
95 THREADSAFETY_ASSERT(NS_IsMainThread()); |
|
96 } |
|
97 |
|
98 // ----------------------------------------------------------------------------- |
|
99 // ParentImpl Declaration |
|
100 // ----------------------------------------------------------------------------- |
|
101 |
|
102 class ParentImpl MOZ_FINAL : public BackgroundParentImpl |
|
103 { |
|
104 friend class mozilla::ipc::BackgroundParent; |
|
105 |
|
106 public: |
|
107 class CreateCallback; |
|
108 |
|
109 private: |
|
110 class ShutdownObserver; |
|
111 class RequestMessageLoopRunnable; |
|
112 class ShutdownBackgroundThreadRunnable; |
|
113 class ForceCloseBackgroundActorsRunnable; |
|
114 class CreateCallbackRunnable; |
|
115 class ConnectActorRunnable; |
|
116 |
|
117 struct MOZ_STACK_CLASS TimerCallbackClosure |
|
118 { |
|
119 nsIThread* mThread; |
|
120 nsTArray<ParentImpl*>* mLiveActors; |
|
121 |
|
122 TimerCallbackClosure(nsIThread* aThread, nsTArray<ParentImpl*>* aLiveActors) |
|
123 : mThread(aThread), mLiveActors(aLiveActors) |
|
124 { |
|
125 AssertIsInMainProcess(); |
|
126 AssertIsOnMainThread(); |
|
127 MOZ_ASSERT(aThread); |
|
128 MOZ_ASSERT(aLiveActors); |
|
129 } |
|
130 }; |
|
131 |
|
132 // A handle that is invalid on any platform. |
|
133 static const ProcessHandle kInvalidProcessHandle; |
|
134 |
|
135 // The length of time we will wait at shutdown for all actors to clean |
|
136 // themselves up before forcing them to be destroyed. |
|
137 static const uint32_t kShutdownTimerDelayMS = 10000; |
|
138 |
|
139 // This is only modified on the main thread. It is null if the thread does not |
|
140 // exist or is shutting down. |
|
141 static StaticRefPtr<nsIThread> sBackgroundThread; |
|
142 |
|
143 // This is created and destroyed on the main thread but only modified on the |
|
144 // background thread. It is specific to each instance of sBackgroundThread. |
|
145 static nsTArray<ParentImpl*>* sLiveActorsForBackgroundThread; |
|
146 |
|
147 // This is only modified on the main thread. |
|
148 static StaticRefPtr<nsITimer> sShutdownTimer; |
|
149 |
|
150 // This exists so that that [Assert]IsOnBackgroundThread() can continue to |
|
151 // work during shutdown. |
|
152 static Atomic<PRThread*> sBackgroundPRThread; |
|
153 |
|
154 // This is only modified on the main thread. It is null if the thread does not |
|
155 // exist or is shutting down. |
|
156 static MessageLoop* sBackgroundThreadMessageLoop; |
|
157 |
|
158 // This is only modified on the main thread. It maintains a count of live |
|
159 // actors so that the background thread can be shut down when it is no longer |
|
160 // needed. |
|
161 static uint64_t sLiveActorCount; |
|
162 |
|
163 // This is only modified on the main thread. It is true after the shutdown |
|
164 // observer is registered and is never unset thereafter. |
|
165 static bool sShutdownObserverRegistered; |
|
166 |
|
167 // This is only modified on the main thread. It prevents us from trying to |
|
168 // create the background thread after application shutdown has started. |
|
169 static bool sShutdownHasStarted; |
|
170 |
|
171 // This is only modified on the main thread. It is a FIFO queue for callbacks |
|
172 // waiting for the background thread to be created. |
|
173 static StaticAutoPtr<nsTArray<nsRefPtr<CreateCallback>>> sPendingCallbacks; |
|
174 |
|
175 // Only touched on the main thread, null if this is a same-process actor. |
|
176 nsRefPtr<ContentParent> mContent; |
|
177 |
|
178 // mTransport is "owned" by this object but it must only be released on the |
|
179 // IPC thread. It's left as a raw pointer here to prevent accidentally |
|
180 // deleting it on the wrong thread. Only non-null for other-process actors. |
|
181 Transport* mTransport; |
|
182 |
|
183 // Set when the actor is opened successfully and used to handle shutdown |
|
184 // hangs. Only touched on the background thread. |
|
185 nsTArray<ParentImpl*>* mLiveActorArray; |
|
186 |
|
187 // Set at construction to indicate whether this parent actor corresponds to a |
|
188 // child actor in another process or to a child actor from a different thread |
|
189 // in the same process. |
|
190 const bool mIsOtherProcessActor; |
|
191 |
|
192 // Set after ActorDestroy has been called. Only touched on the background |
|
193 // thread. |
|
194 bool mActorDestroyed; |
|
195 |
|
196 public: |
|
197 static bool |
|
198 CreateActorForSameProcess(CreateCallback* aCallback); |
|
199 |
|
200 static bool |
|
201 IsOnBackgroundThread() |
|
202 { |
|
203 return PR_GetCurrentThread() == sBackgroundPRThread; |
|
204 } |
|
205 |
|
206 static void |
|
207 AssertIsOnBackgroundThread() |
|
208 { |
|
209 THREADSAFETY_ASSERT(IsOnBackgroundThread()); |
|
210 } |
|
211 |
|
212 NS_INLINE_DECL_REFCOUNTING(ParentImpl) |
|
213 |
|
214 void |
|
215 Destroy(); |
|
216 |
|
217 private: |
|
218 // Forwarded from BackgroundParent. |
|
219 static bool |
|
220 IsOtherProcessActor(PBackgroundParent* aBackgroundActor); |
|
221 |
|
222 // Forwarded from BackgroundParent. |
|
223 static already_AddRefed<ContentParent> |
|
224 GetContentParent(PBackgroundParent* aBackgroundActor); |
|
225 |
|
226 // Forwarded from BackgroundParent. |
|
227 static PBackgroundParent* |
|
228 Alloc(ContentParent* aContent, |
|
229 Transport* aTransport, |
|
230 ProcessId aOtherProcess); |
|
231 |
|
232 static bool |
|
233 CreateBackgroundThread(); |
|
234 |
|
235 static void |
|
236 ShutdownBackgroundThread(); |
|
237 |
|
238 static void |
|
239 ShutdownTimerCallback(nsITimer* aTimer, void* aClosure); |
|
240 |
|
241 // For same-process actors. |
|
242 ParentImpl() |
|
243 : mTransport(nullptr), mLiveActorArray(nullptr), mIsOtherProcessActor(false), |
|
244 mActorDestroyed(false) |
|
245 { |
|
246 AssertIsInMainProcess(); |
|
247 AssertIsOnMainThread(); |
|
248 |
|
249 SetOtherProcess(kInvalidProcessHandle); |
|
250 } |
|
251 |
|
252 // For other-process actors. |
|
253 ParentImpl(ContentParent* aContent, Transport* aTransport) |
|
254 : mContent(aContent), mTransport(aTransport), mLiveActorArray(nullptr), |
|
255 mIsOtherProcessActor(true), mActorDestroyed(false) |
|
256 { |
|
257 AssertIsInMainProcess(); |
|
258 AssertIsOnMainThread(); |
|
259 MOZ_ASSERT(aContent); |
|
260 MOZ_ASSERT(aTransport); |
|
261 } |
|
262 |
|
263 ~ParentImpl() |
|
264 { |
|
265 AssertIsInMainProcess(); |
|
266 AssertIsOnMainThread(); |
|
267 MOZ_ASSERT(!mContent); |
|
268 MOZ_ASSERT(!mTransport); |
|
269 } |
|
270 |
|
271 void |
|
272 MainThreadActorDestroy(); |
|
273 |
|
274 void |
|
275 SetLiveActorArray(nsTArray<ParentImpl*>* aLiveActorArray) |
|
276 { |
|
277 AssertIsInMainProcess(); |
|
278 AssertIsOnBackgroundThread(); |
|
279 MOZ_ASSERT(aLiveActorArray); |
|
280 MOZ_ASSERT(!aLiveActorArray->Contains(this)); |
|
281 MOZ_ASSERT(!mLiveActorArray); |
|
282 MOZ_ASSERT(mIsOtherProcessActor); |
|
283 |
|
284 mLiveActorArray = aLiveActorArray; |
|
285 mLiveActorArray->AppendElement(this); |
|
286 } |
|
287 |
|
288 // These methods are only called by IPDL. |
|
289 virtual IToplevelProtocol* |
|
290 CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds, |
|
291 ProcessHandle aPeerProcess, |
|
292 ProtocolCloneContext* aCtx) MOZ_OVERRIDE; |
|
293 |
|
294 virtual void |
|
295 ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE; |
|
296 }; |
|
297 |
|
298 // ----------------------------------------------------------------------------- |
|
299 // ChildImpl Declaration |
|
300 // ----------------------------------------------------------------------------- |
|
301 |
|
302 class ChildImpl MOZ_FINAL : public BackgroundChildImpl |
|
303 { |
|
304 friend class mozilla::ipc::BackgroundChild; |
|
305 friend class mozilla::ipc::BackgroundChildImpl; |
|
306 |
|
307 typedef base::ProcessId ProcessId; |
|
308 typedef mozilla::ipc::Transport Transport; |
|
309 |
|
310 class ShutdownObserver; |
|
311 class CreateActorRunnable; |
|
312 class ParentCreateCallback; |
|
313 class CreateCallbackRunnable; |
|
314 class OpenChildProcessActorRunnable; |
|
315 class OpenMainProcessActorRunnable; |
|
316 |
|
317 // A thread-local index that is not valid. |
|
318 static const unsigned int kBadThreadLocalIndex = |
|
319 static_cast<unsigned int>(-1); |
|
320 |
|
321 // This is only modified on the main thread. It is the thread-local index that |
|
322 // we use to store the BackgroundChild for each thread. |
|
323 static unsigned int sThreadLocalIndex; |
|
324 |
|
325 struct ThreadLocalInfo |
|
326 { |
|
327 ThreadLocalInfo(nsIIPCBackgroundChildCreateCallback* aCallback) |
|
328 { |
|
329 mCallbacks.AppendElement(aCallback); |
|
330 } |
|
331 |
|
332 nsRefPtr<ChildImpl> mActor; |
|
333 nsTArray<nsCOMPtr<nsIIPCBackgroundChildCreateCallback>> mCallbacks; |
|
334 nsAutoPtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal; |
|
335 }; |
|
336 |
|
337 // This is only modified on the main thread. It is a FIFO queue for actors |
|
338 // that are in the process of construction. |
|
339 static StaticAutoPtr<nsTArray<nsCOMPtr<nsIEventTarget>>> sPendingTargets; |
|
340 |
|
341 // This is only modified on the main thread. It prevents us from trying to |
|
342 // create the background thread after application shutdown has started. |
|
343 static bool sShutdownHasStarted; |
|
344 |
|
345 #ifdef RELEASE_BUILD |
|
346 DebugOnly<nsIThread*> mBoundThread; |
|
347 #else |
|
348 nsIThread* mBoundThread; |
|
349 #endif |
|
350 |
|
351 public: |
|
352 static bool |
|
353 OpenProtocolOnMainThread(nsIEventTarget* aEventTarget); |
|
354 |
|
355 static void |
|
356 Shutdown(); |
|
357 |
|
358 void |
|
359 AssertIsOnBoundThread() |
|
360 { |
|
361 THREADSAFETY_ASSERT(mBoundThread); |
|
362 |
|
363 #ifdef RELEASE_BUILD |
|
364 DebugOnly<bool> current; |
|
365 #else |
|
366 bool current; |
|
367 #endif |
|
368 THREADSAFETY_ASSERT( |
|
369 NS_SUCCEEDED(mBoundThread->IsOnCurrentThread(¤t))); |
|
370 THREADSAFETY_ASSERT(current); |
|
371 } |
|
372 |
|
373 ChildImpl() |
|
374 : mBoundThread(nullptr) |
|
375 { |
|
376 AssertIsOnMainThread(); |
|
377 } |
|
378 |
|
379 NS_INLINE_DECL_REFCOUNTING(ChildImpl) |
|
380 |
|
381 private: |
|
382 // Forwarded from BackgroundChild. |
|
383 static void |
|
384 Startup(); |
|
385 |
|
386 // Forwarded from BackgroundChild. |
|
387 static PBackgroundChild* |
|
388 Alloc(Transport* aTransport, ProcessId aOtherProcess); |
|
389 |
|
390 // Forwarded from BackgroundChild. |
|
391 static PBackgroundChild* |
|
392 GetForCurrentThread(); |
|
393 |
|
394 // Forwarded from BackgroundChild. |
|
395 static bool |
|
396 GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback); |
|
397 |
|
398 // Forwarded from BackgroundChildImpl. |
|
399 static BackgroundChildImpl::ThreadLocal* |
|
400 GetThreadLocalForCurrentThread(); |
|
401 |
|
402 static void |
|
403 ThreadLocalDestructor(void* aThreadLocal) |
|
404 { |
|
405 auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal); |
|
406 |
|
407 if (threadLocalInfo) { |
|
408 if (threadLocalInfo->mActor) { |
|
409 threadLocalInfo->mActor->Close(); |
|
410 } |
|
411 delete threadLocalInfo; |
|
412 } |
|
413 } |
|
414 |
|
415 static void |
|
416 DispatchFailureCallback(nsIEventTarget* aEventTarget); |
|
417 |
|
418 // This class is reference counted. |
|
419 ~ChildImpl() |
|
420 { } |
|
421 |
|
422 void |
|
423 SetBoundThread() |
|
424 { |
|
425 THREADSAFETY_ASSERT(!mBoundThread); |
|
426 |
|
427 #if defined(DEBUG) || !defined(RELEASE_BUILD) |
|
428 mBoundThread = NS_GetCurrentThread(); |
|
429 #endif |
|
430 |
|
431 THREADSAFETY_ASSERT(mBoundThread); |
|
432 } |
|
433 |
|
434 // Only called by IPDL. |
|
435 virtual void |
|
436 ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE; |
|
437 }; |
|
438 |
|
439 // ----------------------------------------------------------------------------- |
|
440 // ParentImpl Helper Declarations |
|
441 // ----------------------------------------------------------------------------- |
|
442 |
|
443 class ParentImpl::ShutdownObserver MOZ_FINAL : public nsIObserver |
|
444 { |
|
445 public: |
|
446 ShutdownObserver() |
|
447 { |
|
448 AssertIsOnMainThread(); |
|
449 } |
|
450 |
|
451 NS_DECL_ISUPPORTS |
|
452 NS_DECL_NSIOBSERVER |
|
453 |
|
454 private: |
|
455 ~ShutdownObserver() |
|
456 { |
|
457 AssertIsOnMainThread(); |
|
458 } |
|
459 }; |
|
460 |
|
461 class ParentImpl::RequestMessageLoopRunnable MOZ_FINAL : |
|
462 public nsRunnable |
|
463 { |
|
464 nsCOMPtr<nsIThread> mTargetThread; |
|
465 MessageLoop* mMessageLoop; |
|
466 |
|
467 public: |
|
468 RequestMessageLoopRunnable(nsIThread* aTargetThread) |
|
469 : mTargetThread(aTargetThread), mMessageLoop(nullptr) |
|
470 { |
|
471 AssertIsInMainProcess(); |
|
472 AssertIsOnMainThread(); |
|
473 MOZ_ASSERT(aTargetThread); |
|
474 } |
|
475 |
|
476 NS_DECL_ISUPPORTS_INHERITED |
|
477 |
|
478 private: |
|
479 ~RequestMessageLoopRunnable() |
|
480 { } |
|
481 |
|
482 NS_DECL_NSIRUNNABLE |
|
483 }; |
|
484 |
|
485 class ParentImpl::ShutdownBackgroundThreadRunnable MOZ_FINAL : public nsRunnable |
|
486 { |
|
487 public: |
|
488 ShutdownBackgroundThreadRunnable() |
|
489 { |
|
490 AssertIsInMainProcess(); |
|
491 AssertIsOnMainThread(); |
|
492 } |
|
493 |
|
494 NS_DECL_ISUPPORTS_INHERITED |
|
495 |
|
496 private: |
|
497 ~ShutdownBackgroundThreadRunnable() |
|
498 { } |
|
499 |
|
500 NS_DECL_NSIRUNNABLE |
|
501 }; |
|
502 |
|
503 class ParentImpl::ForceCloseBackgroundActorsRunnable MOZ_FINAL : public nsRunnable |
|
504 { |
|
505 nsTArray<ParentImpl*>* mActorArray; |
|
506 |
|
507 public: |
|
508 ForceCloseBackgroundActorsRunnable(nsTArray<ParentImpl*>* aActorArray) |
|
509 : mActorArray(aActorArray) |
|
510 { |
|
511 AssertIsInMainProcess(); |
|
512 AssertIsOnMainThread(); |
|
513 MOZ_ASSERT(aActorArray); |
|
514 } |
|
515 |
|
516 NS_DECL_ISUPPORTS_INHERITED |
|
517 |
|
518 private: |
|
519 ~ForceCloseBackgroundActorsRunnable() |
|
520 { } |
|
521 |
|
522 NS_DECL_NSIRUNNABLE |
|
523 }; |
|
524 |
|
525 class ParentImpl::CreateCallbackRunnable MOZ_FINAL : public nsRunnable |
|
526 { |
|
527 nsRefPtr<CreateCallback> mCallback; |
|
528 |
|
529 public: |
|
530 CreateCallbackRunnable(CreateCallback* aCallback) |
|
531 : mCallback(aCallback) |
|
532 { |
|
533 AssertIsInMainProcess(); |
|
534 AssertIsOnMainThread(); |
|
535 MOZ_ASSERT(aCallback); |
|
536 } |
|
537 |
|
538 NS_DECL_ISUPPORTS_INHERITED |
|
539 |
|
540 private: |
|
541 ~CreateCallbackRunnable() |
|
542 { } |
|
543 |
|
544 NS_DECL_NSIRUNNABLE |
|
545 }; |
|
546 |
|
547 class ParentImpl::ConnectActorRunnable MOZ_FINAL : public nsRunnable |
|
548 { |
|
549 nsRefPtr<ParentImpl> mActor; |
|
550 Transport* mTransport; |
|
551 ProcessHandle mProcessHandle; |
|
552 nsTArray<ParentImpl*>* mLiveActorArray; |
|
553 |
|
554 public: |
|
555 ConnectActorRunnable(ParentImpl* aActor, |
|
556 Transport* aTransport, |
|
557 ProcessHandle aProcessHandle, |
|
558 nsTArray<ParentImpl*>* aLiveActorArray) |
|
559 : mActor(aActor), mTransport(aTransport), mProcessHandle(aProcessHandle), |
|
560 mLiveActorArray(aLiveActorArray) |
|
561 { |
|
562 AssertIsInMainProcess(); |
|
563 AssertIsOnMainThread(); |
|
564 MOZ_ASSERT(aActor); |
|
565 MOZ_ASSERT(aTransport); |
|
566 MOZ_ASSERT(aLiveActorArray); |
|
567 } |
|
568 |
|
569 NS_DECL_ISUPPORTS_INHERITED |
|
570 |
|
571 private: |
|
572 ~ConnectActorRunnable() |
|
573 { |
|
574 AssertIsInMainProcess(); |
|
575 } |
|
576 |
|
577 NS_DECL_NSIRUNNABLE |
|
578 }; |
|
579 |
|
580 class NS_NO_VTABLE ParentImpl::CreateCallback |
|
581 { |
|
582 public: |
|
583 NS_INLINE_DECL_REFCOUNTING(CreateCallback) |
|
584 |
|
585 virtual void |
|
586 Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop) = 0; |
|
587 |
|
588 virtual void |
|
589 Failure() = 0; |
|
590 |
|
591 protected: |
|
592 virtual ~CreateCallback() |
|
593 { } |
|
594 }; |
|
595 |
|
596 // ----------------------------------------------------------------------------- |
|
597 // ChildImpl Helper Declarations |
|
598 // ----------------------------------------------------------------------------- |
|
599 |
|
600 class ChildImpl::ShutdownObserver MOZ_FINAL : public nsIObserver |
|
601 { |
|
602 public: |
|
603 ShutdownObserver() |
|
604 { |
|
605 AssertIsOnMainThread(); |
|
606 } |
|
607 |
|
608 NS_DECL_ISUPPORTS |
|
609 NS_DECL_NSIOBSERVER |
|
610 |
|
611 private: |
|
612 ~ShutdownObserver() |
|
613 { |
|
614 AssertIsOnMainThread(); |
|
615 } |
|
616 }; |
|
617 |
|
618 class ChildImpl::CreateActorRunnable MOZ_FINAL : public nsRunnable |
|
619 { |
|
620 nsCOMPtr<nsIEventTarget> mEventTarget; |
|
621 |
|
622 public: |
|
623 CreateActorRunnable() |
|
624 : mEventTarget(NS_GetCurrentThread()) |
|
625 { |
|
626 MOZ_ASSERT(mEventTarget); |
|
627 } |
|
628 |
|
629 NS_DECL_ISUPPORTS_INHERITED |
|
630 |
|
631 private: |
|
632 ~CreateActorRunnable() |
|
633 { } |
|
634 |
|
635 NS_DECL_NSIRUNNABLE |
|
636 }; |
|
637 |
|
638 class ChildImpl::ParentCreateCallback MOZ_FINAL : |
|
639 public ParentImpl::CreateCallback |
|
640 { |
|
641 nsCOMPtr<nsIEventTarget> mEventTarget; |
|
642 |
|
643 public: |
|
644 ParentCreateCallback(nsIEventTarget* aEventTarget) |
|
645 : mEventTarget(aEventTarget) |
|
646 { |
|
647 AssertIsInMainProcess(); |
|
648 AssertIsOnMainThread(); |
|
649 MOZ_ASSERT(aEventTarget); |
|
650 } |
|
651 |
|
652 private: |
|
653 ~ParentCreateCallback() |
|
654 { } |
|
655 |
|
656 virtual void |
|
657 Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop) |
|
658 MOZ_OVERRIDE; |
|
659 |
|
660 virtual void |
|
661 Failure() MOZ_OVERRIDE; |
|
662 }; |
|
663 |
|
664 class ChildImpl::CreateCallbackRunnable : public nsRunnable |
|
665 { |
|
666 protected: |
|
667 nsRefPtr<ChildImpl> mActor; |
|
668 |
|
669 public: |
|
670 CreateCallbackRunnable(already_AddRefed<ChildImpl>&& aActor) |
|
671 : mActor(aActor) |
|
672 { |
|
673 // May be created on any thread! |
|
674 |
|
675 MOZ_ASSERT(mActor); |
|
676 } |
|
677 |
|
678 CreateCallbackRunnable() |
|
679 { |
|
680 // May be created on any thread! |
|
681 } |
|
682 |
|
683 NS_DECL_ISUPPORTS_INHERITED |
|
684 |
|
685 protected: |
|
686 virtual ~CreateCallbackRunnable(); |
|
687 |
|
688 static already_AddRefed<nsIIPCBackgroundChildCreateCallback> |
|
689 GetNextCallback(); |
|
690 |
|
691 NS_DECL_NSIRUNNABLE |
|
692 }; |
|
693 |
|
694 class ChildImpl::OpenChildProcessActorRunnable MOZ_FINAL : |
|
695 public ChildImpl::CreateCallbackRunnable |
|
696 { |
|
697 nsAutoPtr<Transport> mTransport; |
|
698 ProcessHandle mProcessHandle; |
|
699 |
|
700 public: |
|
701 OpenChildProcessActorRunnable(already_AddRefed<ChildImpl>&& aActor, |
|
702 Transport* aTransport, |
|
703 ProcessHandle aProcessHandle) |
|
704 : CreateCallbackRunnable(Move(aActor)), mTransport(aTransport), |
|
705 mProcessHandle(aProcessHandle) |
|
706 { |
|
707 AssertIsOnMainThread(); |
|
708 MOZ_ASSERT(aTransport); |
|
709 } |
|
710 |
|
711 NS_DECL_ISUPPORTS_INHERITED |
|
712 |
|
713 private: |
|
714 ~OpenChildProcessActorRunnable() |
|
715 { |
|
716 if (mTransport) { |
|
717 CRASH_IN_CHILD_PROCESS("Leaking transport!"); |
|
718 unused << mTransport.forget(); |
|
719 } |
|
720 } |
|
721 |
|
722 NS_DECL_NSIRUNNABLE |
|
723 }; |
|
724 |
|
725 class ChildImpl::OpenMainProcessActorRunnable MOZ_FINAL : |
|
726 public ChildImpl::CreateCallbackRunnable |
|
727 { |
|
728 nsRefPtr<ParentImpl> mParentActor; |
|
729 MessageLoop* mParentMessageLoop; |
|
730 |
|
731 public: |
|
732 OpenMainProcessActorRunnable(already_AddRefed<ChildImpl>&& aChildActor, |
|
733 already_AddRefed<ParentImpl> aParentActor, |
|
734 MessageLoop* aParentMessageLoop) |
|
735 : CreateCallbackRunnable(Move(aChildActor)), mParentActor(aParentActor), |
|
736 mParentMessageLoop(aParentMessageLoop) |
|
737 { |
|
738 AssertIsOnMainThread(); |
|
739 MOZ_ASSERT(mParentActor); |
|
740 MOZ_ASSERT(aParentMessageLoop); |
|
741 } |
|
742 |
|
743 NS_DECL_ISUPPORTS_INHERITED |
|
744 |
|
745 private: |
|
746 ~OpenMainProcessActorRunnable() |
|
747 { } |
|
748 |
|
749 NS_DECL_NSIRUNNABLE |
|
750 }; |
|
751 |
|
752 } // anonymous namespace |
|
753 |
|
754 namespace mozilla { |
|
755 namespace ipc { |
|
756 |
|
757 bool |
|
758 IsOnBackgroundThread() |
|
759 { |
|
760 return ParentImpl::IsOnBackgroundThread(); |
|
761 } |
|
762 |
|
763 #ifdef DEBUG |
|
764 |
|
765 void |
|
766 AssertIsOnBackgroundThread() |
|
767 { |
|
768 ParentImpl::AssertIsOnBackgroundThread(); |
|
769 } |
|
770 |
|
771 #endif // DEBUG |
|
772 |
|
773 } // namespace ipc |
|
774 } // namespace mozilla |
|
775 |
|
776 // ----------------------------------------------------------------------------- |
|
777 // BackgroundParent Public Methods |
|
778 // ----------------------------------------------------------------------------- |
|
779 |
|
780 // static |
|
781 bool |
|
782 BackgroundParent::IsOtherProcessActor(PBackgroundParent* aBackgroundActor) |
|
783 { |
|
784 return ParentImpl::IsOtherProcessActor(aBackgroundActor); |
|
785 } |
|
786 |
|
787 // static |
|
788 already_AddRefed<ContentParent> |
|
789 BackgroundParent::GetContentParent(PBackgroundParent* aBackgroundActor) |
|
790 { |
|
791 return ParentImpl::GetContentParent(aBackgroundActor); |
|
792 } |
|
793 |
|
794 // static |
|
795 PBackgroundParent* |
|
796 BackgroundParent::Alloc(ContentParent* aContent, |
|
797 Transport* aTransport, |
|
798 ProcessId aOtherProcess) |
|
799 { |
|
800 return ParentImpl::Alloc(aContent, aTransport, aOtherProcess); |
|
801 } |
|
802 |
|
803 // ----------------------------------------------------------------------------- |
|
804 // BackgroundChild Public Methods |
|
805 // ----------------------------------------------------------------------------- |
|
806 |
|
807 // static |
|
808 void |
|
809 BackgroundChild::Startup() |
|
810 { |
|
811 ChildImpl::Startup(); |
|
812 } |
|
813 |
|
814 // static |
|
815 PBackgroundChild* |
|
816 BackgroundChild::Alloc(Transport* aTransport, ProcessId aOtherProcess) |
|
817 { |
|
818 return ChildImpl::Alloc(aTransport, aOtherProcess); |
|
819 } |
|
820 |
|
821 // static |
|
822 PBackgroundChild* |
|
823 BackgroundChild::GetForCurrentThread() |
|
824 { |
|
825 return ChildImpl::GetForCurrentThread(); |
|
826 } |
|
827 |
|
828 // static |
|
829 bool |
|
830 BackgroundChild::GetOrCreateForCurrentThread( |
|
831 nsIIPCBackgroundChildCreateCallback* aCallback) |
|
832 { |
|
833 return ChildImpl::GetOrCreateForCurrentThread(aCallback); |
|
834 } |
|
835 |
|
836 // ----------------------------------------------------------------------------- |
|
837 // BackgroundChildImpl Public Methods |
|
838 // ----------------------------------------------------------------------------- |
|
839 |
|
840 // static |
|
841 BackgroundChildImpl::ThreadLocal* |
|
842 BackgroundChildImpl::GetThreadLocalForCurrentThread() |
|
843 { |
|
844 return ChildImpl::GetThreadLocalForCurrentThread(); |
|
845 } |
|
846 |
|
847 // ----------------------------------------------------------------------------- |
|
848 // ParentImpl Static Members |
|
849 // ----------------------------------------------------------------------------- |
|
850 |
|
851 const ParentImpl::ProcessHandle ParentImpl::kInvalidProcessHandle = |
|
852 #ifdef XP_WIN |
|
853 ProcessHandle(INVALID_HANDLE_VALUE); |
|
854 #else |
|
855 ProcessHandle(-1); |
|
856 #endif |
|
857 |
|
858 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread; |
|
859 |
|
860 nsTArray<ParentImpl*>* ParentImpl::sLiveActorsForBackgroundThread; |
|
861 |
|
862 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer; |
|
863 |
|
864 Atomic<PRThread*> ParentImpl::sBackgroundPRThread; |
|
865 |
|
866 MessageLoop* ParentImpl::sBackgroundThreadMessageLoop = nullptr; |
|
867 |
|
868 uint64_t ParentImpl::sLiveActorCount = 0; |
|
869 |
|
870 bool ParentImpl::sShutdownObserverRegistered = false; |
|
871 |
|
872 bool ParentImpl::sShutdownHasStarted = false; |
|
873 |
|
874 StaticAutoPtr<nsTArray<nsRefPtr<ParentImpl::CreateCallback>>> |
|
875 ParentImpl::sPendingCallbacks; |
|
876 |
|
877 // ----------------------------------------------------------------------------- |
|
878 // ChildImpl Static Members |
|
879 // ----------------------------------------------------------------------------- |
|
880 |
|
881 unsigned int ChildImpl::sThreadLocalIndex = kBadThreadLocalIndex; |
|
882 |
|
883 StaticAutoPtr<nsTArray<nsCOMPtr<nsIEventTarget>>> ChildImpl::sPendingTargets; |
|
884 |
|
885 bool ChildImpl::sShutdownHasStarted = false; |
|
886 |
|
887 // ----------------------------------------------------------------------------- |
|
888 // ParentImpl Implementation |
|
889 // ----------------------------------------------------------------------------- |
|
890 |
|
891 // static |
|
892 bool |
|
893 ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor) |
|
894 { |
|
895 AssertIsOnBackgroundThread(); |
|
896 MOZ_ASSERT(aBackgroundActor); |
|
897 |
|
898 return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor; |
|
899 } |
|
900 |
|
901 // static |
|
902 already_AddRefed<ContentParent> |
|
903 ParentImpl::GetContentParent(PBackgroundParent* aBackgroundActor) |
|
904 { |
|
905 AssertIsOnBackgroundThread(); |
|
906 MOZ_ASSERT(aBackgroundActor); |
|
907 |
|
908 auto actor = static_cast<ParentImpl*>(aBackgroundActor); |
|
909 if (actor->mActorDestroyed) { |
|
910 MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!"); |
|
911 return nullptr; |
|
912 } |
|
913 |
|
914 if (actor->mContent) { |
|
915 // We need to hand out a reference to our ContentParent but we also need to |
|
916 // keep the one we have. We can't call AddRef here because ContentParent is |
|
917 // not threadsafe so instead we dispatch a runnable to the main thread to do |
|
918 // it for us. This is safe since we are guaranteed that our AddRef runnable |
|
919 // will run before the reference we hand out can be released, and the |
|
920 // ContentParent can't die as long as the existing reference is maintained. |
|
921 nsCOMPtr<nsIRunnable> runnable = |
|
922 NS_NewNonOwningRunnableMethod(actor->mContent, &ContentParent::AddRef); |
|
923 MOZ_ASSERT(runnable); |
|
924 |
|
925 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); |
|
926 } |
|
927 |
|
928 return actor->mContent.get(); |
|
929 } |
|
930 |
|
931 // static |
|
932 PBackgroundParent* |
|
933 ParentImpl::Alloc(ContentParent* aContent, |
|
934 Transport* aTransport, |
|
935 ProcessId aOtherProcess) |
|
936 { |
|
937 AssertIsInMainProcess(); |
|
938 AssertIsOnMainThread(); |
|
939 MOZ_ASSERT(aTransport); |
|
940 |
|
941 ProcessHandle processHandle; |
|
942 if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) { |
|
943 // Process has already died? |
|
944 return nullptr; |
|
945 } |
|
946 |
|
947 if (!sBackgroundThread && !CreateBackgroundThread()) { |
|
948 NS_WARNING("Failed to create background thread!"); |
|
949 return nullptr; |
|
950 } |
|
951 |
|
952 MOZ_ASSERT(sLiveActorsForBackgroundThread); |
|
953 |
|
954 sLiveActorCount++; |
|
955 |
|
956 nsRefPtr<ParentImpl> actor = new ParentImpl(aContent, aTransport); |
|
957 |
|
958 nsCOMPtr<nsIRunnable> connectRunnable = |
|
959 new ConnectActorRunnable(actor, aTransport, processHandle, |
|
960 sLiveActorsForBackgroundThread); |
|
961 |
|
962 if (NS_FAILED(sBackgroundThread->Dispatch(connectRunnable, |
|
963 NS_DISPATCH_NORMAL))) { |
|
964 NS_WARNING("Failed to dispatch connect runnable!"); |
|
965 |
|
966 MOZ_ASSERT(sLiveActorCount); |
|
967 sLiveActorCount--; |
|
968 |
|
969 if (!sLiveActorCount) { |
|
970 ShutdownBackgroundThread(); |
|
971 } |
|
972 |
|
973 return nullptr; |
|
974 } |
|
975 |
|
976 return actor; |
|
977 } |
|
978 |
|
979 // static |
|
980 bool |
|
981 ParentImpl::CreateActorForSameProcess(CreateCallback* aCallback) |
|
982 { |
|
983 AssertIsInMainProcess(); |
|
984 AssertIsOnMainThread(); |
|
985 MOZ_ASSERT(aCallback); |
|
986 |
|
987 if (!sBackgroundThread && !CreateBackgroundThread()) { |
|
988 NS_WARNING("Failed to create background thread!"); |
|
989 return false; |
|
990 } |
|
991 |
|
992 MOZ_ASSERT(!sShutdownHasStarted); |
|
993 |
|
994 sLiveActorCount++; |
|
995 |
|
996 if (sBackgroundThreadMessageLoop) { |
|
997 nsCOMPtr<nsIRunnable> callbackRunnable = |
|
998 new CreateCallbackRunnable(aCallback); |
|
999 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(callbackRunnable))); |
|
1000 return true; |
|
1001 } |
|
1002 |
|
1003 if (!sPendingCallbacks) { |
|
1004 sPendingCallbacks = new nsTArray<nsRefPtr<CreateCallback>>(); |
|
1005 } |
|
1006 |
|
1007 sPendingCallbacks->AppendElement(aCallback); |
|
1008 return true; |
|
1009 } |
|
1010 |
|
1011 // static |
|
1012 bool |
|
1013 ParentImpl::CreateBackgroundThread() |
|
1014 { |
|
1015 AssertIsInMainProcess(); |
|
1016 AssertIsOnMainThread(); |
|
1017 MOZ_ASSERT(!sBackgroundThread); |
|
1018 MOZ_ASSERT(!sLiveActorsForBackgroundThread); |
|
1019 |
|
1020 if (sShutdownHasStarted) { |
|
1021 NS_WARNING("Trying to create background thread after shutdown has " |
|
1022 "already begun!"); |
|
1023 return false; |
|
1024 } |
|
1025 |
|
1026 nsCOMPtr<nsITimer> newShutdownTimer; |
|
1027 |
|
1028 if (!sShutdownTimer) { |
|
1029 nsresult rv; |
|
1030 newShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); |
|
1031 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
1032 return false; |
|
1033 } |
|
1034 } |
|
1035 |
|
1036 if (!sShutdownObserverRegistered) { |
|
1037 nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
|
1038 if (NS_WARN_IF(!obs)) { |
|
1039 return false; |
|
1040 } |
|
1041 |
|
1042 nsCOMPtr<nsIObserver> observer = new ShutdownObserver(); |
|
1043 |
|
1044 nsresult rv = |
|
1045 obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false); |
|
1046 if (NS_WARN_IF(NS_FAILED(rv))) { |
|
1047 return false; |
|
1048 } |
|
1049 |
|
1050 sShutdownObserverRegistered = true; |
|
1051 } |
|
1052 |
|
1053 nsCOMPtr<nsIThread> thread; |
|
1054 if (NS_FAILED(NS_NewNamedThread("IPDL Background", getter_AddRefs(thread)))) { |
|
1055 NS_WARNING("NS_NewNamedThread failed!"); |
|
1056 return false; |
|
1057 } |
|
1058 |
|
1059 nsCOMPtr<nsIRunnable> messageLoopRunnable = |
|
1060 new RequestMessageLoopRunnable(thread); |
|
1061 if (NS_FAILED(thread->Dispatch(messageLoopRunnable, NS_DISPATCH_NORMAL))) { |
|
1062 NS_WARNING("Failed to dispatch RequestMessageLoopRunnable!"); |
|
1063 return false; |
|
1064 } |
|
1065 |
|
1066 sBackgroundThread = thread; |
|
1067 sLiveActorsForBackgroundThread = new nsTArray<ParentImpl*>(1); |
|
1068 |
|
1069 if (!sShutdownTimer) { |
|
1070 MOZ_ASSERT(newShutdownTimer); |
|
1071 sShutdownTimer = newShutdownTimer; |
|
1072 } |
|
1073 |
|
1074 return true; |
|
1075 } |
|
1076 |
|
1077 // static |
|
1078 void |
|
1079 ParentImpl::ShutdownBackgroundThread() |
|
1080 { |
|
1081 AssertIsInMainProcess(); |
|
1082 AssertIsOnMainThread(); |
|
1083 MOZ_ASSERT_IF(!sBackgroundThread, !sBackgroundThreadMessageLoop); |
|
1084 MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount); |
|
1085 MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount); |
|
1086 MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer); |
|
1087 |
|
1088 if (sPendingCallbacks) { |
|
1089 if (!sPendingCallbacks->IsEmpty()) { |
|
1090 nsTArray<nsRefPtr<CreateCallback>> callbacks; |
|
1091 sPendingCallbacks->SwapElements(callbacks); |
|
1092 |
|
1093 for (uint32_t index = 0; index < callbacks.Length(); index++) { |
|
1094 nsRefPtr<CreateCallback> callback; |
|
1095 callbacks[index].swap(callback); |
|
1096 MOZ_ASSERT(callback); |
|
1097 |
|
1098 callback->Failure(); |
|
1099 } |
|
1100 } |
|
1101 |
|
1102 if (sShutdownHasStarted) { |
|
1103 sPendingCallbacks = nullptr; |
|
1104 } |
|
1105 } |
|
1106 |
|
1107 nsCOMPtr<nsITimer> shutdownTimer; |
|
1108 if (sShutdownHasStarted) { |
|
1109 shutdownTimer = sShutdownTimer.get(); |
|
1110 sShutdownTimer = nullptr; |
|
1111 } |
|
1112 |
|
1113 if (sBackgroundThread) { |
|
1114 nsCOMPtr<nsIThread> thread = sBackgroundThread.get(); |
|
1115 nsAutoPtr<nsTArray<ParentImpl*>> liveActors(sLiveActorsForBackgroundThread); |
|
1116 |
|
1117 sBackgroundThread = nullptr; |
|
1118 sLiveActorsForBackgroundThread = nullptr; |
|
1119 sBackgroundThreadMessageLoop = nullptr; |
|
1120 |
|
1121 MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount); |
|
1122 |
|
1123 if (sShutdownHasStarted) { |
|
1124 // If this is final shutdown then we need to spin the event loop while we |
|
1125 // wait for all the actors to be cleaned up. We also set a timeout to |
|
1126 // force-kill any hanging actors. |
|
1127 |
|
1128 if (sLiveActorCount) { |
|
1129 TimerCallbackClosure closure(thread, liveActors); |
|
1130 |
|
1131 MOZ_ALWAYS_TRUE(NS_SUCCEEDED( |
|
1132 shutdownTimer->InitWithFuncCallback(&ShutdownTimerCallback, &closure, |
|
1133 kShutdownTimerDelayMS, |
|
1134 nsITimer::TYPE_ONE_SHOT))); |
|
1135 |
|
1136 nsIThread* currentThread = NS_GetCurrentThread(); |
|
1137 MOZ_ASSERT(currentThread); |
|
1138 |
|
1139 while (sLiveActorCount) { |
|
1140 NS_ProcessNextEvent(currentThread); |
|
1141 } |
|
1142 |
|
1143 MOZ_ASSERT(liveActors->IsEmpty()); |
|
1144 |
|
1145 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(shutdownTimer->Cancel())); |
|
1146 } |
|
1147 } |
|
1148 |
|
1149 // Dispatch this runnable to unregister the thread from the profiler. |
|
1150 nsCOMPtr<nsIRunnable> shutdownRunnable = |
|
1151 new ShutdownBackgroundThreadRunnable(); |
|
1152 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->Dispatch(shutdownRunnable, |
|
1153 NS_DISPATCH_NORMAL))); |
|
1154 |
|
1155 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(thread->Shutdown())); |
|
1156 } |
|
1157 } |
|
1158 |
|
1159 // static |
|
1160 void |
|
1161 ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure) |
|
1162 { |
|
1163 AssertIsInMainProcess(); |
|
1164 AssertIsOnMainThread(); |
|
1165 MOZ_ASSERT(sShutdownHasStarted); |
|
1166 MOZ_ASSERT(sLiveActorCount); |
|
1167 |
|
1168 auto closure = static_cast<TimerCallbackClosure*>(aClosure); |
|
1169 MOZ_ASSERT(closure); |
|
1170 |
|
1171 // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has |
|
1172 // finished. |
|
1173 sLiveActorCount++; |
|
1174 |
|
1175 nsCOMPtr<nsIRunnable> forceCloseRunnable = |
|
1176 new ForceCloseBackgroundActorsRunnable(closure->mLiveActors); |
|
1177 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(closure->mThread->Dispatch(forceCloseRunnable, |
|
1178 NS_DISPATCH_NORMAL))); |
|
1179 } |
|
1180 |
|
1181 void |
|
1182 ParentImpl::Destroy() |
|
1183 { |
|
1184 // May be called on any thread! |
|
1185 |
|
1186 AssertIsInMainProcess(); |
|
1187 |
|
1188 nsCOMPtr<nsIRunnable> destroyRunnable = |
|
1189 NS_NewNonOwningRunnableMethod(this, &ParentImpl::MainThreadActorDestroy); |
|
1190 MOZ_ASSERT(destroyRunnable); |
|
1191 |
|
1192 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(destroyRunnable))); |
|
1193 } |
|
1194 |
|
1195 void |
|
1196 ParentImpl::MainThreadActorDestroy() |
|
1197 { |
|
1198 AssertIsInMainProcess(); |
|
1199 AssertIsOnMainThread(); |
|
1200 MOZ_ASSERT_IF(mIsOtherProcessActor, mContent); |
|
1201 MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent); |
|
1202 MOZ_ASSERT_IF(mIsOtherProcessActor, mTransport); |
|
1203 MOZ_ASSERT_IF(!mIsOtherProcessActor, !mTransport); |
|
1204 |
|
1205 if (mTransport) { |
|
1206 XRE_GetIOMessageLoop()->PostTask(FROM_HERE, |
|
1207 new DeleteTask<Transport>(mTransport)); |
|
1208 mTransport = nullptr; |
|
1209 } |
|
1210 |
|
1211 ProcessHandle otherProcess = OtherProcess(); |
|
1212 if (otherProcess != kInvalidProcessHandle) { |
|
1213 base::CloseProcessHandle(otherProcess); |
|
1214 #ifdef DEBUG |
|
1215 SetOtherProcess(kInvalidProcessHandle); |
|
1216 #endif |
|
1217 } |
|
1218 |
|
1219 mContent = nullptr; |
|
1220 |
|
1221 MOZ_ASSERT(sLiveActorCount); |
|
1222 sLiveActorCount--; |
|
1223 |
|
1224 if (!sLiveActorCount) { |
|
1225 ShutdownBackgroundThread(); |
|
1226 } |
|
1227 |
|
1228 // This may be the last reference! |
|
1229 Release(); |
|
1230 } |
|
1231 |
|
1232 IToplevelProtocol* |
|
1233 ParentImpl::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds, |
|
1234 ProcessHandle aPeerProcess, |
|
1235 ProtocolCloneContext* aCtx) |
|
1236 { |
|
1237 AssertIsInMainProcess(); |
|
1238 AssertIsOnMainThread(); |
|
1239 |
|
1240 const ProtocolId protocolId = GetProtocolId(); |
|
1241 |
|
1242 for (unsigned int i = 0; i < aFds.Length(); i++) { |
|
1243 if (static_cast<ProtocolId>(aFds[i].protocolId()) != protocolId) { |
|
1244 continue; |
|
1245 } |
|
1246 |
|
1247 Transport* transport = OpenDescriptor(aFds[i].fd(), |
|
1248 Transport::MODE_SERVER); |
|
1249 if (!transport) { |
|
1250 NS_WARNING("Failed to open transport!"); |
|
1251 break; |
|
1252 } |
|
1253 |
|
1254 PBackgroundParent* clonedActor = |
|
1255 Alloc(mContent, transport, base::GetProcId(aPeerProcess)); |
|
1256 MOZ_ASSERT(clonedActor); |
|
1257 |
|
1258 clonedActor->CloneManagees(this, aCtx); |
|
1259 clonedActor->SetTransport(transport); |
|
1260 |
|
1261 return clonedActor; |
|
1262 } |
|
1263 |
|
1264 return nullptr; |
|
1265 } |
|
1266 |
|
1267 void |
|
1268 ParentImpl::ActorDestroy(ActorDestroyReason aWhy) |
|
1269 { |
|
1270 AssertIsInMainProcess(); |
|
1271 AssertIsOnBackgroundThread(); |
|
1272 MOZ_ASSERT(!mActorDestroyed); |
|
1273 MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray); |
|
1274 |
|
1275 BackgroundParentImpl::ActorDestroy(aWhy); |
|
1276 |
|
1277 mActorDestroyed = true; |
|
1278 |
|
1279 if (mLiveActorArray) { |
|
1280 MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this)); |
|
1281 mLiveActorArray = nullptr; |
|
1282 } |
|
1283 |
|
1284 // This is tricky. We should be able to call Destroy() here directly because |
|
1285 // we're not going to touch 'this' or our MessageChannel any longer on this |
|
1286 // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when |
|
1287 // it runs it will destroy 'this' and our associated MessageChannel. However, |
|
1288 // IPDL is about to call MessageChannel::Clear() on this thread! To avoid |
|
1289 // racing with the main thread we must ensure that the MessageChannel lives |
|
1290 // long enough to be cleared in this call stack. |
|
1291 nsCOMPtr<nsIRunnable> destroyRunnable = |
|
1292 NS_NewNonOwningRunnableMethod(this, &ParentImpl::Destroy); |
|
1293 MOZ_ASSERT(destroyRunnable); |
|
1294 |
|
1295 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(destroyRunnable))); |
|
1296 } |
|
1297 |
|
1298 NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver) |
|
1299 |
|
1300 NS_IMETHODIMP |
|
1301 ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject, |
|
1302 const char* aTopic, |
|
1303 const char16_t* aData) |
|
1304 { |
|
1305 AssertIsInMainProcess(); |
|
1306 AssertIsOnMainThread(); |
|
1307 MOZ_ASSERT(!sShutdownHasStarted); |
|
1308 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID)); |
|
1309 |
|
1310 sShutdownHasStarted = true; |
|
1311 |
|
1312 // Do this first before calling (and spinning the event loop in) |
|
1313 // ShutdownBackgroundThread(). |
|
1314 ChildImpl::Shutdown(); |
|
1315 |
|
1316 ShutdownBackgroundThread(); |
|
1317 |
|
1318 return NS_OK; |
|
1319 } |
|
1320 |
|
1321 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::RequestMessageLoopRunnable, |
|
1322 nsRunnable) |
|
1323 |
|
1324 NS_IMETHODIMP |
|
1325 ParentImpl::RequestMessageLoopRunnable::Run() |
|
1326 { |
|
1327 AssertIsInMainProcess(); |
|
1328 MOZ_ASSERT(mTargetThread); |
|
1329 |
|
1330 if (NS_IsMainThread()) { |
|
1331 MOZ_ASSERT(mMessageLoop); |
|
1332 |
|
1333 if (!sBackgroundThread || |
|
1334 !SameCOMIdentity(mTargetThread.get(), sBackgroundThread.get())) { |
|
1335 return NS_OK; |
|
1336 } |
|
1337 |
|
1338 MOZ_ASSERT(!sBackgroundThreadMessageLoop); |
|
1339 sBackgroundThreadMessageLoop = mMessageLoop; |
|
1340 |
|
1341 if (sPendingCallbacks && !sPendingCallbacks->IsEmpty()) { |
|
1342 nsTArray<nsRefPtr<CreateCallback>> callbacks; |
|
1343 sPendingCallbacks->SwapElements(callbacks); |
|
1344 |
|
1345 for (uint32_t index = 0; index < callbacks.Length(); index++) { |
|
1346 MOZ_ASSERT(callbacks[index]); |
|
1347 |
|
1348 nsCOMPtr<nsIRunnable> callbackRunnable = |
|
1349 new CreateCallbackRunnable(callbacks[index]); |
|
1350 if (NS_FAILED(NS_DispatchToCurrentThread(callbackRunnable))) { |
|
1351 NS_WARNING("Failed to dispatch callback runnable!"); |
|
1352 } |
|
1353 } |
|
1354 } |
|
1355 |
|
1356 return NS_OK; |
|
1357 } |
|
1358 |
|
1359 char stackBaseGuess; |
|
1360 profiler_register_thread("IPDL Background", &stackBaseGuess); |
|
1361 |
|
1362 #ifdef DEBUG |
|
1363 { |
|
1364 bool correctThread; |
|
1365 MOZ_ASSERT(NS_SUCCEEDED(mTargetThread->IsOnCurrentThread(&correctThread))); |
|
1366 MOZ_ASSERT(correctThread); |
|
1367 } |
|
1368 #endif |
|
1369 |
|
1370 DebugOnly<PRThread*> oldBackgroundThread = |
|
1371 sBackgroundPRThread.exchange(PR_GetCurrentThread()); |
|
1372 |
|
1373 MOZ_ASSERT_IF(oldBackgroundThread, |
|
1374 PR_GetCurrentThread() != oldBackgroundThread); |
|
1375 |
|
1376 MOZ_ASSERT(!mMessageLoop); |
|
1377 |
|
1378 mMessageLoop = MessageLoop::current(); |
|
1379 MOZ_ASSERT(mMessageLoop); |
|
1380 |
|
1381 if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) { |
|
1382 NS_WARNING("Failed to dispatch RequestMessageLoopRunnable to main thread!"); |
|
1383 return NS_ERROR_FAILURE; |
|
1384 } |
|
1385 |
|
1386 return NS_OK; |
|
1387 } |
|
1388 |
|
1389 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ShutdownBackgroundThreadRunnable, |
|
1390 nsRunnable) |
|
1391 |
|
1392 NS_IMETHODIMP |
|
1393 ParentImpl::ShutdownBackgroundThreadRunnable::Run() |
|
1394 { |
|
1395 AssertIsInMainProcess(); |
|
1396 |
|
1397 // It is possible that another background thread was created while this thread |
|
1398 // was shutting down. In that case we can't assert anything about |
|
1399 // sBackgroundPRThread and we should not modify it here. |
|
1400 sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr); |
|
1401 |
|
1402 profiler_unregister_thread(); |
|
1403 |
|
1404 return NS_OK; |
|
1405 } |
|
1406 |
|
1407 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ForceCloseBackgroundActorsRunnable, |
|
1408 nsRunnable) |
|
1409 |
|
1410 NS_IMETHODIMP |
|
1411 ParentImpl::ForceCloseBackgroundActorsRunnable::Run() |
|
1412 { |
|
1413 AssertIsInMainProcess(); |
|
1414 MOZ_ASSERT(mActorArray); |
|
1415 |
|
1416 if (NS_IsMainThread()) { |
|
1417 MOZ_ASSERT(sLiveActorCount); |
|
1418 sLiveActorCount--; |
|
1419 return NS_OK; |
|
1420 } |
|
1421 |
|
1422 AssertIsOnBackgroundThread(); |
|
1423 |
|
1424 if (!mActorArray->IsEmpty()) { |
|
1425 // Copy the array since calling Close() could mutate the actual array. |
|
1426 nsTArray<ParentImpl*> actorsToClose(*mActorArray); |
|
1427 |
|
1428 for (uint32_t index = 0; index < actorsToClose.Length(); index++) { |
|
1429 actorsToClose[index]->Close(); |
|
1430 } |
|
1431 } |
|
1432 |
|
1433 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(this))); |
|
1434 |
|
1435 return NS_OK; |
|
1436 } |
|
1437 |
|
1438 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::CreateCallbackRunnable, nsRunnable) |
|
1439 |
|
1440 NS_IMETHODIMP |
|
1441 ParentImpl::CreateCallbackRunnable::Run() |
|
1442 { |
|
1443 AssertIsInMainProcess(); |
|
1444 AssertIsOnMainThread(); |
|
1445 MOZ_ASSERT(sBackgroundThreadMessageLoop); |
|
1446 MOZ_ASSERT(mCallback); |
|
1447 |
|
1448 nsRefPtr<CreateCallback> callback; |
|
1449 mCallback.swap(callback); |
|
1450 |
|
1451 nsRefPtr<ParentImpl> actor = new ParentImpl(); |
|
1452 |
|
1453 callback->Success(actor.forget(), sBackgroundThreadMessageLoop); |
|
1454 |
|
1455 return NS_OK; |
|
1456 } |
|
1457 |
|
1458 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ConnectActorRunnable, nsRunnable) |
|
1459 |
|
1460 NS_IMETHODIMP |
|
1461 ParentImpl::ConnectActorRunnable::Run() |
|
1462 { |
|
1463 AssertIsInMainProcess(); |
|
1464 AssertIsOnBackgroundThread(); |
|
1465 |
|
1466 // Transfer ownership to this thread. If Open() fails then we will release |
|
1467 // this reference in Destroy. |
|
1468 ParentImpl* actor; |
|
1469 mActor.forget(&actor); |
|
1470 |
|
1471 if (!actor->Open(mTransport, mProcessHandle, XRE_GetIOMessageLoop(), |
|
1472 ParentSide)) { |
|
1473 actor->Destroy(); |
|
1474 return NS_ERROR_FAILURE; |
|
1475 } |
|
1476 |
|
1477 actor->SetLiveActorArray(mLiveActorArray); |
|
1478 |
|
1479 return NS_OK; |
|
1480 } |
|
1481 |
|
1482 // ----------------------------------------------------------------------------- |
|
1483 // ChildImpl Implementation |
|
1484 // ----------------------------------------------------------------------------- |
|
1485 |
|
1486 // static |
|
1487 void |
|
1488 ChildImpl::Startup() |
|
1489 { |
|
1490 // This happens on the main thread but before XPCOM has started so we can't |
|
1491 // assert that we're being called on the main thread here. |
|
1492 |
|
1493 MOZ_ASSERT(sThreadLocalIndex == kBadThreadLocalIndex, |
|
1494 "BackgroundChild::Startup() called more than once!"); |
|
1495 |
|
1496 PRStatus status = |
|
1497 PR_NewThreadPrivateIndex(&sThreadLocalIndex, ThreadLocalDestructor); |
|
1498 MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!"); |
|
1499 |
|
1500 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex); |
|
1501 |
|
1502 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
|
1503 MOZ_RELEASE_ASSERT(observerService); |
|
1504 |
|
1505 nsCOMPtr<nsIObserver> observer = new ShutdownObserver(); |
|
1506 |
|
1507 nsresult rv = |
|
1508 observerService->AddObserver(observer, |
|
1509 NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, |
|
1510 false); |
|
1511 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); |
|
1512 } |
|
1513 |
|
1514 // static |
|
1515 void |
|
1516 ChildImpl::Shutdown() |
|
1517 { |
|
1518 AssertIsOnMainThread(); |
|
1519 |
|
1520 if (sShutdownHasStarted) { |
|
1521 MOZ_ASSERT_IF(sThreadLocalIndex != kBadThreadLocalIndex, |
|
1522 !PR_GetThreadPrivate(sThreadLocalIndex)); |
|
1523 return; |
|
1524 } |
|
1525 |
|
1526 sShutdownHasStarted = true; |
|
1527 |
|
1528 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex); |
|
1529 |
|
1530 DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr); |
|
1531 MOZ_ASSERT(status == PR_SUCCESS); |
|
1532 } |
|
1533 |
|
1534 // static |
|
1535 PBackgroundChild* |
|
1536 ChildImpl::Alloc(Transport* aTransport, ProcessId aOtherProcess) |
|
1537 { |
|
1538 AssertIsInChildProcess(); |
|
1539 AssertIsOnMainThread(); |
|
1540 MOZ_ASSERT(aTransport); |
|
1541 MOZ_ASSERT(sPendingTargets); |
|
1542 MOZ_ASSERT(!sPendingTargets->IsEmpty()); |
|
1543 |
|
1544 nsCOMPtr<nsIEventTarget> eventTarget; |
|
1545 sPendingTargets->ElementAt(0).swap(eventTarget); |
|
1546 |
|
1547 sPendingTargets->RemoveElementAt(0); |
|
1548 |
|
1549 ProcessHandle processHandle; |
|
1550 if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) { |
|
1551 MOZ_CRASH("Failed to open process handle!"); |
|
1552 } |
|
1553 |
|
1554 nsRefPtr<ChildImpl> actor = new ChildImpl(); |
|
1555 |
|
1556 ChildImpl* weakActor = actor; |
|
1557 |
|
1558 nsCOMPtr<nsIRunnable> openRunnable = |
|
1559 new OpenChildProcessActorRunnable(actor.forget(), aTransport, |
|
1560 processHandle); |
|
1561 if (NS_FAILED(eventTarget->Dispatch(openRunnable, NS_DISPATCH_NORMAL))) { |
|
1562 MOZ_CRASH("Failed to dispatch OpenActorRunnable!"); |
|
1563 } |
|
1564 |
|
1565 // This value is only checked against null to determine success/failure, so |
|
1566 // there is no need to worry about the reference count here. |
|
1567 return weakActor; |
|
1568 } |
|
1569 |
|
1570 // static |
|
1571 PBackgroundChild* |
|
1572 ChildImpl::GetForCurrentThread() |
|
1573 { |
|
1574 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex); |
|
1575 |
|
1576 auto threadLocalInfo = |
|
1577 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); |
|
1578 |
|
1579 return threadLocalInfo ? threadLocalInfo->mActor : nullptr; |
|
1580 } |
|
1581 |
|
1582 // static |
|
1583 bool |
|
1584 ChildImpl::GetOrCreateForCurrentThread( |
|
1585 nsIIPCBackgroundChildCreateCallback* aCallback) |
|
1586 { |
|
1587 MOZ_ASSERT(aCallback); |
|
1588 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex, |
|
1589 "BackgroundChild::Startup() was never called!"); |
|
1590 |
|
1591 bool created = false; |
|
1592 |
|
1593 auto threadLocalInfo = |
|
1594 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); |
|
1595 |
|
1596 if (threadLocalInfo) { |
|
1597 threadLocalInfo->mCallbacks.AppendElement(aCallback); |
|
1598 } else { |
|
1599 nsAutoPtr<ThreadLocalInfo> newInfo(new ThreadLocalInfo(aCallback)); |
|
1600 |
|
1601 if (PR_SetThreadPrivate(sThreadLocalIndex, newInfo) != PR_SUCCESS) { |
|
1602 CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!"); |
|
1603 return false; |
|
1604 } |
|
1605 |
|
1606 created = true; |
|
1607 threadLocalInfo = newInfo.forget(); |
|
1608 } |
|
1609 |
|
1610 if (threadLocalInfo->mActor) { |
|
1611 nsRefPtr<ChildImpl> actor = threadLocalInfo->mActor; |
|
1612 |
|
1613 nsCOMPtr<nsIRunnable> runnable = new CreateCallbackRunnable(actor.forget()); |
|
1614 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable))); |
|
1615 |
|
1616 return true; |
|
1617 } |
|
1618 |
|
1619 if (!created) { |
|
1620 // We have already started the sequence for opening the actor so there's |
|
1621 // nothing else we need to do here. This callback will be called after the |
|
1622 // first callback in CreateCallbackRunnable::Run(). |
|
1623 return true; |
|
1624 } |
|
1625 |
|
1626 if (NS_IsMainThread()) { |
|
1627 if (NS_WARN_IF(!OpenProtocolOnMainThread(NS_GetCurrentThread()))) { |
|
1628 return false; |
|
1629 } |
|
1630 |
|
1631 return true; |
|
1632 } |
|
1633 |
|
1634 nsRefPtr<CreateActorRunnable> runnable = new CreateActorRunnable(); |
|
1635 if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) { |
|
1636 CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!"); |
|
1637 return false; |
|
1638 } |
|
1639 |
|
1640 return true; |
|
1641 } |
|
1642 |
|
1643 // static |
|
1644 BackgroundChildImpl::ThreadLocal* |
|
1645 ChildImpl::GetThreadLocalForCurrentThread() |
|
1646 { |
|
1647 MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex, |
|
1648 "BackgroundChild::Startup() was never called!"); |
|
1649 |
|
1650 auto threadLocalInfo = |
|
1651 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); |
|
1652 |
|
1653 if (!threadLocalInfo) { |
|
1654 return nullptr; |
|
1655 } |
|
1656 |
|
1657 if (!threadLocalInfo->mConsumerThreadLocal) { |
|
1658 threadLocalInfo->mConsumerThreadLocal = |
|
1659 new BackgroundChildImpl::ThreadLocal(); |
|
1660 } |
|
1661 |
|
1662 return threadLocalInfo->mConsumerThreadLocal; |
|
1663 } |
|
1664 |
|
1665 ChildImpl::CreateCallbackRunnable::~CreateCallbackRunnable() |
|
1666 { |
|
1667 if (mActor) { |
|
1668 CRASH_IN_CHILD_PROCESS("Leaking actor!"); |
|
1669 unused << mActor.forget(); |
|
1670 } |
|
1671 } |
|
1672 |
|
1673 // static |
|
1674 already_AddRefed<nsIIPCBackgroundChildCreateCallback> |
|
1675 ChildImpl::CreateCallbackRunnable::GetNextCallback() |
|
1676 { |
|
1677 // May run on any thread! |
|
1678 |
|
1679 auto threadLocalInfo = |
|
1680 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); |
|
1681 MOZ_ASSERT(threadLocalInfo); |
|
1682 |
|
1683 if (threadLocalInfo->mCallbacks.IsEmpty()) { |
|
1684 return nullptr; |
|
1685 } |
|
1686 |
|
1687 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback; |
|
1688 threadLocalInfo->mCallbacks[0].swap(callback); |
|
1689 |
|
1690 threadLocalInfo->mCallbacks.RemoveElementAt(0); |
|
1691 |
|
1692 return callback.forget(); |
|
1693 } |
|
1694 |
|
1695 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::CreateCallbackRunnable, nsRunnable) |
|
1696 |
|
1697 NS_IMETHODIMP |
|
1698 ChildImpl::CreateCallbackRunnable::Run() |
|
1699 { |
|
1700 // May run on any thread! |
|
1701 |
|
1702 nsRefPtr<ChildImpl> actor; |
|
1703 mActor.swap(actor); |
|
1704 |
|
1705 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = GetNextCallback(); |
|
1706 while (callback) { |
|
1707 if (actor) { |
|
1708 callback->ActorCreated(actor); |
|
1709 } else { |
|
1710 callback->ActorFailed(); |
|
1711 } |
|
1712 |
|
1713 callback = GetNextCallback(); |
|
1714 } |
|
1715 |
|
1716 return NS_OK; |
|
1717 } |
|
1718 |
|
1719 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenChildProcessActorRunnable, |
|
1720 ChildImpl::CreateCallbackRunnable) |
|
1721 |
|
1722 NS_IMETHODIMP |
|
1723 ChildImpl::OpenChildProcessActorRunnable::Run() |
|
1724 { |
|
1725 // May be run on any thread! |
|
1726 |
|
1727 AssertIsInChildProcess(); |
|
1728 MOZ_ASSERT(mActor); |
|
1729 MOZ_ASSERT(mTransport); |
|
1730 |
|
1731 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = GetNextCallback(); |
|
1732 MOZ_ASSERT(callback, |
|
1733 "There should be at least one callback when first creating the " |
|
1734 "actor!"); |
|
1735 |
|
1736 nsRefPtr<ChildImpl> strongActor; |
|
1737 mActor.swap(strongActor); |
|
1738 |
|
1739 if (!strongActor->Open(mTransport.forget(), mProcessHandle, |
|
1740 XRE_GetIOMessageLoop(), ChildSide)) { |
|
1741 CRASH_IN_CHILD_PROCESS("Failed to open ChildImpl!"); |
|
1742 |
|
1743 while (callback) { |
|
1744 callback->ActorFailed(); |
|
1745 callback = GetNextCallback(); |
|
1746 } |
|
1747 |
|
1748 return NS_OK; |
|
1749 } |
|
1750 |
|
1751 // Now that Open() has succeeded transfer the ownership of the actor to IPDL. |
|
1752 auto threadLocalInfo = |
|
1753 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); |
|
1754 |
|
1755 MOZ_ASSERT(threadLocalInfo); |
|
1756 MOZ_ASSERT(!threadLocalInfo->mActor); |
|
1757 |
|
1758 nsRefPtr<ChildImpl>& actor = threadLocalInfo->mActor; |
|
1759 strongActor.swap(actor); |
|
1760 |
|
1761 actor->SetBoundThread(); |
|
1762 |
|
1763 while (callback) { |
|
1764 callback->ActorCreated(actor); |
|
1765 callback = GetNextCallback(); |
|
1766 } |
|
1767 |
|
1768 return NS_OK; |
|
1769 } |
|
1770 |
|
1771 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::OpenMainProcessActorRunnable, |
|
1772 ChildImpl::CreateCallbackRunnable) |
|
1773 |
|
1774 NS_IMETHODIMP |
|
1775 ChildImpl::OpenMainProcessActorRunnable::Run() |
|
1776 { |
|
1777 // May run on any thread! |
|
1778 |
|
1779 AssertIsInMainProcess(); |
|
1780 MOZ_ASSERT(mActor); |
|
1781 MOZ_ASSERT(mParentActor); |
|
1782 MOZ_ASSERT(mParentMessageLoop); |
|
1783 |
|
1784 nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = GetNextCallback(); |
|
1785 MOZ_ASSERT(callback, |
|
1786 "There should be at least one callback when first creating the " |
|
1787 "actor!"); |
|
1788 |
|
1789 nsRefPtr<ChildImpl> strongChildActor; |
|
1790 mActor.swap(strongChildActor); |
|
1791 |
|
1792 nsRefPtr<ParentImpl> parentActor; |
|
1793 mParentActor.swap(parentActor); |
|
1794 |
|
1795 MessageChannel* parentChannel = parentActor->GetIPCChannel(); |
|
1796 MOZ_ASSERT(parentChannel); |
|
1797 |
|
1798 if (!strongChildActor->Open(parentChannel, mParentMessageLoop, ChildSide)) { |
|
1799 NS_WARNING("Failed to open ChildImpl!"); |
|
1800 |
|
1801 parentActor->Destroy(); |
|
1802 |
|
1803 while (callback) { |
|
1804 callback->ActorFailed(); |
|
1805 callback = GetNextCallback(); |
|
1806 } |
|
1807 |
|
1808 return NS_OK; |
|
1809 } |
|
1810 |
|
1811 // Now that Open() has succeeded transfer the ownership of the actors to IPDL. |
|
1812 unused << parentActor.forget(); |
|
1813 |
|
1814 auto threadLocalInfo = |
|
1815 static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); |
|
1816 |
|
1817 MOZ_ASSERT(threadLocalInfo); |
|
1818 MOZ_ASSERT(!threadLocalInfo->mActor); |
|
1819 |
|
1820 nsRefPtr<ChildImpl>& childActor = threadLocalInfo->mActor; |
|
1821 strongChildActor.swap(childActor); |
|
1822 |
|
1823 childActor->SetBoundThread(); |
|
1824 |
|
1825 while (callback) { |
|
1826 callback->ActorCreated(childActor); |
|
1827 callback = GetNextCallback(); |
|
1828 } |
|
1829 |
|
1830 return NS_OK; |
|
1831 } |
|
1832 |
|
1833 NS_IMPL_ISUPPORTS_INHERITED0(ChildImpl::CreateActorRunnable, nsRunnable) |
|
1834 |
|
1835 NS_IMETHODIMP |
|
1836 ChildImpl::CreateActorRunnable::Run() |
|
1837 { |
|
1838 AssertIsOnMainThread(); |
|
1839 |
|
1840 if (!OpenProtocolOnMainThread(mEventTarget)) { |
|
1841 NS_WARNING("OpenProtocolOnMainThread failed!"); |
|
1842 return NS_ERROR_FAILURE; |
|
1843 } |
|
1844 |
|
1845 return NS_OK; |
|
1846 } |
|
1847 |
|
1848 void |
|
1849 ChildImpl::ParentCreateCallback::Success( |
|
1850 already_AddRefed<ParentImpl> aParentActor, |
|
1851 MessageLoop* aParentMessageLoop) |
|
1852 { |
|
1853 AssertIsInMainProcess(); |
|
1854 AssertIsOnMainThread(); |
|
1855 |
|
1856 nsRefPtr<ParentImpl> parentActor = aParentActor; |
|
1857 MOZ_ASSERT(parentActor); |
|
1858 MOZ_ASSERT(aParentMessageLoop); |
|
1859 MOZ_ASSERT(mEventTarget); |
|
1860 |
|
1861 nsRefPtr<ChildImpl> childActor = new ChildImpl(); |
|
1862 |
|
1863 nsCOMPtr<nsIEventTarget> target; |
|
1864 mEventTarget.swap(target); |
|
1865 |
|
1866 nsCOMPtr<nsIRunnable> openRunnable = |
|
1867 new OpenMainProcessActorRunnable(childActor.forget(), parentActor.forget(), |
|
1868 aParentMessageLoop); |
|
1869 if (NS_FAILED(target->Dispatch(openRunnable, NS_DISPATCH_NORMAL))) { |
|
1870 NS_WARNING("Failed to dispatch open runnable!"); |
|
1871 } |
|
1872 } |
|
1873 |
|
1874 void |
|
1875 ChildImpl::ParentCreateCallback::Failure() |
|
1876 { |
|
1877 AssertIsInMainProcess(); |
|
1878 AssertIsOnMainThread(); |
|
1879 MOZ_ASSERT(mEventTarget); |
|
1880 |
|
1881 nsCOMPtr<nsIEventTarget> target; |
|
1882 mEventTarget.swap(target); |
|
1883 |
|
1884 DispatchFailureCallback(target); |
|
1885 } |
|
1886 |
|
1887 // static |
|
1888 bool |
|
1889 ChildImpl::OpenProtocolOnMainThread(nsIEventTarget* aEventTarget) |
|
1890 { |
|
1891 AssertIsOnMainThread(); |
|
1892 MOZ_ASSERT(aEventTarget); |
|
1893 |
|
1894 if (sShutdownHasStarted) { |
|
1895 MOZ_CRASH("Called BackgroundChild::GetOrCreateForCurrentThread after " |
|
1896 "shutdown has started!"); |
|
1897 } |
|
1898 |
|
1899 if (IsMainProcess()) { |
|
1900 nsRefPtr<ParentImpl::CreateCallback> parentCallback = |
|
1901 new ParentCreateCallback(aEventTarget); |
|
1902 |
|
1903 if (!ParentImpl::CreateActorForSameProcess(parentCallback)) { |
|
1904 NS_WARNING("BackgroundParent::CreateActor() failed!"); |
|
1905 DispatchFailureCallback(aEventTarget); |
|
1906 return false; |
|
1907 } |
|
1908 |
|
1909 return true; |
|
1910 } |
|
1911 |
|
1912 ContentChild* content = ContentChild::GetSingleton(); |
|
1913 MOZ_ASSERT(content); |
|
1914 |
|
1915 if (!PBackground::Open(content)) { |
|
1916 MOZ_CRASH("Failed to create top level actor!"); |
|
1917 return false; |
|
1918 } |
|
1919 |
|
1920 if (!sPendingTargets) { |
|
1921 sPendingTargets = new nsTArray<nsCOMPtr<nsIEventTarget>>(1); |
|
1922 ClearOnShutdown(&sPendingTargets); |
|
1923 } |
|
1924 |
|
1925 sPendingTargets->AppendElement(aEventTarget); |
|
1926 |
|
1927 return true; |
|
1928 } |
|
1929 |
|
1930 // static |
|
1931 void |
|
1932 ChildImpl::DispatchFailureCallback(nsIEventTarget* aEventTarget) |
|
1933 { |
|
1934 MOZ_ASSERT(aEventTarget); |
|
1935 |
|
1936 nsCOMPtr<nsIRunnable> callbackRunnable = new CreateCallbackRunnable(); |
|
1937 if (NS_FAILED(aEventTarget->Dispatch(callbackRunnable, NS_DISPATCH_NORMAL))) { |
|
1938 NS_WARNING("Failed to dispatch CreateCallbackRunnable!"); |
|
1939 } |
|
1940 } |
|
1941 |
|
1942 void |
|
1943 ChildImpl::ActorDestroy(ActorDestroyReason aWhy) |
|
1944 { |
|
1945 AssertIsOnBoundThread(); |
|
1946 |
|
1947 BackgroundChildImpl::ActorDestroy(aWhy); |
|
1948 } |
|
1949 |
|
1950 NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver) |
|
1951 |
|
1952 NS_IMETHODIMP |
|
1953 ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject, |
|
1954 const char* aTopic, |
|
1955 const char16_t* aData) |
|
1956 { |
|
1957 AssertIsOnMainThread(); |
|
1958 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID)); |
|
1959 |
|
1960 ChildImpl::Shutdown(); |
|
1961 |
|
1962 return NS_OK; |
|
1963 } |