ipc/glue/BackgroundImpl.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial