Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/ipc/glue/BackgroundImpl.cpp
Line
Count
Source (jump to first uncovered line)
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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "BackgroundChild.h"
8
#include "BackgroundParent.h"
9
10
#include "BackgroundChildImpl.h"
11
#include "BackgroundParentImpl.h"
12
#include "base/process_util.h"
13
#include "base/task.h"
14
#include "FileDescriptor.h"
15
#include "GeckoProfiler.h"
16
#include "InputStreamUtils.h"
17
#include "mozilla/Assertions.h"
18
#include "mozilla/Atomics.h"
19
#include "mozilla/ClearOnShutdown.h"
20
#include "mozilla/DebugOnly.h"
21
#include "mozilla/Services.h"
22
#include "mozilla/StaticPtr.h"
23
#include "mozilla/Unused.h"
24
#include "mozilla/dom/ContentChild.h"
25
#include "mozilla/dom/ContentParent.h"
26
#include "mozilla/dom/File.h"
27
#include "mozilla/ipc/ProtocolTypes.h"
28
#include "nsAutoPtr.h"
29
#include "nsCOMPtr.h"
30
#include "nsIEventTarget.h"
31
#include "nsIMutable.h"
32
#include "nsIObserver.h"
33
#include "nsIObserverService.h"
34
#include "nsIRunnable.h"
35
#include "nsISupportsImpl.h"
36
#include "nsIThread.h"
37
#include "nsITimer.h"
38
#include "nsTArray.h"
39
#include "nsThreadUtils.h"
40
#include "nsTraceRefcnt.h"
41
#include "nsXULAppAPI.h"
42
#include "nsXPCOMPrivate.h"
43
#include "prthread.h"
44
45
#ifdef RELEASE_OR_BETA
46
#define THREADSAFETY_ASSERT MOZ_ASSERT
47
#else
48
3
#define THREADSAFETY_ASSERT MOZ_RELEASE_ASSERT
49
#endif
50
51
#define CRASH_IN_CHILD_PROCESS(_msg)                                           \
52
0
  do {                                                                         \
53
0
    if (XRE_IsParentProcess()) {                                               \
54
0
      MOZ_ASSERT(false, _msg);                                                 \
55
0
    } else {                                                                   \
56
0
      MOZ_CRASH(_msg);                                                         \
57
0
    }                                                                          \
58
0
  }                                                                            \
59
0
  while (0)
