Coverage Report

Created: 2018-09-25 14:53

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