xpcom/threads/LazyIdleThread.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "LazyIdleThread.h"
michael@0 8
michael@0 9 #include "nsIObserverService.h"
michael@0 10
michael@0 11 #include "GeckoProfiler.h"
michael@0 12 #include "nsComponentManagerUtils.h"
michael@0 13 #include "nsServiceManagerUtils.h"
michael@0 14 #include "nsThreadUtils.h"
michael@0 15 #include "mozilla/Services.h"
michael@0 16
michael@0 17 #ifdef DEBUG
michael@0 18 #define ASSERT_OWNING_THREAD() \
michael@0 19 PR_BEGIN_MACRO \
michael@0 20 nsIThread* currentThread = NS_GetCurrentThread(); \
michael@0 21 if (currentThread) { \
michael@0 22 nsCOMPtr<nsISupports> current(do_QueryInterface(currentThread)); \
michael@0 23 nsCOMPtr<nsISupports> test(do_QueryInterface(mOwningThread)); \
michael@0 24 MOZ_ASSERT(current == test, "Wrong thread!"); \
michael@0 25 } \
michael@0 26 PR_END_MACRO
michael@0 27 #else
michael@0 28 #define ASSERT_OWNING_THREAD() /* nothing */
michael@0 29 #endif
michael@0 30
michael@0 31 namespace mozilla {
michael@0 32
michael@0 33 LazyIdleThread::LazyIdleThread(uint32_t aIdleTimeoutMS,
michael@0 34 const nsCSubstring& aName,
michael@0 35 ShutdownMethod aShutdownMethod,
michael@0 36 nsIObserver* aIdleObserver)
michael@0 37 : mMutex("LazyIdleThread::mMutex"),
michael@0 38 mOwningThread(NS_GetCurrentThread()),
michael@0 39 mIdleObserver(aIdleObserver),
michael@0 40 mQueuedRunnables(nullptr),
michael@0 41 mIdleTimeoutMS(aIdleTimeoutMS),
michael@0 42 mPendingEventCount(0),
michael@0 43 mIdleNotificationCount(0),
michael@0 44 mShutdownMethod(aShutdownMethod),
michael@0 45 mShutdown(false),
michael@0 46 mThreadIsShuttingDown(false),
michael@0 47 mIdleTimeoutEnabled(true),
michael@0 48 mName(aName)
michael@0 49 {
michael@0 50 MOZ_ASSERT(mOwningThread, "Need owning thread!");
michael@0 51 }
michael@0 52
michael@0 53 LazyIdleThread::~LazyIdleThread()
michael@0 54 {
michael@0 55 ASSERT_OWNING_THREAD();
michael@0 56
michael@0 57 Shutdown();
michael@0 58 }
michael@0 59
michael@0 60 void
michael@0 61 LazyIdleThread::SetWeakIdleObserver(nsIObserver* aObserver)
michael@0 62 {
michael@0 63 ASSERT_OWNING_THREAD();
michael@0 64
michael@0 65 if (mShutdown) {
michael@0 66 NS_WARN_IF_FALSE(!aObserver,
michael@0 67 "Setting an observer after Shutdown was called!");
michael@0 68 return;
michael@0 69 }
michael@0 70
michael@0 71 mIdleObserver = aObserver;
michael@0 72 }
michael@0 73
michael@0 74 void
michael@0 75 LazyIdleThread::DisableIdleTimeout()
michael@0 76 {
michael@0 77 ASSERT_OWNING_THREAD();
michael@0 78 if (!mIdleTimeoutEnabled) {
michael@0 79 return;
michael@0 80 }
michael@0 81 mIdleTimeoutEnabled = false;
michael@0 82
michael@0 83 if (mIdleTimer && NS_FAILED(mIdleTimer->Cancel())) {
michael@0 84 NS_WARNING("Failed to cancel timer!");
michael@0 85 }
michael@0 86
michael@0 87 MutexAutoLock lock(mMutex);
michael@0 88
michael@0 89 // Pretend we have a pending event to keep the idle timer from firing.
michael@0 90 MOZ_ASSERT(mPendingEventCount < UINT32_MAX, "Way too many!");
michael@0 91 mPendingEventCount++;
michael@0 92 }
michael@0 93
michael@0 94 void
michael@0 95 LazyIdleThread::EnableIdleTimeout()
michael@0 96 {
michael@0 97 ASSERT_OWNING_THREAD();
michael@0 98 if (mIdleTimeoutEnabled) {
michael@0 99 return;
michael@0 100 }
michael@0 101 mIdleTimeoutEnabled = true;
michael@0 102
michael@0 103 {
michael@0 104 MutexAutoLock lock(mMutex);
michael@0 105
michael@0 106 MOZ_ASSERT(mPendingEventCount, "Mismatched calls to observer methods!");
michael@0 107 --mPendingEventCount;
michael@0 108 }
michael@0 109
michael@0 110 if (mThread) {
michael@0 111 nsCOMPtr<nsIRunnable> runnable(new nsRunnable());
michael@0 112 if (NS_FAILED(Dispatch(runnable, NS_DISPATCH_NORMAL))) {
michael@0 113 NS_WARNING("Failed to dispatch!");
michael@0 114 }
michael@0 115 }
michael@0 116 }
michael@0 117
michael@0 118 void
michael@0 119 LazyIdleThread::PreDispatch()
michael@0 120 {
michael@0 121 MutexAutoLock lock(mMutex);
michael@0 122
michael@0 123 MOZ_ASSERT(mPendingEventCount < UINT32_MAX, "Way too many!");
michael@0 124 mPendingEventCount++;
michael@0 125 }
michael@0 126
michael@0 127 nsresult
michael@0 128 LazyIdleThread::EnsureThread()
michael@0 129 {
michael@0 130 ASSERT_OWNING_THREAD();
michael@0 131
michael@0 132 if (mShutdown) {
michael@0 133 return NS_ERROR_UNEXPECTED;
michael@0 134 }
michael@0 135
michael@0 136 if (mThread) {
michael@0 137 return NS_OK;
michael@0 138 }
michael@0 139
michael@0 140 MOZ_ASSERT(!mPendingEventCount, "Shouldn't have events yet!");
michael@0 141 MOZ_ASSERT(!mIdleNotificationCount, "Shouldn't have idle events yet!");
michael@0 142 MOZ_ASSERT(!mIdleTimer, "Should have killed this long ago!");
michael@0 143 MOZ_ASSERT(!mThreadIsShuttingDown, "Should have cleared that!");
michael@0 144
michael@0 145 nsresult rv;
michael@0 146
michael@0 147 if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) {
michael@0 148 nsCOMPtr<nsIObserverService> obs =
michael@0 149 do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
michael@0 150 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 151 return rv;
michael@0 152
michael@0 153 rv = obs->AddObserver(this, "xpcom-shutdown-threads", false);
michael@0 154 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 155 return rv;
michael@0 156 }
michael@0 157
michael@0 158 mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
michael@0 159 if (NS_WARN_IF(!mIdleTimer))
michael@0 160 return NS_ERROR_UNEXPECTED;
michael@0 161
michael@0 162 nsCOMPtr<nsIRunnable> runnable =
michael@0 163 NS_NewRunnableMethod(this, &LazyIdleThread::InitThread);
michael@0 164 if (NS_WARN_IF(!runnable))
michael@0 165 return NS_ERROR_UNEXPECTED;
michael@0 166
michael@0 167 rv = NS_NewThread(getter_AddRefs(mThread), runnable);
michael@0 168 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 169 return rv;
michael@0 170
michael@0 171 return NS_OK;
michael@0 172 }
michael@0 173
michael@0 174 void
michael@0 175 LazyIdleThread::InitThread()
michael@0 176 {
michael@0 177 char aLocal;
michael@0 178 profiler_register_thread(mName.get(), &aLocal);
michael@0 179
michael@0 180 PR_SetCurrentThreadName(mName.get());
michael@0 181
michael@0 182 // Happens on mThread but mThread may not be set yet...
michael@0 183
michael@0 184 nsCOMPtr<nsIThreadInternal> thread(do_QueryInterface(NS_GetCurrentThread()));
michael@0 185 MOZ_ASSERT(thread, "This should always succeed!");
michael@0 186
michael@0 187 if (NS_FAILED(thread->SetObserver(this))) {
michael@0 188 NS_WARNING("Failed to set thread observer!");
michael@0 189 }
michael@0 190 }
michael@0 191
michael@0 192 void
michael@0 193 LazyIdleThread::CleanupThread()
michael@0 194 {
michael@0 195 nsCOMPtr<nsIThreadInternal> thread(do_QueryInterface(NS_GetCurrentThread()));
michael@0 196 MOZ_ASSERT(thread, "This should always succeed!");
michael@0 197
michael@0 198 if (NS_FAILED(thread->SetObserver(nullptr))) {
michael@0 199 NS_WARNING("Failed to set thread observer!");
michael@0 200 }
michael@0 201
michael@0 202 {
michael@0 203 MutexAutoLock lock(mMutex);
michael@0 204
michael@0 205 MOZ_ASSERT(!mThreadIsShuttingDown, "Shouldn't be true ever!");
michael@0 206 mThreadIsShuttingDown = true;
michael@0 207 }
michael@0 208
michael@0 209 profiler_unregister_thread();
michael@0 210 }
michael@0 211
michael@0 212 void
michael@0 213 LazyIdleThread::ScheduleTimer()
michael@0 214 {
michael@0 215 ASSERT_OWNING_THREAD();
michael@0 216
michael@0 217 bool shouldSchedule;
michael@0 218 {
michael@0 219 MutexAutoLock lock(mMutex);
michael@0 220
michael@0 221 MOZ_ASSERT(mIdleNotificationCount, "Should have at least one!");
michael@0 222 --mIdleNotificationCount;
michael@0 223
michael@0 224 shouldSchedule = !mIdleNotificationCount && !mPendingEventCount;
michael@0 225 }
michael@0 226
michael@0 227 if (NS_FAILED(mIdleTimer->Cancel())) {
michael@0 228 NS_WARNING("Failed to cancel timer!");
michael@0 229 }
michael@0 230
michael@0 231 if (shouldSchedule &&
michael@0 232 NS_FAILED(mIdleTimer->InitWithCallback(this, mIdleTimeoutMS,
michael@0 233 nsITimer::TYPE_ONE_SHOT))) {
michael@0 234 NS_WARNING("Failed to schedule timer!");
michael@0 235 }
michael@0 236 }
michael@0 237
michael@0 238 nsresult
michael@0 239 LazyIdleThread::ShutdownThread()
michael@0 240 {
michael@0 241 ASSERT_OWNING_THREAD();
michael@0 242
michael@0 243 // Before calling Shutdown() on the real thread we need to put a queue in
michael@0 244 // place in case a runnable is posted to the thread while it's in the
michael@0 245 // process of shutting down. This will be our queue.
michael@0 246 nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queuedRunnables;
michael@0 247
michael@0 248 nsresult rv;
michael@0 249
michael@0 250 if (mThread) {
michael@0 251 if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) {
michael@0 252 nsCOMPtr<nsIObserverService> obs =
michael@0 253 mozilla::services::GetObserverService();
michael@0 254 NS_WARN_IF_FALSE(obs, "Failed to get observer service!");
michael@0 255
michael@0 256 if (obs &&
michael@0 257 NS_FAILED(obs->RemoveObserver(this, "xpcom-shutdown-threads"))) {
michael@0 258 NS_WARNING("Failed to remove observer!");
michael@0 259 }
michael@0 260 }
michael@0 261
michael@0 262 if (mIdleObserver) {
michael@0 263 mIdleObserver->Observe(static_cast<nsIThread*>(this), IDLE_THREAD_TOPIC,
michael@0 264 nullptr);
michael@0 265 }
michael@0 266
michael@0 267 #ifdef DEBUG
michael@0 268 {
michael@0 269 MutexAutoLock lock(mMutex);
michael@0 270 MOZ_ASSERT(!mThreadIsShuttingDown, "Huh?!");
michael@0 271 }
michael@0 272 #endif
michael@0 273
michael@0 274 nsCOMPtr<nsIRunnable> runnable =
michael@0 275 NS_NewRunnableMethod(this, &LazyIdleThread::CleanupThread);
michael@0 276 if (NS_WARN_IF(!runnable))
michael@0 277 return NS_ERROR_UNEXPECTED;
michael@0 278
michael@0 279 PreDispatch();
michael@0 280
michael@0 281 rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
michael@0 282 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 283 return rv;
michael@0 284
michael@0 285 // Put the temporary queue in place before calling Shutdown().
michael@0 286 mQueuedRunnables = &queuedRunnables;
michael@0 287
michael@0 288 if (NS_FAILED(mThread->Shutdown())) {
michael@0 289 NS_ERROR("Failed to shutdown the thread!");
michael@0 290 }
michael@0 291
michael@0 292 // Now unset the queue.
michael@0 293 mQueuedRunnables = nullptr;
michael@0 294
michael@0 295 mThread = nullptr;
michael@0 296
michael@0 297 {
michael@0 298 MutexAutoLock lock(mMutex);
michael@0 299
michael@0 300 MOZ_ASSERT(!mPendingEventCount, "Huh?!");
michael@0 301 MOZ_ASSERT(!mIdleNotificationCount, "Huh?!");
michael@0 302 MOZ_ASSERT(mThreadIsShuttingDown, "Huh?!");
michael@0 303 mThreadIsShuttingDown = false;
michael@0 304 }
michael@0 305 }
michael@0 306
michael@0 307 if (mIdleTimer) {
michael@0 308 rv = mIdleTimer->Cancel();
michael@0 309 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 310 return rv;
michael@0 311
michael@0 312 mIdleTimer = nullptr;
michael@0 313 }
michael@0 314
michael@0 315 // If our temporary queue has any runnables then we need to dispatch them.
michael@0 316 if (queuedRunnables.Length()) {
michael@0 317 // If the thread manager has gone away then these runnables will never run.
michael@0 318 if (mShutdown) {
michael@0 319 NS_ERROR("Runnables dispatched to LazyIdleThread will never run!");
michael@0 320 return NS_OK;
michael@0 321 }
michael@0 322
michael@0 323 // Re-dispatch the queued runnables.
michael@0 324 for (uint32_t index = 0; index < queuedRunnables.Length(); index++) {
michael@0 325 nsCOMPtr<nsIRunnable> runnable;
michael@0 326 runnable.swap(queuedRunnables[index]);
michael@0 327 MOZ_ASSERT(runnable, "Null runnable?!");
michael@0 328
michael@0 329 if (NS_FAILED(Dispatch(runnable, NS_DISPATCH_NORMAL))) {
michael@0 330 NS_ERROR("Failed to re-dispatch queued runnable!");
michael@0 331 }
michael@0 332 }
michael@0 333 }
michael@0 334
michael@0 335 return NS_OK;
michael@0 336 }
michael@0 337
michael@0 338 void
michael@0 339 LazyIdleThread::SelfDestruct()
michael@0 340 {
michael@0 341 MOZ_ASSERT(mRefCnt == 1, "Bad refcount!");
michael@0 342 delete this;
michael@0 343 }
michael@0 344
michael@0 345 NS_IMPL_ADDREF(LazyIdleThread)
michael@0 346
michael@0 347 NS_IMETHODIMP_(MozExternalRefCountType)
michael@0 348 LazyIdleThread::Release()
michael@0 349 {
michael@0 350 nsrefcnt count = --mRefCnt;
michael@0 351 NS_LOG_RELEASE(this, count, "LazyIdleThread");
michael@0 352
michael@0 353 if (!count) {
michael@0 354 // Stabilize refcount.
michael@0 355 mRefCnt = 1;
michael@0 356
michael@0 357 nsCOMPtr<nsIRunnable> runnable =
michael@0 358 NS_NewNonOwningRunnableMethod(this, &LazyIdleThread::SelfDestruct);
michael@0 359 NS_WARN_IF_FALSE(runnable, "Couldn't make runnable!");
michael@0 360
michael@0 361 if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
michael@0 362 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
michael@0 363 // The only way this could fail is if we're in shutdown, and in that case
michael@0 364 // threads should have been joined already. Deleting here isn't dangerous
michael@0 365 // anymore because we won't spin the event loop waiting to join the
michael@0 366 // thread.
michael@0 367 SelfDestruct();
michael@0 368 }
michael@0 369 }
michael@0 370
michael@0 371 return count;
michael@0 372 }
michael@0 373
michael@0 374 NS_IMPL_QUERY_INTERFACE(LazyIdleThread, nsIThread,
michael@0 375 nsIEventTarget,
michael@0 376 nsITimerCallback,
michael@0 377 nsIThreadObserver,
michael@0 378 nsIObserver)
michael@0 379
michael@0 380 NS_IMETHODIMP
michael@0 381 LazyIdleThread::Dispatch(nsIRunnable* aEvent,
michael@0 382 uint32_t aFlags)
michael@0 383 {
michael@0 384 ASSERT_OWNING_THREAD();
michael@0 385
michael@0 386 // LazyIdleThread can't always support synchronous dispatch currently.
michael@0 387 if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL))
michael@0 388 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 389
michael@0 390 // If our thread is shutting down then we can't actually dispatch right now.
michael@0 391 // Queue this runnable for later.
michael@0 392 if (UseRunnableQueue()) {
michael@0 393 mQueuedRunnables->AppendElement(aEvent);
michael@0 394 return NS_OK;
michael@0 395 }
michael@0 396
michael@0 397 nsresult rv = EnsureThread();
michael@0 398 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 399 return rv;
michael@0 400
michael@0 401 PreDispatch();
michael@0 402
michael@0 403 return mThread->Dispatch(aEvent, aFlags);
michael@0 404 }
michael@0 405
michael@0 406 NS_IMETHODIMP
michael@0 407 LazyIdleThread::IsOnCurrentThread(bool* aIsOnCurrentThread)
michael@0 408 {
michael@0 409 if (mThread) {
michael@0 410 return mThread->IsOnCurrentThread(aIsOnCurrentThread);
michael@0 411 }
michael@0 412
michael@0 413 *aIsOnCurrentThread = false;
michael@0 414 return NS_OK;
michael@0 415 }
michael@0 416
michael@0 417 NS_IMETHODIMP
michael@0 418 LazyIdleThread::GetPRThread(PRThread** aPRThread)
michael@0 419 {
michael@0 420 if (mThread) {
michael@0 421 return mThread->GetPRThread(aPRThread);
michael@0 422 }
michael@0 423
michael@0 424 *aPRThread = nullptr;
michael@0 425 return NS_ERROR_NOT_AVAILABLE;
michael@0 426 }
michael@0 427
michael@0 428 NS_IMETHODIMP
michael@0 429 LazyIdleThread::Shutdown()
michael@0 430 {
michael@0 431 ASSERT_OWNING_THREAD();
michael@0 432
michael@0 433 mShutdown = true;
michael@0 434
michael@0 435 nsresult rv = ShutdownThread();
michael@0 436 MOZ_ASSERT(!mThread, "Should have destroyed this by now!");
michael@0 437
michael@0 438 mIdleObserver = nullptr;
michael@0 439
michael@0 440 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 441 return rv;
michael@0 442
michael@0 443 return NS_OK;
michael@0 444 }
michael@0 445
michael@0 446 NS_IMETHODIMP
michael@0 447 LazyIdleThread::HasPendingEvents(bool* aHasPendingEvents)
michael@0 448 {
michael@0 449 // This is only supposed to be called from the thread itself so it's not
michael@0 450 // implemented here.
michael@0 451 NS_NOTREACHED("Shouldn't ever call this!");
michael@0 452 return NS_ERROR_UNEXPECTED;
michael@0 453 }
michael@0 454
michael@0 455 NS_IMETHODIMP
michael@0 456 LazyIdleThread::ProcessNextEvent(bool aMayWait,
michael@0 457 bool* aEventWasProcessed)
michael@0 458 {
michael@0 459 // This is only supposed to be called from the thread itself so it's not
michael@0 460 // implemented here.
michael@0 461 NS_NOTREACHED("Shouldn't ever call this!");
michael@0 462 return NS_ERROR_UNEXPECTED;
michael@0 463 }
michael@0 464
michael@0 465 NS_IMETHODIMP
michael@0 466 LazyIdleThread::Notify(nsITimer* aTimer)
michael@0 467 {
michael@0 468 ASSERT_OWNING_THREAD();
michael@0 469
michael@0 470 {
michael@0 471 MutexAutoLock lock(mMutex);
michael@0 472
michael@0 473 if (mPendingEventCount || mIdleNotificationCount) {
michael@0 474 // Another event was scheduled since this timer was set. Don't do
michael@0 475 // anything and wait for the timer to fire again.
michael@0 476 return NS_OK;
michael@0 477 }
michael@0 478 }
michael@0 479
michael@0 480 nsresult rv = ShutdownThread();
michael@0 481 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 482 return rv;
michael@0 483
michael@0 484 return NS_OK;
michael@0 485 }
michael@0 486
michael@0 487 NS_IMETHODIMP
michael@0 488 LazyIdleThread::OnDispatchedEvent(nsIThreadInternal* /*aThread */)
michael@0 489 {
michael@0 490 MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread, "Wrong thread!");
michael@0 491 return NS_OK;
michael@0 492 }
michael@0 493
michael@0 494 NS_IMETHODIMP
michael@0 495 LazyIdleThread::OnProcessNextEvent(nsIThreadInternal* /* aThread */,
michael@0 496 bool /* aMayWait */,
michael@0 497 uint32_t /* aRecursionDepth */)
michael@0 498 {
michael@0 499 return NS_OK;
michael@0 500 }
michael@0 501
michael@0 502 NS_IMETHODIMP
michael@0 503 LazyIdleThread::AfterProcessNextEvent(nsIThreadInternal* /* aThread */,
michael@0 504 uint32_t /* aRecursionDepth */,
michael@0 505 bool aEventWasProcessed)
michael@0 506 {
michael@0 507 bool shouldNotifyIdle;
michael@0 508 {
michael@0 509 MutexAutoLock lock(mMutex);
michael@0 510
michael@0 511 if (aEventWasProcessed) {
michael@0 512 MOZ_ASSERT(mPendingEventCount, "Mismatched calls to observer methods!");
michael@0 513 --mPendingEventCount;
michael@0 514 }
michael@0 515
michael@0 516 if (mThreadIsShuttingDown) {
michael@0 517 // We're shutting down, no need to fire any timer.
michael@0 518 return NS_OK;
michael@0 519 }
michael@0 520
michael@0 521 shouldNotifyIdle = !mPendingEventCount;
michael@0 522 if (shouldNotifyIdle) {
michael@0 523 MOZ_ASSERT(mIdleNotificationCount < UINT32_MAX, "Way too many!");
michael@0 524 mIdleNotificationCount++;
michael@0 525 }
michael@0 526 }
michael@0 527
michael@0 528 if (shouldNotifyIdle) {
michael@0 529 nsCOMPtr<nsIRunnable> runnable =
michael@0 530 NS_NewRunnableMethod(this, &LazyIdleThread::ScheduleTimer);
michael@0 531 if (NS_WARN_IF(!runnable))
michael@0 532 return NS_ERROR_UNEXPECTED;
michael@0 533
michael@0 534 nsresult rv = mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
michael@0 535 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 536 return rv;
michael@0 537 }
michael@0 538
michael@0 539 return NS_OK;
michael@0 540 }
michael@0 541
michael@0 542 NS_IMETHODIMP
michael@0 543 LazyIdleThread::Observe(nsISupports* /* aSubject */,
michael@0 544 const char* aTopic,
michael@0 545 const char16_t* /* aData */)
michael@0 546 {
michael@0 547 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
michael@0 548 MOZ_ASSERT(mShutdownMethod == AutomaticShutdown,
michael@0 549 "Should not receive notifications if not AutomaticShutdown!");
michael@0 550 MOZ_ASSERT(!strcmp("xpcom-shutdown-threads", aTopic), "Bad topic!");
michael@0 551
michael@0 552 Shutdown();
michael@0 553 return NS_OK;
michael@0 554 }
michael@0 555
michael@0 556 } // namespace mozilla

mercurial