60
61
using namespace mozilla;
62
using namespace mozilla::dom;
63
using namespace mozilla::ipc;
64
65
namespace {
66
67
class ChildImpl;
68
69
// -----------------------------------------------------------------------------
70
// Utility Functions
71
// -----------------------------------------------------------------------------
72
73
74
void
75
AssertIsInMainProcess()
76
0
{
77
0
  MOZ_ASSERT(XRE_IsParentProcess());
78
0
}
79
80
void
81
AssertIsOnMainThread()
82
3
{
83
3
  THREADSAFETY_ASSERT(NS_IsMainThread());
84
3
}
85
86
void
87
AssertIsNotOnMainThread()
88
0
{
89
0
  THREADSAFETY_ASSERT(!NS_IsMainThread());
90
0
}
91
92
// -----------------------------------------------------------------------------
93
// ParentImpl Declaration
94
// -----------------------------------------------------------------------------
95
96
class ParentImpl final : public BackgroundParentImpl
97
{
98
  friend class mozilla::ipc::BackgroundParent;
99
100
public:
101
  class CreateCallback;
102
103
private:
104
  class ShutdownObserver;
105
  class RequestMessageLoopRunnable;
106
  class ShutdownBackgroundThreadRunnable;
107
  class ForceCloseBackgroundActorsRunnable;
108
  class ConnectActorRunnable;
109
  class CreateActorHelper;
110
111
  struct MOZ_STACK_CLASS TimerCallbackClosure
112
  {
113
    nsIThread* mThread;
114
    nsTArray<ParentImpl*>* mLiveActors;
115
116
    TimerCallbackClosure(nsIThread* aThread, nsTArray<ParentImpl*>* aLiveActors)
117
      : mThread(aThread), mLiveActors(aLiveActors)
118
0
    {
119
0
      AssertIsInMainProcess();
120
0
      AssertIsOnMainThread();
121
0
      MOZ_ASSERT(aThread);
122
0
      MOZ_ASSERT(aLiveActors);
123
0
    }
124
  };
125
126
  // The length of time we will wait at shutdown for all actors to clean
127
  // themselves up before forcing them to be destroyed.
128
  static const uint32_t kShutdownTimerDelayMS = 10000;
129
130
  // This is only modified on the main thread. It is null if the thread does not
131
  // exist or is shutting down.
132
  static StaticRefPtr<nsIThread> sBackgroundThread;
133
134
  // This is created and destroyed on the main thread but only modified on the
135
  // background thread. It is specific to each instance of sBackgroundThread.
136
  static nsTArray<ParentImpl*>* sLiveActorsForBackgroundThread;
137
138
  // This is only modified on the main thread.
139
  static StaticRefPtr<nsITimer> sShutdownTimer;
140
141
  // This exists so that that [Assert]IsOnBackgroundThread() can continue to
142
  // work during shutdown.
143
  static Atomic<PRThread*> sBackgroundPRThread;
144
145
  // This is only modified on the main thread. It is null if the thread does not
146
  // exist or is shutting down.
147
  static MessageLoop* sBackgroundThreadMessageLoop;
148
149
  // This is only modified on the main thread. It maintains a count of live
150
  // actors so that the background thread can be shut down when it is no longer
151
  // needed.
152
  static uint64_t sLiveActorCount;
153
154
  // This is only modified on the main thread. It is true after the shutdown
155
  // observer is registered and is never unset thereafter.
156
  static bool sShutdownObserverRegistered;
157
158
  // This is only modified on the main thread. It prevents us from trying to
159
  // create the background thread after application shutdown has started.
160
  static bool sShutdownHasStarted;
161
162
  // Only touched on the main thread, null if this is a same-process actor.
163
  RefPtr<ContentParent> mContent;
164
165
  // Set when the actor is opened successfully and used to handle shutdown
166
  // hangs. Only touched on the background thread.
167
  nsTArray<ParentImpl*>* mLiveActorArray;
168
169
  // Set at construction to indicate whether this parent actor corresponds to a
170
  // child actor in another process or to a child actor from a different thread
171
  // in the same process.
172
  const bool mIsOtherProcessActor;
173
174
  // Set after ActorDestroy has been called. Only touched on the background
175
  // thread.
176
  bool mActorDestroyed;
177
178
public:
179
  static already_AddRefed<ChildImpl>
180
  CreateActorForSameProcess();
181
182
  static bool
183
  IsOnBackgroundThread()
184
0
  {
185
0
    return PR_GetCurrentThread() == sBackgroundPRThread;
186
0
  }
187
188
  static void
189
  AssertIsOnBackgroundThread()
190
0
  {
191
0
    THREADSAFETY_ASSERT(IsOnBackgroundThread());
192
0
  }
193
194
  NS_INLINE_DECL_REFCOUNTING(ParentImpl)
195
196
  void
197
  Destroy();
198
199
private:
200
  // Forwarded from BackgroundParent.
201
  static bool
202
  IsOtherProcessActor(PBackgroundParent* aBackgroundActor);
203
204
  // Forwarded from BackgroundParent.
205
  static already_AddRefed<ContentParent>
206
  GetContentParent(PBackgroundParent* aBackgroundActor);
207
208
  // Forwarded from BackgroundParent.
209
  static intptr_t
210
  GetRawContentParentForComparison(PBackgroundParent* aBackgroundActor);
211
212
  // Forwarded from BackgroundParent.
213
  static uint64_t
214
  GetChildID(PBackgroundParent* aBackgroundActor);
215
216
  // Forwarded from BackgroundParent.
217
  static bool
218
  GetLiveActorArray(PBackgroundParent* aBackgroundActor,
219
                    nsTArray<PBackgroundParent*>& aLiveActorArray);
220
221
  // Forwarded from BackgroundParent.
222
  static bool
223
  Alloc(ContentParent* aContent,
224
        Endpoint<PBackgroundParent>&& aEndpoint);
225
226
  static bool
227
  CreateBackgroundThread();
228
229
  static void
230
  ShutdownBackgroundThread();
231
232
  static void
233
  ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
234
235
  // For same-process actors.
236
  ParentImpl()
237
  : mLiveActorArray(nullptr), mIsOtherProcessActor(false),
238
    mActorDestroyed(false)
239
0
  {
240
0
    AssertIsInMainProcess();
241
0
    AssertIsOnMainThread();
242
0
  }
243
244
  // For other-process actors.
245
  explicit ParentImpl(ContentParent* aContent)
246
  : mContent(aContent), mLiveActorArray(nullptr),
247
    mIsOtherProcessActor(true), mActorDestroyed(false)
248
0
  {
249
0
    AssertIsInMainProcess();
250
0
    AssertIsOnMainThread();
251
0
    MOZ_ASSERT(aContent);
252
0
  }
253
254
  ~ParentImpl()
255
0
  {
256
0
    AssertIsInMainProcess();
257
0
    AssertIsOnMainThread();
258
0
    MOZ_ASSERT(!mContent);
259
0
  }
260
261
  void
262
  MainThreadActorDestroy();
263
264
  void
265
  SetLiveActorArray(nsTArray<ParentImpl*>* aLiveActorArray)
266
0
  {
267
0
    AssertIsInMainProcess();
268
0
    AssertIsOnBackgroundThread();
269
0
    MOZ_ASSERT(aLiveActorArray);
270
0
    MOZ_ASSERT(!aLiveActorArray->Contains(this));
271
0
    MOZ_ASSERT(!mLiveActorArray);
272
0
    MOZ_ASSERT(mIsOtherProcessActor);
273
0
274
0
    mLiveActorArray = aLiveActorArray;
275
0
    mLiveActorArray->AppendElement(this);
276
0
  }
277
278
  // These methods are only called by IPDL.
279
  virtual void
280
  ActorDestroy(ActorDestroyReason aWhy) override;
281
};
282
283
// -----------------------------------------------------------------------------
284
// ChildImpl Declaration
285
// -----------------------------------------------------------------------------
286
287
class ChildImpl final : public BackgroundChildImpl
288
{
289
  friend class mozilla::ipc::BackgroundChild;
290
  friend class mozilla::ipc::BackgroundChildImpl;
291
292
  typedef base::ProcessId ProcessId;
293
  typedef mozilla::ipc::Transport Transport;
294
295
  class ShutdownObserver;
296
  class ActorCreatedRunnable;
297
298
  // A thread-local index that is not valid.
299
  static const unsigned int kBadThreadLocalIndex =
300
    static_cast<unsigned int>(-1);
301
302
  // This is only modified on the main thread. It is the thread-local index that
303
  // we use to store the BackgroundChild for each thread.
304
  static unsigned int sThreadLocalIndex;
305
306
  struct ThreadLocalInfo
307
  {
308
    ThreadLocalInfo()
309
#ifdef DEBUG
310
      : mClosed(false)
311
#endif
312
0
    {
313
0
    }
314
315
    RefPtr<ChildImpl> mActor;
316
    nsAutoPtr<BackgroundChildImpl::ThreadLocal> mConsumerThreadLocal;
317
#ifdef DEBUG
318
    bool mClosed;
319
#endif
320
  };
321
322
  // On the main thread, we store TLS in this global instead of in
323
  // sThreadLocalIndex. That way, cooperative main threads all share the same
324
  // thread info.
325
  static ThreadLocalInfo* sMainThreadInfo;
326
327
  // This is only modified on the main thread. It prevents us from trying to
328
  // create the background thread after application shutdown has started.
329
  static bool sShutdownHasStarted;
330
331
#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
332
  nsISerialEventTarget* mOwningEventTarget;
333
#endif
334
335
#ifdef DEBUG
336
  bool mActorWasAlive;
337
  bool mActorDestroyed;
338
#endif
339
340
public:
341
  static void
342
  Shutdown();
343
344
  void
345
  AssertIsOnOwningThread()
346
0
  {
347
0
    THREADSAFETY_ASSERT(mOwningEventTarget);
348
0
349
#ifdef RELEASE_OR_BETA
350
    DebugOnly<bool> current;
351
#else
352
0
    bool current;
353
0
#endif
354
0
    THREADSAFETY_ASSERT(
355
0
      NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)));
356
0
    THREADSAFETY_ASSERT(current);
357
0
  }
358
359
  void
360
  AssertActorDestroyed()
361
0
  {
362
0
    MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
363
0
  }
364
365
  explicit ChildImpl()
366
#if defined(DEBUG) || !defined(RELEASE_OR_BETA)
367
  : mOwningEventTarget(GetCurrentThreadSerialEventTarget())
368
#endif
369
#ifdef DEBUG
370
  , mActorWasAlive(false)
371
  , mActorDestroyed(false)
372
#endif
373
0
  {
374
0
    AssertIsOnOwningThread();
375
0
  }
376
377
  void
378
  SetActorAlive()
379
0
  {
380
0
    AssertIsOnOwningThread();
381
0
    MOZ_ASSERT(!mActorWasAlive);
382
0
    MOZ_ASSERT(!mActorDestroyed);
383
0
384
#ifdef DEBUG
385
    mActorWasAlive = true;
386
#endif
387
  }
388
389
  NS_INLINE_DECL_REFCOUNTING(ChildImpl)
390
391
private:
392
  // Forwarded from BackgroundChild.
393
  static void
394
  Startup();
395
396
  // Forwarded from BackgroundChild.
397
  static PBackgroundChild*
398
  GetForCurrentThread();
399
400
  // Forwarded from BackgroundChild.
401
  static PBackgroundChild*
402
  GetOrCreateForCurrentThread();
403
404
  // Forwarded from BackgroundChild.
405
  static void
406
  CloseForCurrentThread();
407
408
  // Forwarded from BackgroundChildImpl.
409
  static BackgroundChildImpl::ThreadLocal*
410
  GetThreadLocalForCurrentThread();
411
412
  static void
413
  ThreadLocalDestructor(void* aThreadLocal)
414
0
  {
415
0
    auto threadLocalInfo = static_cast<ThreadLocalInfo*>(aThreadLocal);
416
0
417
0
    if (threadLocalInfo) {
418
0
      MOZ_ASSERT(threadLocalInfo->mClosed);
419
0
420
0
      if (threadLocalInfo->mActor) {
421
0
        threadLocalInfo->mActor->Close();
422
0
        threadLocalInfo->mActor->AssertActorDestroyed();
423
0
      }
424
0
      delete threadLocalInfo;
425
0
    }
426
0
  }
427
428
  // This class is reference counted.
