Line data Source code
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 : #ifndef nsThreadUtils_h__
8 : #define nsThreadUtils_h__
9 :
10 : #include "prthread.h"
11 : #include "prinrval.h"
12 : #include "MainThreadUtils.h"
13 : #include "nsICancelableRunnable.h"
14 : #include "nsIIdlePeriod.h"
15 : #include "nsIIdleRunnable.h"
16 : #include "nsINamed.h"
17 : #include "nsIRunnable.h"
18 : #include "nsIThreadManager.h"
19 : #include "nsITimer.h"
20 : #include "nsIThread.h"
21 : #include "nsStringGlue.h"
22 : #include "nsCOMPtr.h"
23 : #include "nsAutoPtr.h"
24 : #include "mozilla/Atomics.h"
25 : #include "mozilla/IndexSequence.h"
26 : #include "mozilla/Likely.h"
27 : #include "mozilla/Move.h"
28 : #include "mozilla/TimeStamp.h"
29 : #include "mozilla/Tuple.h"
30 : #include "mozilla/TypeTraits.h"
31 :
32 : //-----------------------------------------------------------------------------
33 : // These methods are alternatives to the methods on nsIThreadManager, provided
34 : // for convenience.
35 :
36 : /**
37 : * Create a new thread, and optionally provide an initial event for the thread.
38 : *
39 : * @param aResult
40 : * The resulting nsIThread object.
41 : * @param aInitialEvent
42 : * The initial event to run on this thread. This parameter may be null.
43 : * @param aStackSize
44 : * The size in bytes to reserve for the thread's stack.
45 : *
46 : * @returns NS_ERROR_INVALID_ARG
47 : * Indicates that the given name is not unique.
48 : */
49 : extern nsresult
50 : NS_NewThread(nsIThread** aResult,
51 : nsIRunnable* aInitialEvent = nullptr,
52 : uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE);
53 :
54 : /**
55 : * Creates a named thread, otherwise the same as NS_NewThread
56 : */
57 : extern nsresult
58 : NS_NewNamedThread(const nsACString& aName,
59 : nsIThread** aResult,
60 : nsIRunnable* aInitialEvent = nullptr,
61 : uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE);
62 :
63 : template<size_t LEN>
64 : inline nsresult
65 29 : NS_NewNamedThread(const char (&aName)[LEN],
66 : nsIThread** aResult,
67 : nsIRunnable* aInitialEvent = nullptr,
68 : uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE)
69 : {
70 : static_assert(LEN <= 16,
71 : "Thread name must be no more than 16 characters");
72 58 : return NS_NewNamedThread(nsDependentCString(aName, LEN - 1),
73 58 : aResult, aInitialEvent, aStackSize);
74 : }
75 :
76 : /**
77 : * Get a reference to the current thread.
78 : *
79 : * @param aResult
80 : * The resulting nsIThread object.
81 : */
82 : extern nsresult NS_GetCurrentThread(nsIThread** aResult);
83 :
84 : /**
85 : * Dispatch the given event to the current thread.
86 : *
87 : * @param aEvent
88 : * The event to dispatch.
89 : *
90 : * @returns NS_ERROR_INVALID_ARG
91 : * If event is null.
92 : */
93 : extern nsresult NS_DispatchToCurrentThread(nsIRunnable* aEvent);
94 : extern nsresult
95 : NS_DispatchToCurrentThread(already_AddRefed<nsIRunnable>&& aEvent);
96 :
97 : /**
98 : * Dispatch the given event to the main thread.
99 : *
100 : * @param aEvent
101 : * The event to dispatch.
102 : * @param aDispatchFlags
103 : * The flags to pass to the main thread's dispatch method.
104 : *
105 : * @returns NS_ERROR_INVALID_ARG
106 : * If event is null.
107 : */
108 : extern nsresult
109 : NS_DispatchToMainThread(nsIRunnable* aEvent,
110 : uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
111 : extern nsresult
112 : NS_DispatchToMainThread(already_AddRefed<nsIRunnable>&& aEvent,
113 : uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
114 :
115 : extern nsresult
116 : NS_DelayedDispatchToCurrentThread(
117 : already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDelayMs);
118 :
119 : /**
120 : * Dispatch the given event to the idle queue of the current thread.
121 : *
122 : * @param aEvent
123 : * The event to dispatch.
124 : *
125 : * @returns NS_ERROR_INVALID_ARG
126 : * If event is null.
127 : * @returns NS_ERROR_UNEXPECTED
128 : * If the thread is shutting down.
129 : */
130 : extern nsresult
131 : NS_IdleDispatchToCurrentThread(already_AddRefed<nsIRunnable>&& aEvent);
132 :
133 : /**
134 : * Dispatch the given event to the idle queue of the current thread.
135 : *
136 : * @param aEvent The event to dispatch. If the event implements
137 : * nsIIdleRunnable, it will receive a call on
138 : * nsIIdleRunnable::SetTimer when dispatched, with the value of
139 : * aTimeout.
140 : *
141 : * @param aTimeout The time in milliseconds until the event should be
142 : * moved from the idle queue to the regular queue, if it hasn't been
143 : * executed. If aEvent is also an nsIIdleRunnable, it is expected
144 : * that it should handle the timeout itself, after a call to
145 : * nsIIdleRunnable::SetTimer.
146 : *
147 : * @returns NS_ERROR_INVALID_ARG
148 : * If event is null.
149 : * @returns NS_ERROR_UNEXPECTED
150 : * If the thread is shutting down.
151 : */
152 : extern nsresult
153 : NS_IdleDispatchToCurrentThread(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout);
154 :
155 : /**
156 : * Dispatch the given event to the idle queue of a thread.
157 : *
158 : * @param aEvent The event to dispatch.
159 : *
160 : * @param aThread The target thread for the dispatch.
161 : *
162 : * @returns NS_ERROR_INVALID_ARG
163 : * If event is null.
164 : * @returns NS_ERROR_UNEXPECTED
165 : * If the thread is shutting down.
166 : */
167 : extern nsresult
168 : NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
169 : nsIThread* aThread);
170 :
171 : /**
172 : * Dispatch the given event to the idle queue of a thread.
173 : *
174 : * @param aEvent The event to dispatch. If the event implements
175 : * nsIIdleRunnable, it will receive a call on
176 : * nsIIdleRunnable::SetTimer when dispatched, with the value of
177 : * aTimeout.
178 : *
179 : * @param aTimeout The time in milliseconds until the event should be
180 : * moved from the idle queue to the regular queue, if it hasn't been
181 : * executed. If aEvent is also an nsIIdleRunnable, it is expected
182 : * that it should handle the timeout itself, after a call to
183 : * nsIIdleRunnable::SetTimer.
184 : *
185 : * @param aThread The target thread for the dispatch.
186 : *
187 : * @returns NS_ERROR_INVALID_ARG
188 : * If event is null.
189 : * @returns NS_ERROR_UNEXPECTED
190 : * If the thread is shutting down.
191 : */
192 : extern nsresult
193 : NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
194 : uint32_t aTimeout,
195 : nsIThread* aThread);
196 :
197 : #ifndef XPCOM_GLUE_AVOID_NSPR
198 : /**
199 : * Process all pending events for the given thread before returning. This
200 : * method simply calls ProcessNextEvent on the thread while HasPendingEvents
201 : * continues to return true and the time spent in NS_ProcessPendingEvents
202 : * does not exceed the given timeout value.
203 : *
204 : * @param aThread
205 : * The thread object for which to process pending events. If null, then
206 : * events will be processed for the current thread.
207 : * @param aTimeout
208 : * The maximum number of milliseconds to spend processing pending events.
209 : * Events are not pre-empted to honor this timeout. Rather, the timeout
210 : * value is simply used to determine whether or not to process another event.
211 : * Pass PR_INTERVAL_NO_TIMEOUT to specify no timeout.
212 : */
213 : extern nsresult
214 : NS_ProcessPendingEvents(nsIThread* aThread,
215 : PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT);
216 : #endif
217 :
218 : /**
219 : * Shortcut for nsIThread::HasPendingEvents.
220 : *
221 : * It is an error to call this function when the given thread is not the
222 : * current thread. This function will return false if called from some
223 : * other thread.
224 : *
225 : * @param aThread
226 : * The current thread or null.
227 : *
228 : * @returns
229 : * A boolean value that if "true" indicates that there are pending events
230 : * in the current thread's event queue.
231 : */
232 : extern bool NS_HasPendingEvents(nsIThread* aThread = nullptr);
233 :
234 : /**
235 : * Shortcut for nsIThread::ProcessNextEvent.
236 : *
237 : * It is an error to call this function when the given thread is not the
238 : * current thread. This function will simply return false if called
239 : * from some other thread.
240 : *
241 : * @param aThread
242 : * The current thread or null.
243 : * @param aMayWait
244 : * A boolean parameter that if "true" indicates that the method may block
245 : * the calling thread to wait for a pending event.
246 : *
247 : * @returns
248 : * A boolean value that if "true" indicates that an event from the current
249 : * thread's event queue was processed.
250 : */
251 : extern bool NS_ProcessNextEvent(nsIThread* aThread = nullptr,
252 : bool aMayWait = true);
253 :
254 : // A wrapper for nested event loops.
255 : //
256 : // This function is intended to make code more obvious (do you remember
257 : // what NS_ProcessNextEvent(nullptr, true) means?) and slightly more
258 : // efficient, as people often pass nullptr or NS_GetCurrentThread to
259 : // NS_ProcessNextEvent, which results in needless querying of the current
260 : // thread every time through the loop.
261 : //
262 : // You should use this function in preference to NS_ProcessNextEvent inside
263 : // a loop unless one of the following is true:
264 : //
265 : // * You need to pass `false` to NS_ProcessNextEvent; or
266 : // * You need to do unusual things around the call to NS_ProcessNextEvent,
267 : // such as unlocking mutexes that you are holding.
268 : //
269 : // If you *do* need to call NS_ProcessNextEvent manually, please do call
270 : // NS_GetCurrentThread() outside of your loop and pass the returned pointer
271 : // into NS_ProcessNextEvent for a tiny efficiency win.
272 : namespace mozilla {
273 :
274 : // You should normally not need to deal with this template parameter. If
275 : // you enjoy esoteric event loop details, read on.
276 : //
277 : // If you specify that NS_ProcessNextEvent wait for an event, it is possible
278 : // for NS_ProcessNextEvent to return false, i.e. to indicate that an event
279 : // was not processed. This can only happen when the thread has been shut
280 : // down by another thread, but is still attempting to process events outside
281 : // of a nested event loop.
282 : //
283 : // This behavior is admittedly strange. The scenario it deals with is the
284 : // following:
285 : //
286 : // * The current thread has been shut down by some owner thread.
287 : // * The current thread is spinning an event loop waiting for some condition
288 : // to become true.
289 : // * Said condition is actually being fulfilled by another thread, so there
290 : // are timing issues in play.
291 : //
292 : // Thus, there is a small window where the current thread's event loop
293 : // spinning can check the condition, find it false, and call
294 : // NS_ProcessNextEvent to wait for another event. But we don't actually
295 : // want it to wait indefinitely, because there might not be any other events
296 : // in the event loop, and the current thread can't accept dispatched events
297 : // because it's being shut down. Thus, actually blocking would hang the
298 : // thread, which is bad. The solution, then, is to detect such a scenario
299 : // and not actually block inside NS_ProcessNextEvent.
300 : //
301 : // But this is a problem, because we want to return the status of
302 : // NS_ProcessNextEvent to the caller of SpinEventLoopUntil if possible. In
303 : // the above scenario, however, we'd stop spinning prematurely and cause
304 : // all sorts of havoc. We therefore have this template parameter to
305 : // control whether errors are ignored or passed out to the caller of
306 : // SpinEventLoopUntil. The latter is the default; if you find yourself
307 : // wanting to use the former, you should think long and hard before doing
308 : // so, and write a comment like this defending your choice.
309 :
310 : enum class ProcessFailureBehavior {
311 : IgnoreAndContinue,
312 : ReportToCaller,
313 : };
314 :
315 : template<ProcessFailureBehavior Behavior = ProcessFailureBehavior::ReportToCaller,
316 : typename Pred>
317 : bool
318 3 : SpinEventLoopUntil(Pred&& aPredicate, nsIThread* aThread = nullptr)
319 : {
320 3 : nsIThread* thread = aThread ? aThread : NS_GetCurrentThread();
321 :
322 37 : while (!aPredicate()) {
323 17 : bool didSomething = NS_ProcessNextEvent(thread, true);
324 :
325 : if (Behavior == ProcessFailureBehavior::IgnoreAndContinue) {
326 : // Don't care what happened, continue on.
327 0 : continue;
328 17 : } else if (!didSomething) {
329 0 : return false;
330 : }
331 : }
332 :
333 3 : return true;
334 : }
335 :
336 : } // namespace mozilla
337 :
338 : /**
339 : * Returns true if we're in the compositor thread.
340 : *
341 : * We declare this here because the headers required to invoke
342 : * CompositorThreadHolder::IsInCompositorThread() also pull in a bunch of system
343 : * headers that #define various tokens in a way that can break the build.
344 : */
345 : extern bool NS_IsInCompositorThread();
346 :
347 : //-----------------------------------------------------------------------------
348 : // Helpers that work with nsCOMPtr:
349 :
350 : inline already_AddRefed<nsIThread>
351 23 : do_GetCurrentThread()
352 : {
353 23 : nsIThread* thread = nullptr;
354 23 : NS_GetCurrentThread(&thread);
355 23 : return already_AddRefed<nsIThread>(thread);
356 : }
357 :
358 : inline already_AddRefed<nsIThread>
359 298 : do_GetMainThread()
360 : {
361 298 : nsIThread* thread = nullptr;
362 298 : NS_GetMainThread(&thread);
363 298 : return already_AddRefed<nsIThread>(thread);
364 : }
365 :
366 : //-----------------------------------------------------------------------------
367 :
368 : #ifdef MOZILLA_INTERNAL_API
369 : // Fast access to the current thread. Do not release the returned pointer! If
370 : // you want to use this pointer from some other thread, then you will need to
371 : // AddRef it. Otherwise, you should only consider this pointer valid from code
372 : // running on the current thread.
373 : extern nsIThread* NS_GetCurrentThread();
374 :
375 : /**
376 : * Set the name of the current thread. Prefer this function over
377 : * PR_SetCurrentThreadName() if possible. The name will also be included in the
378 : * crash report.
379 : *
380 : * @param aName
381 : * Name of the thread. A C language null-terminated string.
382 : */
383 : extern void NS_SetCurrentThreadName(const char* aName);
384 : #endif
385 :
386 : //-----------------------------------------------------------------------------
387 :
388 : #ifndef XPCOM_GLUE_AVOID_NSPR
389 :
390 : namespace mozilla {
391 :
392 : // This class is designed to be subclassed.
393 : class IdlePeriod : public nsIIdlePeriod
394 : {
395 : public:
396 : NS_DECL_THREADSAFE_ISUPPORTS
397 : NS_DECL_NSIIDLEPERIOD
398 :
399 69 : IdlePeriod() {}
400 :
401 : protected:
402 12 : virtual ~IdlePeriod() {}
403 : private:
404 : IdlePeriod(const IdlePeriod&) = delete;
405 : IdlePeriod& operator=(const IdlePeriod&) = delete;
406 : IdlePeriod& operator=(const IdlePeriod&&) = delete;
407 : };
408 :
409 : // Cancelable runnable methods implement nsICancelableRunnable, and
410 : // Idle and IdleWithTimer also nsIIdleRunnable.
411 : enum RunnableKind
412 : {
413 : Standard,
414 : Cancelable,
415 : Idle,
416 : IdleWithTimer
417 : };
418 :
419 : // This class is designed to be subclassed.
420 : class Runnable : public nsIRunnable, public nsINamed
421 : {
422 : public:
423 : NS_DECL_THREADSAFE_ISUPPORTS
424 : NS_DECL_NSIRUNNABLE
425 : NS_DECL_NSINAMED
426 :
427 : Runnable() = delete;
428 :
429 : #ifdef RELEASE_OR_BETA
430 : explicit Runnable(const char* aName) {}
431 : #else
432 3797 : explicit Runnable(const char* aName) : mName(aName) {}
433 : #endif
434 :
435 : protected:
436 3590 : virtual ~Runnable() {}
437 :
438 : #ifndef RELEASE_OR_BETA
439 : const char* mName = nullptr;
440 : #endif
441 :
442 : private:
443 : Runnable(const Runnable&) = delete;
444 : Runnable& operator=(const Runnable&) = delete;
445 : Runnable& operator=(const Runnable&&) = delete;
446 : };
447 :
448 : // This class is designed to be subclassed.
449 : class CancelableRunnable : public Runnable,
450 : public nsICancelableRunnable
451 : {
452 : public:
453 : NS_DECL_ISUPPORTS_INHERITED
454 : // nsICancelableRunnable
455 : virtual nsresult Cancel() override;
456 :
457 : CancelableRunnable() = delete;
458 1652 : explicit CancelableRunnable(const char* aName) : Runnable(aName) {}
459 :
460 : protected:
461 1516 : virtual ~CancelableRunnable() {}
462 : private:
463 : CancelableRunnable(const CancelableRunnable&) = delete;
464 : CancelableRunnable& operator=(const CancelableRunnable&) = delete;
465 : CancelableRunnable& operator=(const CancelableRunnable&&) = delete;
466 : };
467 :
468 : // This class is designed to be subclassed.
469 : class IdleRunnable : public CancelableRunnable,
470 : public nsIIdleRunnable
471 : {
472 : public:
473 : NS_DECL_ISUPPORTS_INHERITED
474 :
475 10 : IdleRunnable()
476 10 : : CancelableRunnable("IdleRunnable")
477 : {
478 10 : }
479 : explicit IdleRunnable(const char* aName) : CancelableRunnable(aName) {}
480 :
481 : protected:
482 4 : virtual ~IdleRunnable() {}
483 : private:
484 : IdleRunnable(const IdleRunnable&) = delete;
485 : IdleRunnable& operator=(const IdleRunnable&) = delete;
486 : IdleRunnable& operator=(const IdleRunnable&&) = delete;
487 : };
488 :
489 : namespace detail {
490 :
491 : // An event that can be used to call a C++11 functions or function objects,
492 : // including lambdas. The function must have no required arguments, and must
493 : // return void.
494 : template<typename StoredFunction>
495 324 : class RunnableFunction : public Runnable
496 : {
497 : public:
498 : template <typename F>
499 108 : explicit RunnableFunction(F&& aFunction)
500 : : Runnable("RunnableFunction")
501 108 : , mFunction(Forward<F>(aFunction))
502 108 : { }
503 :
504 108 : NS_IMETHOD Run() override {
505 : static_assert(IsVoid<decltype(mFunction())>::value,
506 : "The lambda must return void!");
507 108 : mFunction();
508 108 : return NS_OK;
509 : }
510 : private:
511 : StoredFunction mFunction;
512 : };
513 :
514 : // Type alias for NS_NewRunnableFunction
515 : template<typename Function>
516 : using RunnableFunctionImpl =
517 : // Make sure we store a non-reference in nsRunnableFunction.
518 : typename detail::RunnableFunction<typename RemoveReference<Function>::Type>;
519 :
520 : template <typename T>
521 : inline already_AddRefed<T>
522 1643 : SetRunnableName(const char* aName, T* aObj)
523 : {
524 : #ifdef RELEASE_OR_BETA
525 : return do_AddRef(aObj);
526 : #else
527 1643 : MOZ_RELEASE_ASSERT(aName);
528 3286 : RefPtr<T> ref(aObj);
529 1643 : ref->SetName(aName);
530 3286 : return ref.forget();
531 : #endif
532 : }
533 :
534 : } // namespace detail
535 :
536 : namespace detail {
537 :
538 : template<typename CVRemoved>
539 : struct IsRefcountedSmartPointerHelper : FalseType {};
540 :
541 : template<typename Pointee>
542 : struct IsRefcountedSmartPointerHelper<RefPtr<Pointee>> : TrueType {};
543 :
544 : template<typename Pointee>
545 : struct IsRefcountedSmartPointerHelper<nsCOMPtr<Pointee>> : TrueType {};
546 :
547 : } // namespace detail
548 :
549 : template<typename T>
550 : struct IsRefcountedSmartPointer
551 : : detail::IsRefcountedSmartPointerHelper<typename RemoveCV<T>::Type>
552 : {};
553 :
554 : namespace detail {
555 :
556 : template<typename T, typename CVRemoved>
557 : struct RemoveSmartPointerHelper
558 : {
559 : typedef T Type;
560 : };
561 :
562 : template<typename T, typename Pointee>
563 : struct RemoveSmartPointerHelper<T, RefPtr<Pointee>>
564 : {
565 : typedef Pointee Type;
566 : };
567 :
568 : template<typename T, typename Pointee>
569 : struct RemoveSmartPointerHelper<T, nsCOMPtr<Pointee>>
570 : {
571 : typedef Pointee Type;
572 : };
573 :
574 : } // namespace detail
575 :
576 : template<typename T>
577 : struct RemoveSmartPointer
578 : : detail::RemoveSmartPointerHelper<T, typename RemoveCV<T>::Type>
579 : {};
580 :
581 : namespace detail {
582 :
583 : template<typename T, typename CVRemoved>
584 : struct RemoveRawOrSmartPointerHelper
585 : {
586 : typedef T Type;
587 : };
588 :
589 : template<typename T, typename Pointee>
590 : struct RemoveRawOrSmartPointerHelper<T, Pointee*>
591 : {
592 : typedef Pointee Type;
593 : };
594 :
595 : template<typename T, typename Pointee>
596 : struct RemoveRawOrSmartPointerHelper<T, RefPtr<Pointee>>
597 : {
598 : typedef Pointee Type;
599 : };
600 :
601 : template<typename T, typename Pointee>
602 : struct RemoveRawOrSmartPointerHelper<T, nsCOMPtr<Pointee>>
603 : {
604 : typedef Pointee Type;
605 : };
606 :
607 : } // namespace detail
608 :
609 : template<typename T>
610 : struct RemoveRawOrSmartPointer
611 : : detail::RemoveRawOrSmartPointerHelper<T, typename RemoveCV<T>::Type>
612 : {};
613 :
614 : } // namespace mozilla
615 :
616 : inline nsISupports*
617 0 : ToSupports(mozilla::Runnable *p)
618 : {
619 0 : return static_cast<nsIRunnable*>(p);
620 : }
621 :
622 : template<typename Function>
623 : already_AddRefed<mozilla::Runnable>
624 108 : NS_NewRunnableFunction(const char* aName, Function&& aFunction)
625 : {
626 : // We store a non-reference in RunnableFunction, but still forward aFunction
627 : // to move if possible.
628 : return mozilla::detail::SetRunnableName(
629 : aName,
630 108 : new mozilla::detail::RunnableFunctionImpl<Function>(
631 216 : mozilla::Forward<Function>(aFunction)));
632 : }
633 :
634 : namespace mozilla {
635 : namespace detail {
636 :
637 : already_AddRefed<nsITimer> CreateTimer();
638 :
639 : template <RunnableKind Kind>
640 1554 : class TimerBehaviour
641 : {
642 : public:
643 : nsITimer* GetTimer() { return nullptr; }
644 3062 : void CancelTimer() {}
645 :
646 : protected:
647 1482 : ~TimerBehaviour() {}
648 : };
649 :
650 : template <>
651 : class TimerBehaviour<IdleWithTimer>
652 : {
653 : public:
654 : nsITimer* GetTimer()
655 : {
656 : if (!mTimer) {
657 : mTimer = CreateTimer();
658 : }
659 :
660 : return mTimer;
661 : }
662 :
663 : void CancelTimer()
664 : {
665 : if (mTimer) {
666 : mTimer->Cancel();
667 : }
668 : }
669 :
670 : protected:
671 : ~TimerBehaviour()
672 : {
673 : CancelTimer();
674 : }
675 : private:
676 : nsCOMPtr<nsITimer> mTimer;
677 : };
678 :
679 : } // namespace detail
680 : } // namespace mozilla
681 :
682 : // An event that can be used to call a method on a class. The class type must
683 : // support reference counting. This event supports Revoke for use
684 : // with nsRevocableEventPtr.
685 : template<class ClassType,
686 : typename ReturnType = void,
687 : bool Owning = true,
688 : mozilla::RunnableKind Kind = mozilla::Standard>
689 1464 : class nsRunnableMethod
690 : : public mozilla::Conditional<Kind == mozilla::Standard,
691 : mozilla::Runnable,
692 : typename mozilla::Conditional<
693 : Kind == mozilla::Cancelable,
694 : mozilla::CancelableRunnable,
695 : mozilla::IdleRunnable>::Type>::Type,
696 : protected mozilla::detail::TimerBehaviour<Kind>
697 : {
698 : using BaseType = typename mozilla::Conditional<Kind == mozilla::Standard,
699 : mozilla::Runnable,
700 : typename mozilla::Conditional<
701 : Kind == mozilla::Cancelable,
702 : mozilla::CancelableRunnable,
703 : mozilla::IdleRunnable>::Type>::Type;
704 : public:
705 1535 : nsRunnableMethod() : BaseType("nsRunnableMethod") {}
706 :
707 : virtual void Revoke() = 0;
708 :
709 : // These ReturnTypeEnforcer classes set up a blacklist for return types that
710 : // we know are not safe. The default ReturnTypeEnforcer compiles just fine but
711 : // already_AddRefed will not.
712 : template<typename OtherReturnType>
713 : class ReturnTypeEnforcer
714 : {
715 : public:
716 : typedef int ReturnTypeIsSafe;
717 : };
718 :
719 : template<class T>
720 : class ReturnTypeEnforcer<already_AddRefed<T>>
721 : {
722 : // No ReturnTypeIsSafe makes this illegal!
723 : };
724 :
725 : // Make sure this return type is safe.
726 : typedef typename ReturnTypeEnforcer<ReturnType>::ReturnTypeIsSafe check;
727 : };
728 :
729 : template<class ClassType, bool Owning>
730 : struct nsRunnableMethodReceiver
731 : {
732 : RefPtr<ClassType> mObj;
733 1053 : explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
734 1018 : ~nsRunnableMethodReceiver() { Revoke(); }
735 2119 : ClassType* Get() const { return mObj.get(); }
736 2062 : void Revoke() { mObj = nullptr; }
737 : };
738 :
739 : template<class ClassType>
740 : struct nsRunnableMethodReceiver<ClassType, false>
741 : {
742 : ClassType* MOZ_NON_OWNING_REF mObj;
743 482 : explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
744 930 : ClassType* Get() const { return mObj; }
745 446 : void Revoke() { mObj = nullptr; }
746 : };
747 :
748 : static inline constexpr bool
749 : IsIdle(mozilla::RunnableKind aKind)
750 : {
751 : return aKind == mozilla::Idle || aKind == mozilla::IdleWithTimer;
752 : }
753 :
754 : template<typename PtrType, typename Method, bool Owning, mozilla::RunnableKind Kind>
755 : struct nsRunnableMethodTraits;
756 :
757 : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As>
758 : struct nsRunnableMethodTraits<PtrType, R(C::*)(As...), Owning, Kind>
759 : {
760 : typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
761 : static_assert(mozilla::IsBaseOf<C, class_type>::value,
762 : "Stored class must inherit from method's class");
763 : typedef R return_type;
764 : typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
765 : static const bool can_cancel = Kind == mozilla::Cancelable;
766 : };
767 :
768 : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As>
769 : struct nsRunnableMethodTraits<PtrType, R(C::*)(As...) const, Owning, Kind>
770 : {
771 : typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
772 : static_assert(mozilla::IsBaseOf<C, class_type>::value,
773 : "Stored class must inherit from method's class");
774 : typedef R return_type;
775 : typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
776 : static const bool can_cancel = Kind == mozilla::Cancelable;
777 : };
778 :
779 : #ifdef NS_HAVE_STDCALL
780 : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As>
781 : struct nsRunnableMethodTraits<PtrType, R(__stdcall C::*)(As...), Owning, Kind>
782 : {
783 : typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
784 : static_assert(mozilla::IsBaseOf<C, class_type>::value,
785 : "Stored class must inherit from method's class");
786 : typedef R return_type;
787 : typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
788 : static const bool can_cancel = Kind == mozilla::Cancelable;
789 : };
790 :
791 : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind>
792 : struct nsRunnableMethodTraits<PtrType, R(NS_STDCALL C::*)(), Owning, Kind>
793 : {
794 : typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
795 : static_assert(mozilla::IsBaseOf<C, class_type>::value,
796 : "Stored class must inherit from method's class");
797 : typedef R return_type;
798 : typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
799 : static const bool can_cancel = Kind == mozilla::Cancelable;
800 : };
801 :
802 : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As>
803 : struct nsRunnableMethodTraits<PtrType, R(__stdcall C::*)(As...) const, Owning, Kind>
804 : {
805 : typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
806 : static_assert(mozilla::IsBaseOf<C, class_type>::value,
807 : "Stored class must inherit from method's class");
808 : typedef R return_type;
809 : typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
810 : static const bool can_cancel = Kind == mozilla::Cancelable;
811 : };
812 :
813 : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind>
814 : struct nsRunnableMethodTraits<PtrType, R(NS_STDCALL C::*)() const, Owning, Kind>
815 : {
816 : typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
817 : static_assert(mozilla::IsBaseOf<C, class_type>::value,
818 : "Stored class must inherit from method's class");
819 : typedef R return_type;
820 : typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
821 : static const bool can_cancel = Kind == mozilla::Cancelable;
822 : };
823 : #endif
824 :
825 :
826 : // IsParameterStorageClass<T>::value is true if T is a parameter-storage class
827 : // that will be recognized by NS_New[NonOwning]RunnableMethodWithArg[s] to
828 : // force a specific storage&passing strategy (instead of inferring one,
829 : // see ParameterStorage).
830 : // When creating a new storage class, add a specialization for it to be
831 : // recognized.
832 : template<typename T>
833 : struct IsParameterStorageClass : public mozilla::FalseType {};
834 :
835 : // StoreXPassByY structs used to inform nsRunnableMethodArguments how to
836 : // store arguments, and how to pass them to the target method.
837 :
838 : template<typename T>
839 : struct StoreCopyPassByValue
840 : {
841 : typedef T stored_type;
842 : typedef T passed_type;
843 : stored_type m;
844 : template <typename A>
845 : MOZ_IMPLICIT StoreCopyPassByValue(A&& a) : m(mozilla::Forward<A>(a)) {}
846 : passed_type PassAsParameter() { return m; }
847 : };
848 : template<typename S>
849 : struct IsParameterStorageClass<StoreCopyPassByValue<S>>
850 : : public mozilla::TrueType {};
851 :
852 : template<typename T>
853 14 : struct StoreCopyPassByConstLRef
854 : {
855 : typedef T stored_type;
856 : typedef const T& passed_type;
857 : stored_type m;
858 : template <typename A>
859 813 : MOZ_IMPLICIT StoreCopyPassByConstLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
860 806 : passed_type PassAsParameter() { return m; }
861 : };
862 : template<typename S>
863 : struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>>
864 : : public mozilla::TrueType {};
865 :
866 : template<typename T>
867 0 : struct StoreCopyPassByLRef
868 : {
869 : typedef T stored_type;
870 : typedef T& passed_type;
871 : stored_type m;
872 : template <typename A>
873 0 : MOZ_IMPLICIT StoreCopyPassByLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
874 0 : passed_type PassAsParameter() { return m; }
875 : };
876 : template<typename S>
877 : struct IsParameterStorageClass<StoreCopyPassByLRef<S>>
878 : : public mozilla::TrueType {};
879 :
880 : template<typename T>
881 16 : struct StoreCopyPassByRRef
882 : {
883 : typedef T stored_type;
884 : typedef T&& passed_type;
885 : stored_type m;
886 : template <typename A>
887 16 : MOZ_IMPLICIT StoreCopyPassByRRef(A&& a) : m(mozilla::Forward<A>(a)) {}
888 16 : passed_type PassAsParameter() { return mozilla::Move(m); }
889 : };
890 : template<typename S>
891 : struct IsParameterStorageClass<StoreCopyPassByRRef<S>>
892 : : public mozilla::TrueType {};
893 :
894 : template<typename T>
895 : struct StoreRefPassByLRef
896 : {
897 : typedef T& stored_type;
898 : typedef T& passed_type;
899 : stored_type m;
900 : template <typename A>
901 : MOZ_IMPLICIT StoreRefPassByLRef(A& a) : m(a) {}
902 : passed_type PassAsParameter() { return m; }
903 : };
904 : template<typename S>
905 : struct IsParameterStorageClass<StoreRefPassByLRef<S>>
906 : : public mozilla::TrueType {};
907 :
908 : template<typename T>
909 : struct StoreConstRefPassByConstLRef
910 : {
911 : typedef const T& stored_type;
912 : typedef const T& passed_type;
913 : stored_type m;
914 : template <typename A>
915 0 : MOZ_IMPLICIT StoreConstRefPassByConstLRef(const A& a) : m(a) {}
916 0 : passed_type PassAsParameter() { return m; }
917 : };
918 : template<typename S>
919 : struct IsParameterStorageClass<StoreConstRefPassByConstLRef<S>>
920 : : public mozilla::TrueType {};
921 :
922 : template<typename T>
923 8 : struct StoreRefPtrPassByPtr
924 : {
925 : typedef RefPtr<T> stored_type;
926 : typedef T* passed_type;
927 : stored_type m;
928 : template <typename A>
929 8 : MOZ_IMPLICIT StoreRefPtrPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
930 8 : passed_type PassAsParameter() { return m.get(); }
931 : };
932 : template<typename S>
933 : struct IsParameterStorageClass<StoreRefPtrPassByPtr<S>>
934 : : public mozilla::TrueType {};
935 :
936 : template<typename T>
937 : struct StorePtrPassByPtr
938 : {
939 : typedef T* stored_type;
940 : typedef T* passed_type;
941 : stored_type m;
942 : template <typename A>
943 365 : MOZ_IMPLICIT StorePtrPassByPtr(A a) : m(a) {}
944 369 : passed_type PassAsParameter() { return m; }
945 : };
946 : template<typename S>
947 : struct IsParameterStorageClass<StorePtrPassByPtr<S>>
948 : : public mozilla::TrueType {};
949 :
950 : template<typename T>
951 : struct StoreConstPtrPassByConstPtr
952 : {
953 : typedef const T* stored_type;
954 : typedef const T* passed_type;
955 : stored_type m;
956 : template <typename A>
957 3 : MOZ_IMPLICIT StoreConstPtrPassByConstPtr(A a) : m(a) {}
958 3 : passed_type PassAsParameter() { return m; }
959 : };
960 : template<typename S>
961 : struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>>
962 : : public mozilla::TrueType {};
963 :
964 : template<typename T>
965 : struct StoreCopyPassByConstPtr
966 : {
967 : typedef T stored_type;
968 : typedef const T* passed_type;
969 : stored_type m;
970 : template <typename A>
971 : MOZ_IMPLICIT StoreCopyPassByConstPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
972 : passed_type PassAsParameter() { return &m; }
973 : };
974 : template<typename S>
975 : struct IsParameterStorageClass<StoreCopyPassByConstPtr<S>>
976 : : public mozilla::TrueType {};
977 :
978 : template<typename T>
979 : struct StoreCopyPassByPtr
980 : {
981 : typedef T stored_type;
982 : typedef T* passed_type;
983 : stored_type m;
984 : template <typename A>
985 : MOZ_IMPLICIT StoreCopyPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
986 : passed_type PassAsParameter() { return &m; }
987 : };
988 : template<typename S>
989 : struct IsParameterStorageClass<StoreCopyPassByPtr<S>>
990 : : public mozilla::TrueType {};
991 :
992 : namespace detail {
993 :
994 : template<typename>
995 : struct SFINAE1True : mozilla::TrueType
996 : {};
997 :
998 : template<class T>
999 : static auto HasRefCountMethodsTest(int)
1000 : -> SFINAE1True<decltype(mozilla::DeclVal<T>().AddRef(),
1001 : mozilla::DeclVal<T>().Release())>;
1002 : template<class>
1003 : static auto HasRefCountMethodsTest(long) -> mozilla::FalseType;
1004 :
1005 : template<class T>
1006 : struct HasRefCountMethods : decltype(HasRefCountMethodsTest<T>(0))
1007 : {};
1008 :
1009 : template<typename TWithoutPointer>
1010 : struct NonnsISupportsPointerStorageClass
1011 : : mozilla::Conditional<mozilla::IsConst<TWithoutPointer>::value,
1012 : StoreConstPtrPassByConstPtr<
1013 : typename mozilla::RemoveConst<TWithoutPointer>::Type>,
1014 : StorePtrPassByPtr<TWithoutPointer>>
1015 : {};
1016 :
1017 : template<typename TWithoutPointer>
1018 : struct PointerStorageClass
1019 : : mozilla::Conditional<HasRefCountMethods<TWithoutPointer>::value,
1020 : StoreRefPtrPassByPtr<TWithoutPointer>,
1021 : typename NonnsISupportsPointerStorageClass<
1022 : TWithoutPointer
1023 : >::Type>
1024 : {};
1025 :
1026 : template<typename TWithoutRef>
1027 : struct LValueReferenceStorageClass
1028 : : mozilla::Conditional<mozilla::IsConst<TWithoutRef>::value,
1029 : StoreConstRefPassByConstLRef<
1030 : typename mozilla::RemoveConst<TWithoutRef>::Type>,
1031 : StoreRefPassByLRef<TWithoutRef>>
1032 : {};
1033 :
1034 : template<typename T>
1035 : struct SmartPointerStorageClass
1036 : : mozilla::Conditional<mozilla::IsRefcountedSmartPointer<T>::value,
1037 : StoreRefPtrPassByPtr<
1038 : typename mozilla::RemoveSmartPointer<T>::Type>,
1039 : StoreCopyPassByConstLRef<T>>
1040 : {};
1041 :
1042 : template<typename T>
1043 : struct NonLValueReferenceStorageClass
1044 : : mozilla::Conditional<mozilla::IsRvalueReference<T>::value,
1045 : StoreCopyPassByRRef<
1046 : typename mozilla::RemoveReference<T>::Type>,
1047 : typename SmartPointerStorageClass<T>::Type>
1048 : {};
1049 :
1050 : template<typename T>
1051 : struct NonPointerStorageClass
1052 : : mozilla::Conditional<mozilla::IsLvalueReference<T>::value,
1053 : typename LValueReferenceStorageClass<
1054 : typename mozilla::RemoveReference<T>::Type
1055 : >::Type,
1056 : typename NonLValueReferenceStorageClass<T>::Type>
1057 : {};
1058 :
1059 : template<typename T>
1060 : struct NonParameterStorageClass
1061 : : mozilla::Conditional<mozilla::IsPointer<T>::value,
1062 : typename PointerStorageClass<
1063 : typename mozilla::RemovePointer<T>::Type
1064 : >::Type,
1065 : typename NonPointerStorageClass<T>::Type>
1066 : {};
1067 :
1068 : // Choose storage&passing strategy based on preferred storage type:
1069 : // - If IsParameterStorageClass<T>::value is true, use as-is.
1070 : // - RC* -> StoreRefPtrPassByPtr<RC> : Store RefPtr<RC>, pass RC*
1071 : // ^^ RC quacks like a ref-counted type (i.e., has AddRef and Release methods)
1072 : // - const T* -> StoreConstPtrPassByConstPtr<T> : Store const T*, pass const T*
1073 : // - T* -> StorePtrPassByPtr<T> : Store T*, pass T*.
1074 : // - const T& -> StoreConstRefPassByConstLRef<T>: Store const T&, pass const T&.
1075 : // - T& -> StoreRefPassByLRef<T> : Store T&, pass T&.
1076 : // - T&& -> StoreCopyPassByRRef<T> : Store T, pass Move(T).
1077 : // - RefPtr<T>, nsCOMPtr<T>
1078 : // -> StoreRefPtrPassByPtr<T> : Store RefPtr<T>, pass T*
1079 : // - Other T -> StoreCopyPassByConstLRef<T> : Store T, pass const T&.
1080 : // Other available explicit options:
1081 : // - StoreCopyPassByValue<T> : Store T, pass T.
1082 : // - StoreCopyPassByLRef<T> : Store T, pass T& (of copy!)
1083 : // - StoreCopyPassByConstPtr<T> : Store T, pass const T*
1084 : // - StoreCopyPassByPtr<T> : Store T, pass T* (of copy!)
1085 : // Or create your own class with PassAsParameter() method, optional
1086 : // clean-up in destructor, and with associated IsParameterStorageClass<>.
1087 : template<typename T>
1088 : struct ParameterStorage
1089 : : mozilla::Conditional<IsParameterStorageClass<T>::value,
1090 : T,
1091 : typename NonParameterStorageClass<T>::Type>
1092 : {};
1093 :
1094 : template<class T>
1095 : static auto
1096 : HasSetDeadlineTest(int) -> SFINAE1True<decltype(
1097 : mozilla::DeclVal<T>().SetDeadline(mozilla::DeclVal<mozilla::TimeStamp>()))>;
1098 :
1099 : template<class T>
1100 : static auto
1101 : HasSetDeadlineTest(long) -> mozilla::FalseType;
1102 :
1103 : template<class T>
1104 : struct HasSetDeadline : decltype(HasSetDeadlineTest<T>(0))
1105 : {};
1106 :
1107 : template <class T>
1108 : typename mozilla::EnableIf<::detail::HasSetDeadline<T>::value>::Type
1109 : SetDeadlineImpl(T* aObj, mozilla::TimeStamp aTimeStamp)
1110 : {
1111 : aObj->SetDeadline(aTimeStamp);
1112 : }
1113 :
1114 : template <class T>
1115 : typename mozilla::EnableIf<!::detail::HasSetDeadline<T>::value>::Type
1116 : SetDeadlineImpl(T* aObj, mozilla::TimeStamp aTimeStamp)
1117 : {
1118 : }
1119 : } /* namespace detail */
1120 :
1121 : namespace mozilla {
1122 : namespace detail {
1123 :
1124 : // struct used to store arguments and later apply them to a method.
1125 : template <typename... Ts>
1126 37 : struct RunnableMethodArguments final
1127 : {
1128 : Tuple<typename ::detail::ParameterStorage<Ts>::Type...> mArguments;
1129 : template <typename... As>
1130 1546 : explicit RunnableMethodArguments(As&&... aArguments)
1131 1164 : : mArguments(Forward<As>(aArguments)...)
1132 1546 : {}
1133 : template<typename C, typename M, typename... Args, size_t... Indices>
1134 : static auto
1135 1516 : applyImpl(C* o, M m, Tuple<Args...>& args, IndexSequence<Indices...>)
1136 : -> decltype(((*o).*m)(Get<Indices>(args).PassAsParameter()...))
1137 : {
1138 1516 : return ((*o).*m)(Get<Indices>(args).PassAsParameter()...);
1139 : }
1140 1516 : template<class C, typename M> auto apply(C* o, M m)
1141 : -> decltype(applyImpl(o, m, mArguments,
1142 : typename IndexSequenceFor<Ts...>::Type()))
1143 : {
1144 3026 : return applyImpl(o, m, mArguments,
1145 3029 : typename IndexSequenceFor<Ts...>::Type());
1146 : }
1147 : };
1148 :
1149 : template<typename PtrType, typename Method, bool Owning, RunnableKind Kind, typename... Storages>
1150 : class RunnableMethodImpl final
1151 : : public ::nsRunnableMethodTraits<PtrType, Method, Owning, Kind>::base_type
1152 : {
1153 : typedef typename ::nsRunnableMethodTraits<PtrType, Method, Owning, Kind> Traits;
1154 :
1155 : typedef typename Traits::class_type ClassType;
1156 : typedef typename Traits::base_type BaseType;
1157 : ::nsRunnableMethodReceiver<ClassType, Owning> mReceiver;
1158 : Method mMethod;
1159 : RunnableMethodArguments<Storages...> mArgs;
1160 : using BaseType::GetTimer;
1161 : using BaseType::CancelTimer;
1162 : private:
1163 4392 : virtual ~RunnableMethodImpl() { Revoke(); };
1164 : static void TimedOut(nsITimer* aTimer, void* aClosure)
1165 : {
1166 : static_assert(IsIdle(Kind), "Don't use me!");
1167 : RefPtr<IdleRunnable> r = static_cast<IdleRunnable*>(aClosure);
1168 : r->SetDeadline(TimeStamp());
1169 : r->Run();
1170 : r->Cancel();
1171 : }
1172 : public:
1173 : template<typename ForwardedPtrType, typename... Args>
1174 1535 : explicit RunnableMethodImpl(ForwardedPtrType&& aObj, Method aMethod,
1175 : Args&&... aArgs)
1176 1535 : : mReceiver(Forward<ForwardedPtrType>(aObj))
1177 : , mMethod(aMethod)
1178 3070 : , mArgs(Forward<Args>(aArgs)...)
1179 : {
1180 : static_assert(sizeof...(Storages) == sizeof...(Args), "Storages and Args should have equal sizes");
1181 1535 : }
1182 1536 : NS_IMETHOD Run()
1183 : {
1184 1536 : CancelTimer();
1185 :
1186 1536 : if (MOZ_LIKELY(mReceiver.Get())) {
1187 1513 : mArgs.apply(mReceiver.Get(), mMethod);
1188 : }
1189 :
1190 1536 : return NS_OK;
1191 : }
1192 :
1193 3 : nsresult Cancel()
1194 : {
1195 : static_assert(Kind >= Cancelable, "Don't use me!");
1196 3 : Revoke();
1197 3 : return NS_OK;
1198 : }
1199 :
1200 1490 : void Revoke()
1201 : {
1202 1490 : CancelTimer();
1203 1490 : mReceiver.Revoke();
1204 1490 : }
1205 :
1206 : void SetDeadline(TimeStamp aDeadline)
1207 : {
1208 : if (MOZ_LIKELY(mReceiver.Get())) {
1209 : ::detail::SetDeadlineImpl(mReceiver.Get(), aDeadline);
1210 : }
1211 : }
1212 :
1213 : void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget)
1214 : {
1215 : MOZ_ASSERT(aTarget);
1216 :
1217 : if (nsCOMPtr<nsITimer> timer = GetTimer()) {
1218 : timer->Cancel();
1219 : timer->SetTarget(aTarget);
1220 : timer->InitWithNamedFuncCallback(TimedOut,
1221 : this,
1222 : aDelay,
1223 : nsITimer::TYPE_ONE_SHOT,
1224 : "detail::RunnableMethodImpl::SetTimer");
1225 : }
1226 : }
1227 : };
1228 :
1229 : // Type aliases for NewRunnableMethod.
1230 : template<typename PtrType, typename Method>
1231 : using OwningRunnableMethod = typename ::nsRunnableMethodTraits<
1232 : typename RemoveReference<PtrType>::Type, Method, true, Standard>::base_type;
1233 : template<typename PtrType, typename Method, typename... Storages>
1234 : using OwningRunnableMethodImpl = RunnableMethodImpl<
1235 : typename RemoveReference<PtrType>::Type, Method, true, Standard, Storages...>;
1236 :
1237 : // Type aliases for NewCancelableRunnableMethod.
1238 : template<typename PtrType, typename Method>
1239 : using CancelableRunnableMethod = typename ::nsRunnableMethodTraits<
1240 : typename RemoveReference<PtrType>::Type, Method, true, Cancelable>::base_type;
1241 : template<typename PtrType, typename Method, typename... Storages>
1242 : using CancelableRunnableMethodImpl = RunnableMethodImpl<
1243 : typename RemoveReference<PtrType>::Type, Method, true, Cancelable, Storages...>;
1244 :
1245 : // Type aliases for NewIdleRunnableMethod.
1246 : template<typename PtrType, typename Method>
1247 : using IdleRunnableMethod = typename ::nsRunnableMethodTraits<
1248 : typename RemoveReference<PtrType>::Type, Method, true, Idle>::base_type;
1249 : template<typename PtrType, typename Method, typename... Storages>
1250 : using IdleRunnableMethodImpl = RunnableMethodImpl<
1251 : typename RemoveReference<PtrType>::Type, Method, true, Idle, Storages...>;
1252 :
1253 : // Type aliases for NewIdleRunnableMethodWithTimer.
1254 : template<typename PtrType, typename Method>
1255 : using IdleRunnableMethodWithTimer = typename ::nsRunnableMethodTraits<
1256 : typename RemoveReference<PtrType>::Type, Method, true, IdleWithTimer>::base_type;
1257 : template<typename PtrType, typename Method, typename... Storages>
1258 : using IdleRunnableMethodWithTimerImpl = RunnableMethodImpl<
1259 : typename RemoveReference<PtrType>::Type, Method, true, IdleWithTimer, Storages...>;
1260 :
1261 : // Type aliases for NewNonOwningRunnableMethod.
1262 : template<typename PtrType, typename Method>
1263 : using NonOwningRunnableMethod = typename ::nsRunnableMethodTraits<
1264 : typename RemoveReference<PtrType>::Type, Method, false, Standard>::base_type;
1265 : template<typename PtrType, typename Method, typename... Storages>
1266 : using NonOwningRunnableMethodImpl = RunnableMethodImpl<
1267 : typename RemoveReference<PtrType>::Type, Method, false, Standard, Storages...>;
1268 :
1269 : // Type aliases for NonOwningCancelableRunnableMethod
1270 : template<typename PtrType, typename Method>
1271 : using NonOwningCancelableRunnableMethod = typename ::nsRunnableMethodTraits<
1272 : typename RemoveReference<PtrType>::Type, Method, false, Cancelable>::base_type;
1273 : template<typename PtrType, typename Method, typename... Storages>
1274 : using NonOwningCancelableRunnableMethodImpl = RunnableMethodImpl<
1275 : typename RemoveReference<PtrType>::Type, Method, false, Cancelable, Storages...>;
1276 :
1277 : // Type aliases for NonOwningIdleRunnableMethod
1278 : template<typename PtrType, typename Method>
1279 : using NonOwningIdleRunnableMethod = typename ::nsRunnableMethodTraits<
1280 : typename RemoveReference<PtrType>::Type, Method, false, Idle>::base_type;
1281 : template<typename PtrType, typename Method, typename... Storages>
1282 : using NonOwningIdleRunnableMethodImpl = RunnableMethodImpl<
1283 : typename RemoveReference<PtrType>::Type, Method, false, Idle, Storages...>;
1284 :
1285 : // Type aliases for NewIdleRunnableMethodWithTimer.
1286 : template<typename PtrType, typename Method>
1287 : using NonOwningIdleRunnableMethodWithTimer = typename ::nsRunnableMethodTraits<
1288 : typename RemoveReference<PtrType>::Type, Method, false, IdleWithTimer>::base_type;
1289 : template<typename PtrType, typename Method, typename... Storages>
1290 : using NonOwningIdleRunnableMethodWithTimerImpl = RunnableMethodImpl<
1291 : typename RemoveReference<PtrType>::Type, Method, false, IdleWithTimer, Storages...>;
1292 :
1293 : } // namespace detail
1294 :
1295 : // NewRunnableMethod and friends
1296 : //
1297 : // Very often in Gecko, you'll find yourself in a situation where you want
1298 : // to invoke a method (with or without arguments) asynchronously. You
1299 : // could write a small helper class inheriting from nsRunnable to handle
1300 : // all these details, or you could let NewRunnableMethod take care of all
1301 : // those details for you.
1302 : //
1303 : // The simplest use of NewRunnableMethod looks like:
1304 : //
1305 : // nsCOMPtr<nsIRunnable> event =
1306 : // mozilla::NewRunnableMethod("description", myObject, &MyClass::HandleEvent);
1307 : // NS_DispatchToCurrentThread(event);
1308 : //
1309 : // Statically enforced constraints:
1310 : // - myObject must be of (or implicitly convertible to) type MyClass
1311 : // - MyClass must define AddRef and Release methods
1312 : //
1313 : // The "description" string should specify a human-readable name for the
1314 : // runnable; the provided string is used by various introspection tools
1315 : // in the browser.
1316 : //
1317 : // The created runnable will take a strong reference to `myObject`. For
1318 : // non-refcounted objects, or refcounted objects with unusual refcounting
1319 : // requirements, and if and only if you are 110% certain that `myObject`
1320 : // will live long enough, you can use NewNonOwningRunnableMethod instead,
1321 : // which will, as its name implies, take a non-owning reference. If you
1322 : // find yourself having to use this function, you should accompany your use
1323 : // with a proof comment describing why the runnable will not lead to
1324 : // use-after-frees.
1325 : //
1326 : // (If you find yourself writing contorted code to Release() an object
1327 : // asynchronously on a different thread, you should use the
1328 : // NS_ProxyRelease function.)
1329 : //
1330 : // Invoking a method with arguments takes a little more care. The
1331 : // natural extension of the above:
1332 : //
1333 : // nsCOMPtr<nsIRunnable> event =
1334 : // mozilla::NewRunnableMethod("description", myObject, &MyClass::HandleEvent,
1335 : // arg1, arg2, ...);
1336 : //
1337 : // can lead to security hazards (e.g. passing in raw pointers to refcounted
1338 : // objects and storing those raw pointers in the runnable). We therefore
1339 : // require you to specify the storage types used by the runnable, just as
1340 : // you would if you were writing out the class by hand:
1341 : //
1342 : // nsCOMPtr<nsIRunnable> event =
1343 : // mozilla::NewRunnableMethod<RefPtr<T>, nsTArray<U>>
1344 : // ("description", myObject, &MyClass::HandleEvent, arg1, arg2);
1345 : //
1346 : // Please note that you do not have to pass the same argument type as you
1347 : // specify in the template arguments. For example, if you want to transfer
1348 : // ownership to a runnable, you can write:
1349 : //
1350 : // RefPtr<T> ptr = ...;
1351 : // nsTArray<U> array = ...;
1352 : // nsCOMPtr<nsIRunnable> event =
1353 : // mozilla::NewRunnableMethod<RefPtr<T>, nsTArray<U>>
1354 : // ("description", myObject, &MyClass::DoSomething,
1355 : // Move(ptr), Move(array));
1356 : //
1357 : // and there will be no extra AddRef/Release traffic, or copying of the array.
1358 : //
1359 : // Each type that you specify as a template argument to NewRunnableMethod
1360 : // comes with its own style of storage in the runnable and its own style
1361 : // of argument passing to the invoked method. See the comment for
1362 : // ParameterStorage above for more details.
1363 : //
1364 : // If you need to customize the storage type and/or argument passing type,
1365 : // you can write your own class to use as a template argument to
1366 : // NewRunnableMethod. If you find yourself having to do that frequently,
1367 : // please file a bug in Core::XPCOM about adding the custom type to the
1368 : // core code in this file, and/or for custom rules for ParameterStorage
1369 : // to select that strategy.
1370 : //
1371 : // For places that require you to use cancelable runnables, such as
1372 : // workers, there's also NewCancelableRunnableMethod and its non-owning
1373 : // counterpart. The runnables returned by these methods additionally
1374 : // implement nsICancelableRunnable.
1375 : //
1376 : // Finally, all of the functions discussed above have additional overloads
1377 : // that do not take a `const char*` as their first parameter; you may see
1378 : // these in older code. The `const char*` overload is preferred and
1379 : // should be used in new code exclusively.
1380 :
1381 : template<typename PtrType, typename Method>
1382 : already_AddRefed<detail::OwningRunnableMethod<PtrType, Method>>
1383 272 : NewRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod)
1384 : {
1385 : return detail::SetRunnableName(
1386 : aName,
1387 272 : new detail::OwningRunnableMethodImpl<PtrType, Method>(
1388 544 : Forward<PtrType>(aPtr), aMethod));
1389 : }
1390 :
1391 : template<typename PtrType, typename Method>
1392 : already_AddRefed<detail::CancelableRunnableMethod<PtrType, Method>>
1393 0 : NewCancelableRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod)
1394 : {
1395 : return detail::SetRunnableName(
1396 : aName,
1397 0 : new detail::CancelableRunnableMethodImpl<PtrType, Method>(
1398 0 : Forward<PtrType>(aPtr), aMethod));
1399 : }
1400 :
1401 : template<typename PtrType, typename Method>
1402 : already_AddRefed<detail::IdleRunnableMethod<PtrType, Method>>
1403 : NewIdleRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod)
1404 : {
1405 : return detail::SetRunnableName(
1406 : aName,
1407 : new detail::IdleRunnableMethodImpl<PtrType, Method>(
1408 : Forward<PtrType>(aPtr), aMethod));
1409 : }
1410 :
1411 : template<typename PtrType, typename Method>
1412 : already_AddRefed<detail::IdleRunnableMethodWithTimer<PtrType, Method>>
1413 : NewIdleRunnableMethodWithTimer(const char* aName,
1414 : PtrType&& aPtr,
1415 : Method aMethod)
1416 : {
1417 : return detail::SetRunnableName(
1418 : aName,
1419 : new detail::IdleRunnableMethodWithTimerImpl<PtrType, Method>(
1420 : Forward<PtrType>(aPtr), aMethod));
1421 : }
1422 :
1423 : template<typename PtrType, typename Method>
1424 : already_AddRefed<detail::NonOwningRunnableMethod<PtrType, Method>>
1425 69 : NewNonOwningRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod)
1426 : {
1427 : return detail::SetRunnableName(
1428 : aName,
1429 69 : new detail::NonOwningRunnableMethodImpl<PtrType, Method>(
1430 138 : Forward<PtrType>(aPtr), aMethod));
1431 : }
1432 :
1433 : template<typename PtrType, typename Method>
1434 : already_AddRefed<detail::NonOwningCancelableRunnableMethod<PtrType, Method>>
1435 40 : NewNonOwningCancelableRunnableMethod(const char* aName, PtrType&& aPtr,
1436 : Method aMethod)
1437 : {
1438 : return detail::SetRunnableName(
1439 : aName,
1440 40 : new detail::NonOwningCancelableRunnableMethodImpl<PtrType, Method>(
1441 80 : Forward<PtrType>(aPtr), aMethod));
1442 : }
1443 :
1444 : template<typename PtrType, typename Method>
1445 : already_AddRefed<detail::NonOwningIdleRunnableMethod<PtrType, Method>>
1446 : NewNonOwningIdleRunnableMethod(const char* aName,
1447 : PtrType&& aPtr,
1448 : Method aMethod)
1449 : {
1450 : return detail::SetRunnableName(
1451 : aName,
1452 : new detail::NonOwningIdleRunnableMethodImpl<PtrType, Method>(
1453 : Forward<PtrType>(aPtr), aMethod));
1454 : }
1455 :
1456 : template<typename PtrType, typename Method>
1457 : already_AddRefed<detail::NonOwningIdleRunnableMethodWithTimer<PtrType, Method>>
1458 : NewNonOwningIdleRunnableMethodWithTimer(const char* aName,
1459 : PtrType&& aPtr,
1460 : Method aMethod)
1461 : {
1462 : return detail::SetRunnableName(
1463 : aName,
1464 : new detail::NonOwningIdleRunnableMethodWithTimerImpl<PtrType, Method>(
1465 : Forward<PtrType>(aPtr), aMethod));
1466 : }
1467 :
1468 : // Similar to NewRunnableMethod. Call like so:
1469 : // nsCOMPtr<nsIRunnable> event =
1470 : // NewRunnableMethod<Types,...>(myObject, &MyClass::HandleEvent, myArg1,...);
1471 : // 'Types' are the stored type for each argument, see ParameterStorage for details.
1472 : template<typename... Storages, typename PtrType, typename Method, typename... Args>
1473 : already_AddRefed<detail::OwningRunnableMethod<PtrType, Method>>
1474 111 : NewRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod, Args&&... aArgs)
1475 : {
1476 : static_assert(sizeof...(Storages) == sizeof...(Args),
1477 : "<Storages...> size should be equal to number of arguments");
1478 : return detail::SetRunnableName(
1479 : aName,
1480 111 : new detail::OwningRunnableMethodImpl<PtrType, Method, Storages...>(
1481 222 : Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
1482 : }
1483 :
1484 : template<typename... Storages, typename PtrType, typename Method, typename... Args>
1485 : already_AddRefed<detail::NonOwningRunnableMethod<PtrType, Method>>
1486 373 : NewNonOwningRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod,
1487 : Args&&... aArgs)
1488 : {
1489 : static_assert(sizeof...(Storages) == sizeof...(Args),
1490 : "<Storages...> size should be equal to number of arguments");
1491 : return detail::SetRunnableName(
1492 : aName,
1493 373 : new detail::NonOwningRunnableMethodImpl<PtrType, Method, Storages...>(
1494 746 : Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
1495 : }
1496 :
1497 : template<typename... Storages, typename PtrType, typename Method, typename... Args>
1498 : already_AddRefed<detail::CancelableRunnableMethod<PtrType, Method>>
1499 670 : NewCancelableRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod,
1500 : Args&&... aArgs)
1501 : {
1502 : static_assert(sizeof...(Storages) == sizeof...(Args),
1503 : "<Storages...> size should be equal to number of arguments");
1504 : return detail::SetRunnableName(
1505 : aName,
1506 670 : new detail::CancelableRunnableMethodImpl<PtrType, Method, Storages...>(
1507 1340 : Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
1508 : }
1509 :
1510 : template<typename... Storages, typename PtrType, typename Method, typename... Args>
1511 : already_AddRefed<detail::NonOwningCancelableRunnableMethod<PtrType, Method>>
1512 0 : NewNonOwningCancelableRunnableMethod(const char* aName, PtrType&& aPtr,
1513 : Method aMethod, Args&&... aArgs)
1514 : {
1515 : static_assert(sizeof...(Storages) == sizeof...(Args),
1516 : "<Storages...> size should be equal to number of arguments");
1517 : return detail::SetRunnableName(
1518 : aName,
1519 0 : new detail::NonOwningCancelableRunnableMethodImpl<PtrType, Method, Storages...>(
1520 0 : Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
1521 : }
1522 :
1523 : template<typename... Storages,
1524 : typename PtrType,
1525 : typename Method,
1526 : typename... Args>
1527 : already_AddRefed<detail::IdleRunnableMethod<PtrType, Method>>
1528 : NewIdleRunnableMethod(const char* aName,
1529 : PtrType&& aPtr,
1530 : Method aMethod,
1531 : Args&&... aArgs)
1532 : {
1533 : static_assert(sizeof...(Storages) == sizeof...(Args),
1534 : "<Storages...> size should be equal to number of arguments");
1535 : return detail::SetRunnableName(
1536 : aName,
1537 : new detail::IdleRunnableMethodImpl<PtrType, Method, Storages...>(
1538 : Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
1539 : }
1540 :
1541 : template<typename... Storages,
1542 : typename PtrType,
1543 : typename Method,
1544 : typename... Args>
1545 : already_AddRefed<detail::NonOwningIdleRunnableMethod<PtrType, Method>>
1546 : NewNonOwningIdleRunnableMethod(const char* aName,
1547 : PtrType&& aPtr,
1548 : Method aMethod,
1549 : Args&&... aArgs)
1550 : {
1551 : static_assert(sizeof...(Storages) == sizeof...(Args),
1552 : "<Storages...> size should be equal to number of arguments");
1553 : return detail::SetRunnableName(
1554 : aName,
1555 : new detail::NonOwningIdleRunnableMethodImpl<PtrType, Method, Storages...>(
1556 : Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
1557 : }
1558 :
1559 : } // namespace mozilla
1560 :
1561 : #endif // XPCOM_GLUE_AVOID_NSPR
1562 :
1563 : // This class is designed to be used when you have an event class E that has a
1564 : // pointer back to resource class R. If R goes away while E is still pending,
1565 : // then it is important to "revoke" E so that it does not try use R after R has
1566 : // been destroyed. nsRevocableEventPtr makes it easy for R to manage such
1567 : // situations:
1568 : //
1569 : // class R;
1570 : //
1571 : // class E : public mozilla::Runnable {
1572 : // public:
1573 : // void Revoke() {
1574 : // mResource = nullptr;
1575 : // }
1576 : // private:
1577 : // R *mResource;
1578 : // };
1579 : //
1580 : // class R {
1581 : // public:
1582 : // void EventHandled() {
1583 : // mEvent.Forget();
1584 : // }
1585 : // private:
1586 : // nsRevocableEventPtr<E> mEvent;
1587 : // };
1588 : //
1589 : // void R::PostEvent() {
1590 : // // Make sure any pending event is revoked.
1591 : // mEvent->Revoke();
1592 : //
1593 : // nsCOMPtr<nsIRunnable> event = new E();
1594 : // if (NS_SUCCEEDED(NS_DispatchToCurrentThread(event))) {
1595 : // // Keep pointer to event so we can revoke it.
1596 : // mEvent = event;
1597 : // }
1598 : // }
1599 : //
1600 : // NS_IMETHODIMP E::Run() {
1601 : // if (!mResource)
1602 : // return NS_OK;
1603 : // ...
1604 : // mResource->EventHandled();
1605 : // return NS_OK;
1606 : // }
1607 : //
1608 : template<class T>
1609 : class nsRevocableEventPtr
1610 : {
1611 : public:
1612 609 : nsRevocableEventPtr() : mEvent(nullptr) {}
1613 28 : ~nsRevocableEventPtr() { Revoke(); }
1614 :
1615 138 : const nsRevocableEventPtr& operator=(T* aEvent)
1616 : {
1617 138 : if (mEvent != aEvent) {
1618 89 : Revoke();
1619 89 : mEvent = aEvent;
1620 : }
1621 138 : return *this;
1622 : }
1623 :
1624 2 : const nsRevocableEventPtr& operator=(already_AddRefed<T> aEvent)
1625 : {
1626 4 : RefPtr<T> event = aEvent;
1627 2 : if (mEvent != event) {
1628 2 : Revoke();
1629 2 : mEvent = event.forget();
1630 : }
1631 4 : return *this;
1632 : }
1633 :
1634 167 : void Revoke()
1635 : {
1636 167 : if (mEvent) {
1637 29 : mEvent->Revoke();
1638 29 : mEvent = nullptr;
1639 : }
1640 167 : }
1641 :
1642 59 : void Forget() { mEvent = nullptr; }
1643 375 : bool IsPending() { return mEvent != nullptr; }
1644 61 : T* get() { return mEvent; }
1645 :
1646 : private:
1647 : // Not implemented
1648 : nsRevocableEventPtr(const nsRevocableEventPtr&);
1649 : nsRevocableEventPtr& operator=(const nsRevocableEventPtr&);
1650 :
1651 : RefPtr<T> mEvent;
1652 : };
1653 :
1654 : /**
1655 : * A simple helper to suffix thread pool name
1656 : * with incremental numbers.
1657 : */
1658 : class nsThreadPoolNaming
1659 : {
1660 : public:
1661 11 : nsThreadPoolNaming() : mCounter(0) {}
1662 :
1663 : /**
1664 : * Returns a thread name as "<aPoolName> #<n>" and increments the counter.
1665 : */
1666 : nsCString GetNextThreadName(const nsACString& aPoolName);
1667 :
1668 : template<size_t LEN>
1669 24 : nsCString GetNextThreadName(const char (&aPoolName)[LEN])
1670 : {
1671 24 : return GetNextThreadName(nsDependentCString(aPoolName, LEN - 1));
1672 : }
1673 :
1674 : private:
1675 : mozilla::Atomic<uint32_t> mCounter;
1676 :
1677 : nsThreadPoolNaming(const nsThreadPoolNaming&) = delete;
1678 : void operator=(const nsThreadPoolNaming&) = delete;
1679 : };
1680 :
1681 : /**
1682 : * Thread priority in most operating systems affect scheduling, not IO. This
1683 : * helper is used to set the current thread to low IO priority for the lifetime
1684 : * of the created object. You can only use this low priority IO setting within
1685 : * the context of the current thread.
1686 : */
1687 : class MOZ_STACK_CLASS nsAutoLowPriorityIO
1688 : {
1689 : public:
1690 : nsAutoLowPriorityIO();
1691 : ~nsAutoLowPriorityIO();
1692 :
1693 : private:
1694 : bool lowIOPrioritySet;
1695 : #if defined(XP_MACOSX)
1696 : int oldPriority;
1697 : #endif
1698 : };
1699 :
1700 : void
1701 : NS_SetMainThread();
1702 :
1703 : /**
1704 : * Return the expiration time of the next timer to run on the current
1705 : * thread. If that expiration time is greater than aDefault, then
1706 : * return aDefault. aSearchBound specifies a maximum number of timers
1707 : * to examine to find a timer on the current thread. If no timer that
1708 : * will run on the current thread is found after examining
1709 : * aSearchBound timers, return the highest seen expiration time as a
1710 : * best effort guess.
1711 : *
1712 : * Timers with either the type nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY or
1713 : * nsITIMER::TYPE_REPEATING_SLACK_LOW_PRIORITY will be skipped when
1714 : * searching for the next expiration time. This enables timers to
1715 : * have lower priority than callbacks dispatched from
1716 : * nsIThread::IdleDispatch.
1717 : */
1718 : extern mozilla::TimeStamp
1719 : NS_GetTimerDeadlineHintOnCurrentThread(mozilla::TimeStamp aDefault, uint32_t aSearchBound);
1720 :
1721 : namespace mozilla {
1722 :
1723 : /**
1724 : * Cooperative thread scheduling is governed by two rules:
1725 : * - Only one thread in the pool of cooperatively scheduled threads runs at a
1726 : * time.
1727 : * - Thread switching happens at well-understood safe points.
1728 : *
1729 : * In some cases we may want to treat all the threads in a cooperative pool as a
1730 : * single thread, while other parts of the code may want to view them as separate
1731 : * threads. GetCurrentVirtualThread() will return the same value for all
1732 : * threads in a cooperative thread pool. GetCurrentPhysicalThread will return a
1733 : * different value for each thread in the pool.
1734 : *
1735 : * Thread safety assertions are a concrete example where GetCurrentVirtualThread
1736 : * should be used. An object may want to assert that it only can be used on the
1737 : * thread that created it. Such assertions would normally prevent the object
1738 : * from being used on different cooperative threads. However, the object might
1739 : * really only care that it's used atomically. Cooperative scheduling guarantees
1740 : * that it will be (assuming we don't yield in the middle of modifying the
1741 : * object). So we can weaken the assertion to compare the virtual thread the
1742 : * object was created on to the virtual thread on which it's being used. This
1743 : * assertion allows the object to be used across threads in a cooperative thread
1744 : * pool while preventing accesses across preemptively scheduled threads (which
1745 : * would be unsafe).
1746 : */
1747 :
1748 : // Returns the PRThread on which this code is running.
1749 : PRThread*
1750 : GetCurrentPhysicalThread();
1751 :
1752 : // Returns a "virtual" PRThread that should only be used for comparison with
1753 : // other calls to GetCurrentVirtualThread. Two threads in the same cooperative
1754 : // thread pool will return the same virtual thread. Threads that are not
1755 : // cooperatively scheduled will have their own unique virtual PRThread (which
1756 : // will be equal to their physical PRThread).
1757 : //
1758 : // The return value of GetCurrentVirtualThread() is guaranteed not to change
1759 : // throughout the lifetime of a thread.
1760 : //
1761 : // Note that the original main thread (the first one created in the process) is
1762 : // considered as part of the pool of cooperative threads, so the return value of
1763 : // GetCurrentVirtualThread() for this thread (throughout its lifetime, even
1764 : // during shutdown) is the same as the return value from any other thread in the
1765 : // cooperative pool.
1766 : PRThread*
1767 : GetCurrentVirtualThread();
1768 :
1769 : // These functions return event targets that can be used to dispatch to the
1770 : // current or main thread. They can also be used to test if you're on those
1771 : // threads (via IsOnCurrentThread). These functions should be used in preference
1772 : // to the nsIThread-based NS_Get{Current,Main}Thread functions since they will
1773 : // return more useful answers in the case of threads sharing an event loop.
1774 :
1775 : nsIEventTarget*
1776 : GetCurrentThreadEventTarget();
1777 :
1778 : nsIEventTarget*
1779 : GetMainThreadEventTarget();
1780 :
1781 : // These variants of the above functions assert that the given thread has a
1782 : // serial event target (i.e., that it's not part of a thread pool) and returns
1783 : // that.
1784 :
1785 : nsISerialEventTarget*
1786 : GetCurrentThreadSerialEventTarget();
1787 :
1788 : nsISerialEventTarget*
1789 : GetMainThreadSerialEventTarget();
1790 :
1791 : } // namespace mozilla
1792 :
1793 : #endif // nsThreadUtils_h__
|