429
  ~ChildImpl()
430
0
  {
431
0
    MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed);
432
0
  }
433
434
  // Only called by IPDL.
435
  virtual void
436
  ActorDestroy(ActorDestroyReason aWhy) override;
437
};
438
439
// -----------------------------------------------------------------------------
440
// ParentImpl Helper Declarations
441
// -----------------------------------------------------------------------------
442
443
class ParentImpl::ShutdownObserver final : public nsIObserver
444
{
445
public:
446
  ShutdownObserver()
447
0
  {
448
0
    AssertIsOnMainThread();
449
0
  }
450
451
  NS_DECL_ISUPPORTS
452
  NS_DECL_NSIOBSERVER
453
454
private:
455
  ~ShutdownObserver()
456
0
  {
457
0
    AssertIsOnMainThread();
458
0
  }
459
};
460
461
class ParentImpl::RequestMessageLoopRunnable final : public Runnable
462
{
463
  nsCOMPtr<nsIThread> mTargetThread;
464
  MessageLoop* mMessageLoop;
465
466
public:
467
  explicit RequestMessageLoopRunnable(nsIThread* aTargetThread)
468
    : Runnable("Background::ParentImpl::RequestMessageLoopRunnable")
469
    , mTargetThread(aTargetThread)
470
    , mMessageLoop(nullptr)
471
0
  {
472
0
    AssertIsInMainProcess();
473
0
    AssertIsOnMainThread();
474
0
    MOZ_ASSERT(aTargetThread);
475
0
  }
476
477
private:
478
  ~RequestMessageLoopRunnable()
479
0
  { }
480
481
  NS_DECL_NSIRUNNABLE
482
};
483
484
class ParentImpl::ShutdownBackgroundThreadRunnable final : public Runnable
485
{
486
public:
487
  ShutdownBackgroundThreadRunnable()
488
    : Runnable("Background::ParentImpl::ShutdownBackgroundThreadRunnable")
489
0
  {
490
0
    AssertIsInMainProcess();
491
0
    AssertIsOnMainThread();
492
0
  }
493
494
private:
495
  ~ShutdownBackgroundThreadRunnable()
496
0
  { }
497
498
  NS_DECL_NSIRUNNABLE
499
};
500
501
class ParentImpl::ForceCloseBackgroundActorsRunnable final : public Runnable
502
{
503
  nsTArray<ParentImpl*>* mActorArray;
504
505
public:
506
  explicit ForceCloseBackgroundActorsRunnable(nsTArray<ParentImpl*>* aActorArray)
507
    : Runnable("Background::ParentImpl::ForceCloseBackgroundActorsRunnable")
508
    , mActorArray(aActorArray)
509
0
  {
510
0
    AssertIsInMainProcess();
511
0
    AssertIsOnMainThread();
512
0
    MOZ_ASSERT(aActorArray);
513
0
  }
514
515
private:
516
  ~ForceCloseBackgroundActorsRunnable()
517
0
  { }
518
519
  NS_DECL_NSIRUNNABLE
520
};
521
522
class ParentImpl::ConnectActorRunnable final : public Runnable
523
{
524
  RefPtr<ParentImpl> mActor;
525
  Endpoint<PBackgroundParent> mEndpoint;
526
  nsTArray<ParentImpl*>* mLiveActorArray;
527
528
public:
529
  ConnectActorRunnable(ParentImpl* aActor,
530
                       Endpoint<PBackgroundParent>&& aEndpoint,
531
                       nsTArray<ParentImpl*>* aLiveActorArray)
532
    : Runnable("Background::ParentImpl::ConnectActorRunnable")
533
    , mActor(aActor)
534
    , mEndpoint(std::move(aEndpoint))
535
    , mLiveActorArray(aLiveActorArray)
536
0
  {
537
0
    AssertIsInMainProcess();
538
0
    AssertIsOnMainThread();
539
0
    MOZ_ASSERT(mEndpoint.IsValid());
540
0
    MOZ_ASSERT(aLiveActorArray);
541
0
  }
542
543
private:
544
  ~ConnectActorRunnable()
545
0
  {
546
0
    AssertIsInMainProcess();
547
0
  }
548
549
  NS_DECL_NSIRUNNABLE
550
};
551
552
class ParentImpl::CreateActorHelper final : public Runnable
553
{
554
  mozilla::Monitor mMonitor;
555
  RefPtr<ParentImpl> mParentActor;
556
  nsCOMPtr<nsIThread> mThread;
557
  nsresult mMainThreadResultCode;
558
  bool mWaiting;
559
560
public:
561
  explicit CreateActorHelper()
562
    : Runnable("Background::ParentImpl::CreateActorHelper")
563
    , mMonitor("CreateActorHelper::mMonitor")
564
    , mMainThreadResultCode(NS_OK)
565
    , mWaiting(true)
566
0
  {
567
0
    AssertIsInMainProcess();
568
0
    AssertIsNotOnMainThread();
569
0
  }
570
571
  nsresult
572
  BlockAndGetResults(RefPtr<ParentImpl>& aParentActor,
573
                     nsCOMPtr<nsIThread>& aThread);
574
575
private:
576
  ~CreateActorHelper()
577
0
  {
578
0
    AssertIsInMainProcess();
579
0
  }
580
581
  nsresult
582
  RunOnMainThread();
583
584
  NS_DECL_NSIRUNNABLE
585
};
586
587
class NS_NO_VTABLE ParentImpl::CreateCallback
588
{
589
public:
590
  NS_INLINE_DECL_REFCOUNTING(CreateCallback)
591
592
  virtual void
593
  Success(already_AddRefed<ParentImpl> aActor, MessageLoop* aMessageLoop) = 0;
594
595
  virtual void
596
  Failure() = 0;
597
598
protected:
599
  virtual ~CreateCallback()
600
0
  { }
601
};
602
603
// -----------------------------------------------------------------------------
604
// ChildImpl Helper Declarations
605
// -----------------------------------------------------------------------------
606
607
class ChildImpl::ShutdownObserver final : public nsIObserver
608
{
609
public:
610
  ShutdownObserver()
611
3
  {
612
3
    AssertIsOnMainThread();
613
3
  }
614
615
  NS_DECL_ISUPPORTS
616
  NS_DECL_NSIOBSERVER
617
618
private:
619
  ~ShutdownObserver()
620
0
  {
621
0
    AssertIsOnMainThread();
622
0
  }
623
};
624
625
} // namespace
626
627
namespace mozilla {
628
namespace ipc {
629
630
bool
631
IsOnBackgroundThread()
632
0
{
633
0
  return ParentImpl::IsOnBackgroundThread();
634
0
}
635
636
#ifdef DEBUG
637
638
void
639
AssertIsOnBackgroundThread()
640
{
641
  ParentImpl::AssertIsOnBackgroundThread();
642
}
643
644
#endif // DEBUG
645
646
} // namespace ipc
647
} // namespace mozilla
648
649
// -----------------------------------------------------------------------------
650
// BackgroundParent Public Methods
651
// -----------------------------------------------------------------------------
652
653
// static
654
bool
655
BackgroundParent::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
656
0
{
657
0
  return ParentImpl::IsOtherProcessActor(aBackgroundActor);
658
0
}
659
660
// static
661
already_AddRefed<ContentParent>
662
BackgroundParent::GetContentParent(PBackgroundParent* aBackgroundActor)
663
0
{
664
0
  return ParentImpl::GetContentParent(aBackgroundActor);
665
0
}
666
667
// static
668
intptr_t
669
BackgroundParent::GetRawContentParentForComparison(
670
                                            PBackgroundParent* aBackgroundActor)
671
0
{
672
0
  return ParentImpl::GetRawContentParentForComparison(aBackgroundActor);
673
0
}
674
675
// static
676
uint64_t
677
BackgroundParent::GetChildID(PBackgroundParent* aBackgroundActor)
678
0
{
679
0
  return ParentImpl::GetChildID(aBackgroundActor);
680
0
}
681
682
// static
683
bool
684
BackgroundParent::GetLiveActorArray(
685
                                  PBackgroundParent* aBackgroundActor,
686
                                  nsTArray<PBackgroundParent*>& aLiveActorArray)
687
0
{
688
0
  return ParentImpl::GetLiveActorArray(aBackgroundActor, aLiveActorArray);
689
0
}
690
691
// static
692
bool
693
BackgroundParent::Alloc(ContentParent* aContent,
694
                        Endpoint<PBackgroundParent>&& aEndpoint)
695
0
{
696
0
  return ParentImpl::Alloc(aContent, std::move(aEndpoint));
697
0
}
698
699
// -----------------------------------------------------------------------------
700
// BackgroundChild Public Methods
701
// -----------------------------------------------------------------------------
702
703
// static
704
void
705
BackgroundChild::Startup()
706
3
{
707
3
  ChildImpl::Startup();
708
3
}
709
710
// static
711
PBackgroundChild*
712
BackgroundChild::GetForCurrentThread()
713
0
{
714
0
  return ChildImpl::GetForCurrentThread();
715
0
}
716
717
// static
718
PBackgroundChild*
719
BackgroundChild::GetOrCreateForCurrentThread()
720
0
{
721
0
  return ChildImpl::GetOrCreateForCurrentThread();
722
0
}
723
724
// static
725
void
726
BackgroundChild::CloseForCurrentThread()
727
0
{
728
0
  ChildImpl::CloseForCurrentThread();
729
0
}
730
731
// -----------------------------------------------------------------------------
732
// BackgroundChildImpl Public Methods
733
// -----------------------------------------------------------------------------
734
735
// static
736
BackgroundChildImpl::ThreadLocal*
737
BackgroundChildImpl::GetThreadLocalForCurrentThread()
738
0
{
739
0
  return ChildImpl::GetThreadLocalForCurrentThread();
740
0
}
741
742
// -----------------------------------------------------------------------------
743
// ParentImpl Static Members
744
// -----------------------------------------------------------------------------
745
746
StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
747
748
nsTArray<ParentImpl*>* ParentImpl::sLiveActorsForBackgroundThread;
749
750
StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
751
752
Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
753
754
MessageLoop* ParentImpl::sBackgroundThreadMessageLoop = nullptr;
755
756
uint64_t ParentImpl::sLiveActorCount = 0;
757
758
bool ParentImpl::sShutdownObserverRegistered = false;
759
760
bool ParentImpl::sShutdownHasStarted = false;
761
762
// -----------------------------------------------------------------------------
763
// ChildImpl Static Members
764
// -----------------------------------------------------------------------------
765
766
unsigned int ChildImpl::sThreadLocalIndex = kBadThreadLocalIndex;
767
768
bool ChildImpl::sShutdownHasStarted = false;
769
770
// -----------------------------------------------------------------------------
771
// ParentImpl Implementation
772
// -----------------------------------------------------------------------------
773
774
// static
775
bool
776
ParentImpl::IsOtherProcessActor(PBackgroundParent* aBackgroundActor)
777
0
{
778
0
  AssertIsOnBackgroundThread();
779
0
  MOZ_ASSERT(aBackgroundActor);
780
0
781
0
  return static_cast<ParentImpl*>(aBackgroundActor)->mIsOtherProcessActor;
782
0
}
783
784
// static
785
already_AddRefed<ContentParent>
786
ParentImpl::GetContentParent(PBackgroundParent* aBackgroundActor)
787
0
{
788
0
  AssertIsOnBackgroundThread();
789
0
  MOZ_ASSERT(aBackgroundActor);
790
0
791
0
  auto actor = static_cast<ParentImpl*>(aBackgroundActor);
792
0
  if (actor->mActorDestroyed) {
793
0
    MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
794
0
    return nullptr;
795
0
  }
796
0
797
0
  if (actor->mContent) {
798
0
    // We need to hand out a reference to our ContentParent but we also need to
799
0
    // keep the one we have. We can't call AddRef here because ContentParent is
800
0
    // not threadsafe so instead we dispatch a runnable to the main thread to do
801
0
    // it for us. This is safe since we are guaranteed that our AddRef runnable
802
0
    // will run before the reference we hand out can be released, and the
803
0
    // ContentParent can't die as long as the existing reference is maintained.
804
0
    MOZ_ALWAYS_SUCCEEDS(
805
0
      NS_DispatchToMainThread(NewNonOwningRunnableMethod("ContentParent::AddRef",
806
0
                                                         actor->mContent, &ContentParent::AddRef)));
807
0
  }
808
0
809
0
  return already_AddRefed<ContentParent>(actor->mContent.get());
810
0
}
811
812
// static
813
intptr_t
814
ParentImpl::GetRawContentParentForComparison(
815
                                            PBackgroundParent* aBackgroundActor)
816
0
{
817
0
  AssertIsOnBackgroundThread();
818
0
  MOZ_ASSERT(aBackgroundActor);
819
0
820
0
  auto actor = static_cast<ParentImpl*>(aBackgroundActor);
821
0
  if (actor->mActorDestroyed) {
822
0
    MOZ_ASSERT(false,
823
0
               "GetRawContentParentForComparison called after ActorDestroy was "
824
0
               "called!");
825
0
    return intptr_t(-1);
826
0
  }
827
0
828
0
  return intptr_t(static_cast<nsIContentParent*>(actor->mContent.get()));
829
0
}
830
831
// static
832
uint64_t
833
ParentImpl::GetChildID(PBackgroundParent* aBackgroundActor)
834
0
{
835
0
  AssertIsOnBackgroundThread();
836
0
  MOZ_ASSERT(aBackgroundActor);
837
0
838
0
  auto actor = static_cast<ParentImpl*>(aBackgroundActor);
839
0
  if (actor->mActorDestroyed) {
840
0
    MOZ_ASSERT(false, "GetContentParent called after ActorDestroy was called!");
841
0
    return 0;
842
0
  }
843
0
844
0
  if (actor->mContent) {
845
0
    return actor->mContent->ChildID();
846
0
  }
847
0
848
0
  return 0;
849
0
}
850
851
// static
852
bool
853
ParentImpl::GetLiveActorArray(PBackgroundParent* aBackgroundActor,
854
                              nsTArray<PBackgroundParent*>& aLiveActorArray)
855
0
{
856
0
  AssertIsOnBackgroundThread();
857
0
  MOZ_ASSERT(aBackgroundActor);
858
0
  MOZ_ASSERT(aLiveActorArray.IsEmpty());
859
0
860
0
  auto actor = static_cast<ParentImpl*>(aBackgroundActor);
861
0
  if (actor->mActorDestroyed) {
862
0
    MOZ_ASSERT(false,
863
0
               "GetLiveActorArray called after ActorDestroy was called!");
864
0
    return false;
865
0
  }
866
0
867
0
  if (!actor->mLiveActorArray) {
868
0
    return true;
869
0
  }
870
0
871
0
  for (ParentImpl* liveActor : *actor->mLiveActorArray) {
872
0
    aLiveActorArray.AppendElement(liveActor);
873
0
  }
874
0
875
0
  return true;
876
0
}
877
878
// static
879
bool
880
ParentImpl::Alloc(ContentParent* aContent,
881
                  Endpoint<PBackgroundParent>&& aEndpoint)
882
0
{
883
0
  AssertIsInMainProcess();
884
0
  AssertIsOnMainThread();
885
0
  MOZ_ASSERT(aEndpoint.IsValid());
886
0
887
0
  if (!sBackgroundThread && !CreateBackgroundThread()) {
888
0
    NS_WARNING("Failed to create background thread!");
889
0
    return false;
890
0
  }
891
0
892
0
  MOZ_ASSERT(sLiveActorsForBackgroundThread);
893
0
894
0
  sLiveActorCount++;
895
0
896
0
  RefPtr<ParentImpl> actor = new ParentImpl(aContent);
897
0
898
0
  nsCOMPtr<nsIRunnable> connectRunnable =
899
0
    new ConnectActorRunnable(actor, std::move(aEndpoint),
900
0
                             sLiveActorsForBackgroundThread);
901
0
902
0
  if (NS_FAILED(sBackgroundThread->Dispatch(connectRunnable,
903
0
                                            NS_DISPATCH_NORMAL))) {
904
0
    NS_WARNING("Failed to dispatch connect runnable!");
905
0
906
0
    MOZ_ASSERT(sLiveActorCount);
907
0
    sLiveActorCount--;
908
0
909
0
    return false;
910
0
  }
911
0
912
0
  return true;
913
0
}
914
915
// static
916
already_AddRefed<ChildImpl>
917
ParentImpl::CreateActorForSameProcess()
918
0
{
919
0
  AssertIsInMainProcess();
920
0
921
0
  RefPtr<ParentImpl> parentActor;
922
0
  nsCOMPtr<nsIThread> backgroundThread;
923
0
924
0
  if (NS_IsMainThread()) {
925
0
    if (!sBackgroundThread && !CreateBackgroundThread()) {
926
0
      NS_WARNING("Failed to create background thread!");
927
0
      return nullptr;
928
0
    }
929
0
930
0
    MOZ_ASSERT(!sShutdownHasStarted);
931
0
932
0
    sLiveActorCount++;
933
0
934
0
    parentActor = new ParentImpl();
935
0
    backgroundThread = sBackgroundThread.get();
936
0
  } else {
937
0
    RefPtr<CreateActorHelper> helper = new CreateActorHelper();
938
0
939
0
    nsresult rv = helper->BlockAndGetResults(parentActor, backgroundThread);
940
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
941
0
      return nullptr;
942
0
    }
943
0
  }
944
0
945
0
  RefPtr<ChildImpl> childActor = new ChildImpl();
946
0
947
0
  MessageChannel* parentChannel = parentActor->GetIPCChannel();
948
0
  MOZ_ASSERT(parentChannel);
949
0
950
0
  if (!childActor->Open(parentChannel, backgroundThread, ChildSide)) {
951
0
    NS_WARNING("Failed to open ChildImpl!");
952
0
953
0
    // Can't release it here, we will release this reference in Destroy.
954
0
    ParentImpl* actor;
955
0
    parentActor.forget(&actor);
956
0
957
0
    actor->Destroy();
958
0
959
0
    return nullptr;
960
0
  }
961
0
962
0
  childActor->SetActorAlive();
963
0
964
0
  // Make sure the parent knows it is same process.
965
0
  parentActor->SetOtherProcessId(base::GetCurrentProcId());
966
0
967
0
  // Now that Open() has succeeded transfer the ownership of the actors to IPDL.
968
0
  Unused << parentActor.forget();
969
0
970
0
  return childActor.forget();
971
0
}
972
973
// static
974
bool
975
ParentImpl::CreateBackgroundThread()
976
0
{
977
0
  AssertIsInMainProcess();
978
0
  AssertIsOnMainThread();
979
0
  MOZ_ASSERT(!sBackgroundThread);
980
0
  MOZ_ASSERT(!sLiveActorsForBackgroundThread);
981
0
982
0
  if (sShutdownHasStarted) {
983
0
    NS_WARNING("Trying to create background thread after shutdown has "
984
0
               "already begun!");
985
0
    return false;
986
0
  }
987
0
988
0
  nsCOMPtr<nsITimer> newShutdownTimer;
989
0
990
0
  if (!sShutdownTimer) {
991
0
    newShutdownTimer = NS_NewTimer();
992
0
    if (!newShutdownTimer) {
993
0
      return false;
994
0
    }
995
0
  }
996
0
997
0
  if (!sShutdownObserverRegistered) {
998
0
    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
999
0
    if (NS_WARN_IF(!obs)) {
1000
0
      return false;
1001
0
    }
1002
0
1003
0
    nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1004
0
1005
0
    nsresult rv =
1006
0
      obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
1007
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
1008
0
      return false;
1009
0
    }
1010
0
1011
0
    sShutdownObserverRegistered = true;
1012
0
  }
1013
0
1014
0
  nsCOMPtr<nsIThread> thread;
1015
0
  if (NS_FAILED(NS_NewNamedThread("IPDL Background", getter_AddRefs(thread)))) {
1016
0
    NS_WARNING("NS_NewNamedThread failed!");
1017
0
    return false;
1018
0
  }
1019
0
1020
0
  nsCOMPtr<nsIRunnable> messageLoopRunnable =
1021
0
    new RequestMessageLoopRunnable(thread);
1022
0
  if (NS_FAILED(thread->Dispatch(messageLoopRunnable, NS_DISPATCH_NORMAL))) {
1023
0
    NS_WARNING("Failed to dispatch RequestMessageLoopRunnable!");
1024
0
    return false;
1025
0
  }
1026
0
1027
0
  sBackgroundThread = thread;
1028
0
  sLiveActorsForBackgroundThread = new nsTArray<ParentImpl*>(1);
1029
0
1030
0
  if (!sShutdownTimer) {
1031
0
    MOZ_ASSERT(newShutdownTimer);
1032
0
    sShutdownTimer = newShutdownTimer;
1033
0
  }
1034
0
1035
0
  return true;
1036
0
}
1037
1038
// static
1039
void
1040
ParentImpl::ShutdownBackgroundThread()
1041
0
{
1042
0
  AssertIsInMainProcess();
1043
0
  AssertIsOnMainThread();
1044
0
  MOZ_ASSERT(sShutdownHasStarted);
1045
0
  MOZ_ASSERT_IF(!sBackgroundThread, !sLiveActorCount);
1046
0
  MOZ_ASSERT_IF(sBackgroundThread, sShutdownTimer);
1047
0
1048
0
  nsCOMPtr<nsITimer> shutdownTimer = sShutdownTimer.get();
1049
0
  sShutdownTimer = nullptr;
1050
0
1051
0
  if (sBackgroundThread) {
1052
0
    nsCOMPtr<nsIThread> thread = sBackgroundThread.get();
1053
0
    sBackgroundThread = nullptr;
1054
0
1055
0
    nsAutoPtr<nsTArray<ParentImpl*>> liveActors(sLiveActorsForBackgroundThread);
1056
0
    sLiveActorsForBackgroundThread = nullptr;
1057
0
1058
0
    MOZ_ASSERT_IF(!sShutdownHasStarted, !sLiveActorCount);
1059
0
1060
0
    if (sLiveActorCount) {
1061
0
      // We need to spin the event loop while we wait for all the actors to be
1062
0
      // cleaned up. We also set a timeout to force-kill any hanging actors.
1063
0
      TimerCallbackClosure closure(thread, liveActors);
1064
0
1065
0
      MOZ_ALWAYS_SUCCEEDS(
1066
0
        shutdownTimer->InitWithNamedFuncCallback(&ShutdownTimerCallback,
1067
0
                                                 &closure,
1068
0
                                                 kShutdownTimerDelayMS,
1069
0
                                                 nsITimer::TYPE_ONE_SHOT,
1070
0
                                                 "ParentImpl::ShutdownTimerCallback"));
1071
0
1072
0
      SpinEventLoopUntil([&]() { return !sLiveActorCount; });
1073
0
1074
0
      MOZ_ASSERT(liveActors->IsEmpty());
1075
0
1076
0
      MOZ_ALWAYS_SUCCEEDS(shutdownTimer->Cancel());
1077
0
    }
1078
0
1079
0
    // Dispatch this runnable to unregister the thread from the profiler.
1080
0
    nsCOMPtr<nsIRunnable> shutdownRunnable =
1081
0
      new ShutdownBackgroundThreadRunnable();
1082
0
    MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(shutdownRunnable, NS_DISPATCH_NORMAL));
1083
0
1084
0
    MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
1085
0
  }
1086
0
}
1087
1088
// static
1089
void
1090
ParentImpl::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure)
1091
0
{
1092
0
  AssertIsInMainProcess();
1093
0
  AssertIsOnMainThread();
1094
0
  MOZ_ASSERT(sShutdownHasStarted);
1095
0
  MOZ_ASSERT(sLiveActorCount);
1096
0
1097
0
  auto closure = static_cast<TimerCallbackClosure*>(aClosure);
1098
0
  MOZ_ASSERT(closure);
1099
0
1100
0
  // Don't let the stack unwind until the ForceCloseBackgroundActorsRunnable has
1101
0
  // finished.
1102
0
  sLiveActorCount++;
1103
0
1104
0
  nsCOMPtr<nsIRunnable> forceCloseRunnable =
1105
0
    new ForceCloseBackgroundActorsRunnable(closure->mLiveActors);
1106
0
  MOZ_ALWAYS_SUCCEEDS(closure->mThread->Dispatch(forceCloseRunnable,
1107
0
                                                 NS_DISPATCH_NORMAL));
1108
0
}
1109
1110
void
1111
ParentImpl::Destroy()
1112
0
{
1113
0
  // May be called on any thread!
1114
0
1115
0
  AssertIsInMainProcess();
1116
0
1117
0
  MOZ_ALWAYS_SUCCEEDS(
1118
0
    NS_DispatchToMainThread(NewNonOwningRunnableMethod("ParentImpl::MainThreadActorDestroy",
1119
0
                                                       this, &ParentImpl::MainThreadActorDestroy)));
1120
0
}
1121
1122
void
1123
ParentImpl::MainThreadActorDestroy()
1124
0
{
1125
0
  AssertIsInMainProcess();
1126
0
  AssertIsOnMainThread();
1127
0
  MOZ_ASSERT_IF(mIsOtherProcessActor, mContent);
1128
0
  MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
1129
0
1130
0
  mContent = nullptr;
1131
0
1132
0
  MOZ_ASSERT(sLiveActorCount);
1133
0
  sLiveActorCount--;
1134
0
1135
0
  // This may be the last reference!
1136
0
  Release();
1137
0
}
1138
1139
void
1140
ParentImpl::ActorDestroy(ActorDestroyReason aWhy)
1141
0
{
1142
0
  AssertIsInMainProcess();
1143
0
  AssertIsOnBackgroundThread();
1144
0
  MOZ_ASSERT(!mActorDestroyed);
1145
0
  MOZ_ASSERT_IF(mIsOtherProcessActor, mLiveActorArray);
1146
0
1147
0
  BackgroundParentImpl::ActorDestroy(aWhy);
1148
0
1149
0
  mActorDestroyed = true;
1150
0
1151
0
  if (mLiveActorArray) {
1152
0
    MOZ_ALWAYS_TRUE(mLiveActorArray->RemoveElement(this));
1153
0
    mLiveActorArray = nullptr;
1154
0
  }
1155
0
1156
0
  // This is tricky. We should be able to call Destroy() here directly because
1157
0
  // we're not going to touch 'this' or our MessageChannel any longer on this
1158
0
  // thread. Destroy() dispatches the MainThreadActorDestroy runnable and when
1159
0
  // it runs it will destroy 'this' and our associated MessageChannel. However,
1160
0
  // IPDL is about to call MessageChannel::Clear() on this thread! To avoid
1161
0
  // racing with the main thread we must ensure that the MessageChannel lives
1162
0
  // long enough to be cleared in this call stack.
1163
0
1164
0
  MOZ_ALWAYS_SUCCEEDS(
1165
0
    NS_DispatchToCurrentThread(NewNonOwningRunnableMethod("ParentImpl::Destroy",
1166
0
                                                          this, &ParentImpl::Destroy)));
1167
0
}
1168
1169
NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver)
1170
1171
NS_IMETHODIMP
1172
ParentImpl::ShutdownObserver::Observe(nsISupports* aSubject,
1173
                                      const char* aTopic,
1174
                                      const char16_t* aData)
1175
0
{
1176
0
  AssertIsInMainProcess();
1177
0
  AssertIsOnMainThread();
1178
0
  MOZ_ASSERT(!sShutdownHasStarted);
1179
0
  MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1180
0
1181
0
  sShutdownHasStarted = true;
1182
0
1183
0
  // Do this first before calling (and spinning the event loop in)
1184
0
  // ShutdownBackgroundThread().
1185
0
  ChildImpl::Shutdown();
1186
0
1187
0
  ShutdownBackgroundThread();
1188
0
1189
0
  return NS_OK;
1190
0
}
1191
1192
NS_IMETHODIMP
1193
ParentImpl::RequestMessageLoopRunnable::Run()
1194
0
{
1195
0
  AssertIsInMainProcess();
1196
0
  MOZ_ASSERT(mTargetThread);
1197
0
1198
0
  if (NS_IsMainThread()) {
1199
0
    MOZ_ASSERT(mMessageLoop);
1200
0
1201
0
    if (!sBackgroundThread ||
1202
0
        !SameCOMIdentity(mTargetThread.get(), sBackgroundThread.get())) {
1203
0
      return NS_OK;
1204
0
    }
1205
0
1206
0
    MOZ_ASSERT(!sBackgroundThreadMessageLoop);
1207
0
    sBackgroundThreadMessageLoop = mMessageLoop;
1208
0
1209
0
    return NS_OK;
1210
0
  }
1211
0
1212
#ifdef DEBUG
1213
  {
1214
    bool correctThread;
1215
    MOZ_ASSERT(NS_SUCCEEDED(mTargetThread->IsOnCurrentThread(&correctThread)));
1216
    MOZ_ASSERT(correctThread);
1217
  }
1218
#endif
1219
1220
0
  DebugOnly<PRThread*> oldBackgroundThread =
1221
0
    sBackgroundPRThread.exchange(PR_GetCurrentThread());
1222
0
1223
0
  MOZ_ASSERT_IF(oldBackgroundThread,
1224
0
                PR_GetCurrentThread() != oldBackgroundThread);
1225
0
1226
0
  MOZ_ASSERT(!mMessageLoop);
1227
0
1228
0
  mMessageLoop = MessageLoop::current();
1229
0
  MOZ_ASSERT(mMessageLoop);
1230
0
1231
0
  if (NS_FAILED(NS_DispatchToMainThread(this))) {
1232
0
    NS_WARNING("Failed to dispatch RequestMessageLoopRunnable to main thread!");
1233
0
    return NS_ERROR_FAILURE;
1234
0
  }
1235
0
1236
0
  return NS_OK;
1237
0
}
1238
1239
NS_IMETHODIMP
1240
ParentImpl::ShutdownBackgroundThreadRunnable::Run()
1241
0
{
1242
0
  AssertIsInMainProcess();
1243
0
1244
0
  // It is possible that another background thread was created while this thread
1245
0
  // was shutting down. In that case we can't assert anything about
1246
0
  // sBackgroundPRThread and we should not modify it here.
1247
0
  sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
1248
0
1249
0
  return NS_OK;
1250
0
}
1251
1252
NS_IMETHODIMP
1253
ParentImpl::ForceCloseBackgroundActorsRunnable::Run()
1254
0
{
1255
0
  AssertIsInMainProcess();
1256
0
  MOZ_ASSERT(mActorArray);
1257
0
1258
0
  if (NS_IsMainThread()) {
1259
0
    MOZ_ASSERT(sLiveActorCount);
1260
0
    sLiveActorCount--;
1261
0
    return NS_OK;
1262
0
  }
1263
0
1264
0
  AssertIsOnBackgroundThread();
1265
0
1266
0
  if (!mActorArray->IsEmpty()) {
1267
0
    // Copy the array since calling Close() could mutate the actual array.
1268
0
    nsTArray<ParentImpl*> actorsToClose(*mActorArray);
1269
0
1270
0
    for (uint32_t index = 0; index < actorsToClose.Length(); index++) {
1271
0
      actorsToClose[index]->Close();
1272
0
    }
1273
0
  }
1274
0
1275
0
  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1276
0
1277
0
  return NS_OK;
1278
0
}
1279
1280
NS_IMETHODIMP
1281
ParentImpl::ConnectActorRunnable::Run()
1282
0
{
1283
0
  AssertIsInMainProcess();
1284
0
  AssertIsOnBackgroundThread();
1285
0
1286
0
  // Transfer ownership to this thread. If Open() fails then we will release
1287
0
  // this reference in Destroy.
1288
0
  ParentImpl* actor;
1289
0
  mActor.forget(&actor);
1290
0
1291
0
  Endpoint<PBackgroundParent> endpoint = std::move(mEndpoint);
1292
0
1293
0
  if (!endpoint.Bind(actor)) {
1294
0
    actor->Destroy();
1295
0
    return NS_ERROR_FAILURE;
1296
0
  }
1297
0
1298
0
  actor->SetLiveActorArray(mLiveActorArray);
1299
0
1300
0
  return NS_OK;
1301
0
}
1302
1303
nsresult
1304
ParentImpl::
1305
CreateActorHelper::BlockAndGetResults(RefPtr<ParentImpl>& aParentActor,
1306
                                      nsCOMPtr<nsIThread>& aThread)
1307
0
{
1308
0
  MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1309
0
1310
0
  mozilla::MonitorAutoLock lock(mMonitor);
1311
0
  while (mWaiting) {
1312
0
    lock.Wait();
1313
0
  }
1314
0
1315
0
  if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode))) {
1316
0
    return mMainThreadResultCode;
1317
0
  }
1318
0
1319
0
  aParentActor = std::move(mParentActor);
1320
0
  aThread = std::move(mThread);
1321
0
  return NS_OK;
1322
0
}
1323
1324
nsresult
1325
ParentImpl::
1326
CreateActorHelper::RunOnMainThread()
1327
0
{
1328
0
  AssertIsOnMainThread();
1329
0
1330
0
  if (!sBackgroundThread && !CreateBackgroundThread()) {
1331
0
    NS_WARNING("Failed to create background thread!");
1332
0
    return NS_ERROR_FAILURE;
1333
0
  }
1334
0
1335
0
  MOZ_ASSERT(!sShutdownHasStarted);
1336
0
1337
0
  sLiveActorCount++;
1338
0
1339
0
  mParentActor = new ParentImpl();
1340
0
  mThread = sBackgroundThread;
1341
0
1342
0
  return NS_OK;
1343
0
}
1344
1345
NS_IMETHODIMP
1346
ParentImpl::
1347
CreateActorHelper::Run()
1348
0
{
1349
0
  AssertIsOnMainThread();
1350
0
1351
0
  nsresult rv = RunOnMainThread();
1352
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
1353
0
    mMainThreadResultCode = rv;
1354
0
  }
1355
0
1356
0
  mozilla::MonitorAutoLock lock(mMonitor);
1357
0
  MOZ_ASSERT(mWaiting);
1358
0
1359
0
  mWaiting = false;
1360
0
  lock.Notify();
1361
0
1362
0
  return NS_OK;
1363
0
}
1364
1365
// -----------------------------------------------------------------------------
1366
// ChildImpl Implementation
1367
// -----------------------------------------------------------------------------
1368
1369
// static
1370
void
1371
ChildImpl::Startup()
1372
3
{
1373
3
  // This happens on the main thread but before XPCOM has started so we can't
1374
3
  // assert that we're being called on the main thread here.
1375
3
1376
3
  MOZ_ASSERT(sThreadLocalIndex == kBadThreadLocalIndex,
1377
3
             "BackgroundChild::Startup() called more than once!");
1378
3
1379
3
  PRStatus status =
1380
3
    PR_NewThreadPrivateIndex(&sThreadLocalIndex, ThreadLocalDestructor);
1381
3
  MOZ_RELEASE_ASSERT(status == PR_SUCCESS, "PR_NewThreadPrivateIndex failed!");
1382
3
1383
3
  MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1384
3
1385
3
  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
1386
3
  MOZ_RELEASE_ASSERT(observerService);
1387
3
1388
3
  nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
1389
3
1390
3
  nsresult rv =
1391
3
    observerService->AddObserver(observer,
1392
3
                                 NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
1393
3
                                 false);
1394
3
  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
1395
3
}
1396
1397
// static
1398
void
1399
ChildImpl::Shutdown()
1400
0
{
1401
0
  AssertIsOnMainThread();
1402
0
1403
0
  if (sShutdownHasStarted) {
1404
0
    MOZ_ASSERT_IF(sThreadLocalIndex != kBadThreadLocalIndex,
1405
0
                  !PR_GetThreadPrivate(sThreadLocalIndex));
1406
0
    return;
1407
0
  }
1408
0
1409
0
  sShutdownHasStarted = true;
1410
0
1411
0
  MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1412
0
1413
0
  ThreadLocalInfo* threadLocalInfo;
1414
#ifdef DEBUG
1415
  threadLocalInfo = static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1416
  MOZ_ASSERT(!threadLocalInfo);
1417
#endif
1418
  threadLocalInfo = sMainThreadInfo;
1419
0
1420
0
  if (threadLocalInfo) {
1421
#ifdef DEBUG
1422
    MOZ_ASSERT(!threadLocalInfo->mClosed);
1423
    threadLocalInfo->mClosed = true;
1424
#endif
1425
1426
0
    ThreadLocalDestructor(threadLocalInfo);
1427
0
    sMainThreadInfo = nullptr;
1428
0
  }
1429
0
}
1430
1431
ChildImpl::ThreadLocalInfo* ChildImpl::sMainThreadInfo = nullptr;
1432
1433
// static
1434
PBackgroundChild*
1435
ChildImpl::GetForCurrentThread()
1436
0
{
1437
0
  MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
1438
0
1439
0
  auto threadLocalInfo =
1440
0
    NS_IsMainThread() ? sMainThreadInfo :
1441
0
    static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1442
0
1443
0
  if (!threadLocalInfo) {
1444
0
    return nullptr;
1445
0
  }
1446
0
1447
0
  return threadLocalInfo->mActor;
1448
0
}
1449
1450
/* static */
1451
PBackgroundChild*
1452
ChildImpl::GetOrCreateForCurrentThread()
1453
0
{
1454
0
  MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
1455
0
             "BackgroundChild::Startup() was never called!");
1456
0
1457
0
  if (NS_IsMainThread() && sShutdownHasStarted) {
1458
0
    return nullptr;
1459
0
  }
1460
0
1461
0
  auto threadLocalInfo = NS_IsMainThread() ? sMainThreadInfo :
1462
0
    static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1463
0
1464
0
  if (!threadLocalInfo) {
1465
0
    nsAutoPtr<ThreadLocalInfo> newInfo(new ThreadLocalInfo());
1466
0
1467
0
    if (NS_IsMainThread()) {
1468
0
      sMainThreadInfo = newInfo;
1469
0
    } else {
1470
0
      if (PR_SetThreadPrivate(sThreadLocalIndex, newInfo) != PR_SUCCESS) {
1471
0
        CRASH_IN_CHILD_PROCESS("PR_SetThreadPrivate failed!");
1472
0
        return nullptr;
1473
0
      }
1474
0
    }
1475
0
1476
0
    threadLocalInfo = newInfo.forget();
1477
0
  }
1478
0
1479
0
  if (threadLocalInfo->mActor) {
1480
0
    return threadLocalInfo->mActor;
1481
0
  }
1482
0
1483
0
  if (XRE_IsParentProcess()) {
1484
0
    RefPtr<ChildImpl> strongActor = ParentImpl::CreateActorForSameProcess();
1485
0
    if (NS_WARN_IF(!strongActor)) {
1486
0
      return nullptr;
1487
0
    }
1488
0
1489
0
    RefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
1490
0
    strongActor.swap(actor);
1491
0
1492
0
    return actor;
1493
0
  }
1494
0
1495
0
  RefPtr<ContentChild> content = ContentChild::GetSingleton();
1496
0
  MOZ_ASSERT(content);
1497
0
1498
0
  if (content->IsShuttingDown()) {
1499
0
    // The transport for ContentChild is shut down and can't be used to open
1500
0
    // PBackground.
1501
0
    return nullptr;
1502
0
  }
1503
0
1504
0
  Endpoint<PBackgroundParent> parent;
1505
0
  Endpoint<PBackgroundChild> child;
1506
0
  nsresult rv;
1507
0
  rv = PBackground::CreateEndpoints(content->OtherPid(),
1508
0
                                    base::GetCurrentProcId(),
1509
0
                                    &parent, &child);
1510
0
  if (NS_FAILED(rv)) {
1511
0
    NS_WARNING("Failed to create top level actor!");
1512
0
    return nullptr;
1513
0
  }
1514
0
1515
0
  RefPtr<ChildImpl> strongActor = new ChildImpl();
1516
0
1517
0
  if (!child.Bind(strongActor)) {
1518
0
    CRASH_IN_CHILD_PROCESS("Failed to bind ChildImpl!");
1519
0
1520
0
    return nullptr;
1521
0
  }
1522
0
1523
0
  strongActor->SetActorAlive();
1524
0
1525
0
  if (NS_IsMainThread()) {
1526
0
    if (!content->SendInitBackground(std::move(parent))) {
1527
0
      NS_WARNING("Failed to create top level actor!");
1528
0
      return nullptr;
1529
0
    }
1530
0
  } else {
1531
0
    nsCOMPtr<nsIRunnable> runnable =
1532
0
      NewRunnableMethod<Endpoint<PBackgroundParent>&&>(
1533
0
        "dom::ContentChild::SendInitBackground",
1534
0
        content,
1535
0
        &ContentChild::SendInitBackground,
1536
0
        std::move(parent));
1537
0
    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
1538
0
  }
1539
0
1540
0
  RefPtr<ChildImpl>& actor = threadLocalInfo->mActor;
1541
0
  strongActor.swap(actor);
1542
0
1543
0
  return actor;
1544
0
}
1545
1546
// static
1547
void
1548
ChildImpl::CloseForCurrentThread()
1549
0
{
1550
0
  MOZ_ASSERT(!NS_IsMainThread(),
1551
0
             "PBackground for the main thread should be shut down via ChildImpl::Shutdown().");
1552
0
1553
0
  if (sThreadLocalIndex == kBadThreadLocalIndex) {
1554
0
    return;
1555
0
  }
1556
0
1557
0
  auto threadLocalInfo =
1558
0
    static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1559
0
1560
0
  if (!threadLocalInfo) {
1561
0
    return;
1562
0
  }
1563
0
1564
#ifdef DEBUG
1565
  MOZ_ASSERT(!threadLocalInfo->mClosed);
1566
  threadLocalInfo->mClosed = true;
1567
#endif
1568
1569
0
  // Clearing the thread local will synchronously close the actor.
1570
0
  DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
1571
0
  MOZ_ASSERT(status == PR_SUCCESS);
1572
0
}
1573
1574
// static
1575
BackgroundChildImpl::ThreadLocal*
1576
ChildImpl::GetThreadLocalForCurrentThread()
1577
0
{
1578
0
  MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
1579
0
             "BackgroundChild::Startup() was never called!");
1580
0
1581
0
  auto threadLocalInfo = NS_IsMainThread() ? sMainThreadInfo :
1582
0
    static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
1583
0
1584
0
  if (!threadLocalInfo) {
1585
0
    return nullptr;
1586
0
  }
1587
0
1588
0
  if (!threadLocalInfo->mConsumerThreadLocal) {
1589
0
    threadLocalInfo->mConsumerThreadLocal =
1590
0
      new BackgroundChildImpl::ThreadLocal();
1591
0
  }
1592
0
1593
0
  return threadLocalInfo->mConsumerThreadLocal;
1594
0
}
1595
1596
void
1597
ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
1598
0
{
1599
0
  AssertIsOnOwningThread();
1600
0
1601
#ifdef DEBUG
1602
  MOZ_ASSERT(!mActorDestroyed);
1603
  mActorDestroyed = true;
1604
#endif
1605
1606
0
  BackgroundChildImpl::ActorDestroy(aWhy);
1607
0
}
1608
1609
NS_IMPL_ISUPPORTS(ChildImpl::ShutdownObserver, nsIObserver)
1610
1611
NS_IMETHODIMP
1612
ChildImpl::ShutdownObserver::Observe(nsISupports* aSubject,
1613
                                     const char* aTopic,
1614
                                     const char16_t* aData)
1615
0
{
1616
0
  AssertIsOnMainThread();
1617
0
  MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
1618
0
1619
0
  ChildImpl::Shutdown();
1620
0
1621
0
  return NS_OK;
1622
0
}