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 "nsIThreadManager.h"
14 #include "nsIThread.h"
15 #include "nsIRunnable.h"
16 #include "nsICancelableRunnable.h"
17 #include "nsIIdlePeriod.h"
18 #include "nsIIncrementalRunnable.h"
19 #include "nsStringGlue.h"
20 #include "nsCOMPtr.h"
21 #include "nsAutoPtr.h"
22 #include "mozilla/Atomics.h"
23 #include "mozilla/IndexSequence.h"
24 #include "mozilla/Likely.h"
25 #include "mozilla/Move.h"
26 #include "mozilla/TimeStamp.h"
27 #include "mozilla/Tuple.h"
28 #include "mozilla/TypeTraits.h"
29
30 //-----------------------------------------------------------------------------
31 // These methods are alternatives to the methods on nsIThreadManager, provided
32 // for convenience.
33
34 /**
35 * Set name of the target thread. This operation is asynchronous.
36 */
37 extern void NS_SetThreadName(nsIThread* aThread, const nsACString& aName);
38
39 /**
40 * Static length version of the above function checking length of the
41 * name at compile time.
42 */
43 template<size_t LEN>
44 inline void
NS_SetThreadName(nsIThread * aThread,const char (& aName)[LEN])45 NS_SetThreadName(nsIThread* aThread, const char (&aName)[LEN])
46 {
47 static_assert(LEN <= 16,
48 "Thread name must be no more than 16 characters");
49 NS_SetThreadName(aThread, nsDependentCString(aName));
50 }
51
52 /**
53 * Create a new thread, and optionally provide an initial event for the thread.
54 *
55 * @param aResult
56 * The resulting nsIThread object.
57 * @param aInitialEvent
58 * The initial event to run on this thread. This parameter may be null.
59 * @param aStackSize
60 * The size in bytes to reserve for the thread's stack.
61 *
62 * @returns NS_ERROR_INVALID_ARG
63 * Indicates that the given name is not unique.
64 */
65 extern nsresult
66 NS_NewThread(nsIThread** aResult,
67 nsIRunnable* aInitialEvent = nullptr,
68 uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE);
69
70 /**
71 * Creates a named thread, otherwise the same as NS_NewThread
72 */
73 template<size_t LEN>
74 inline nsresult
75 NS_NewNamedThread(const char (&aName)[LEN],
76 nsIThread** aResult,
77 nsIRunnable* aInitialEvent = nullptr,
78 uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE)
79 {
80 // Hold a ref while dispatching the initial event to match NS_NewThread()
81 nsCOMPtr<nsIThread> thread;
82 nsresult rv = NS_NewThread(getter_AddRefs(thread), nullptr, aStackSize);
83 if (NS_WARN_IF(NS_FAILED(rv))) {
84 return rv;
85 }
86 NS_SetThreadName<LEN>(thread, aName);
87 if (aInitialEvent) {
88 rv = thread->Dispatch(aInitialEvent, NS_DISPATCH_NORMAL);
89 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Initial event dispatch failed");
90 }
91
92 *aResult = nullptr;
93 thread.swap(*aResult);
94 return rv;
95 }
96
97 /**
98 * Get a reference to the current thread.
99 *
100 * @param aResult
101 * The resulting nsIThread object.
102 */
103 extern nsresult NS_GetCurrentThread(nsIThread** aResult);
104
105 /**
106 * Dispatch the given event to the current thread.
107 *
108 * @param aEvent
109 * The event to dispatch.
110 *
111 * @returns NS_ERROR_INVALID_ARG
112 * If event is null.
113 */
114 extern nsresult NS_DispatchToCurrentThread(nsIRunnable* aEvent);
115 extern nsresult
116 NS_DispatchToCurrentThread(already_AddRefed<nsIRunnable>&& aEvent);
117
118 /**
119 * Dispatch the given event to the main thread.
120 *
121 * @param aEvent
122 * The event to dispatch.
123 * @param aDispatchFlags
124 * The flags to pass to the main thread's dispatch method.
125 *
126 * @returns NS_ERROR_INVALID_ARG
127 * If event is null.
128 */
129 extern nsresult
130 NS_DispatchToMainThread(nsIRunnable* aEvent,
131 uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
132 extern nsresult
133 NS_DispatchToMainThread(already_AddRefed<nsIRunnable>&& aEvent,
134 uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
135
136 extern nsresult
137 NS_DelayedDispatchToCurrentThread(
138 already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDelayMs);
139
140 extern nsresult
141 NS_IdleDispatchToCurrentThread(already_AddRefed<nsIRunnable>&& aEvent);
142
143 #ifndef XPCOM_GLUE_AVOID_NSPR
144 /**
145 * Process all pending events for the given thread before returning. This
146 * method simply calls ProcessNextEvent on the thread while HasPendingEvents
147 * continues to return true and the time spent in NS_ProcessPendingEvents
148 * does not exceed the given timeout value.
149 *
150 * @param aThread
151 * The thread object for which to process pending events. If null, then
152 * events will be processed for the current thread.
153 * @param aTimeout
154 * The maximum number of milliseconds to spend processing pending events.
155 * Events are not pre-empted to honor this timeout. Rather, the timeout
156 * value is simply used to determine whether or not to process another event.
157 * Pass PR_INTERVAL_NO_TIMEOUT to specify no timeout.
158 */
159 extern nsresult
160 NS_ProcessPendingEvents(nsIThread* aThread,
161 PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT);
162 #endif
163
164 /**
165 * Shortcut for nsIThread::HasPendingEvents.
166 *
167 * It is an error to call this function when the given thread is not the
168 * current thread. This function will return false if called from some
169 * other thread.
170 *
171 * @param aThread
172 * The current thread or null.
173 *
174 * @returns
175 * A boolean value that if "true" indicates that there are pending events
176 * in the current thread's event queue.
177 */
178 extern bool NS_HasPendingEvents(nsIThread* aThread = nullptr);
179
180 /**
181 * Shortcut for nsIThread::ProcessNextEvent.
182 *
183 * It is an error to call this function when the given thread is not the
184 * current thread. This function will simply return false if called
185 * from some other thread.
186 *
187 * @param aThread
188 * The current thread or null.
189 * @param aMayWait
190 * A boolean parameter that if "true" indicates that the method may block
191 * the calling thread to wait for a pending event.
192 *
193 * @returns
194 * A boolean value that if "true" indicates that an event from the current
195 * thread's event queue was processed.
196 */
197 extern bool NS_ProcessNextEvent(nsIThread* aThread = nullptr,
198 bool aMayWait = true);
199
200 //-----------------------------------------------------------------------------
201 // Helpers that work with nsCOMPtr:
202
203 inline already_AddRefed<nsIThread>
do_GetCurrentThread()204 do_GetCurrentThread()
205 {
206 nsIThread* thread = nullptr;
207 NS_GetCurrentThread(&thread);
208 return already_AddRefed<nsIThread>(thread);
209 }
210
211 inline already_AddRefed<nsIThread>
do_GetMainThread()212 do_GetMainThread()
213 {
214 nsIThread* thread = nullptr;
215 NS_GetMainThread(&thread);
216 return already_AddRefed<nsIThread>(thread);
217 }
218
219 //-----------------------------------------------------------------------------
220
221 #ifdef MOZILLA_INTERNAL_API
222 // Fast access to the current thread. Do not release the returned pointer! If
223 // you want to use this pointer from some other thread, then you will need to
224 // AddRef it. Otherwise, you should only consider this pointer valid from code
225 // running on the current thread.
226 extern nsIThread* NS_GetCurrentThread();
227 #endif
228
229 //-----------------------------------------------------------------------------
230
231 #ifndef XPCOM_GLUE_AVOID_NSPR
232
233 namespace mozilla {
234
235 // This class is designed to be subclassed.
236 class IdlePeriod : public nsIIdlePeriod
237 {
238 public:
239 NS_DECL_THREADSAFE_ISUPPORTS
240 NS_DECL_NSIIDLEPERIOD
241
IdlePeriod()242 IdlePeriod() {}
243
244 protected:
~IdlePeriod()245 virtual ~IdlePeriod() {}
246 private:
247 IdlePeriod(const IdlePeriod&) = delete;
248 IdlePeriod& operator=(const IdlePeriod&) = delete;
249 IdlePeriod& operator=(const IdlePeriod&&) = delete;
250 };
251
252 // This class is designed to be subclassed.
253 class Runnable : public nsIRunnable
254 {
255 public:
256 NS_DECL_THREADSAFE_ISUPPORTS
257 NS_DECL_NSIRUNNABLE
258
Runnable()259 Runnable() {}
260
261 protected:
~Runnable()262 virtual ~Runnable() {}
263 private:
264 Runnable(const Runnable&) = delete;
265 Runnable& operator=(const Runnable&) = delete;
266 Runnable& operator=(const Runnable&&) = delete;
267 };
268
269 // This class is designed to be subclassed.
270 class CancelableRunnable : public Runnable,
271 public nsICancelableRunnable
272 {
273 public:
274 NS_DECL_ISUPPORTS_INHERITED
275 // nsICancelableRunnable
276 virtual nsresult Cancel() override;
277
CancelableRunnable()278 CancelableRunnable() {}
279
280 protected:
~CancelableRunnable()281 virtual ~CancelableRunnable() {}
282 private:
283 CancelableRunnable(const CancelableRunnable&) = delete;
284 CancelableRunnable& operator=(const CancelableRunnable&) = delete;
285 CancelableRunnable& operator=(const CancelableRunnable&&) = delete;
286 };
287
288 // This class is designed to be subclassed.
289 class IncrementalRunnable : public CancelableRunnable,
290 public nsIIncrementalRunnable
291 {
292 public:
293 NS_DECL_ISUPPORTS_INHERITED
294 // nsIIncrementalRunnable
295 virtual void SetDeadline(TimeStamp aDeadline) override;
296
IncrementalRunnable()297 IncrementalRunnable() {}
298
299 protected:
~IncrementalRunnable()300 virtual ~IncrementalRunnable() {}
301 private:
302 IncrementalRunnable(const IncrementalRunnable&) = delete;
303 IncrementalRunnable& operator=(const IncrementalRunnable&) = delete;
304 IncrementalRunnable& operator=(const IncrementalRunnable&&) = delete;
305 };
306
307 namespace detail {
308
309 // An event that can be used to call a C++11 functions or function objects,
310 // including lambdas. The function must have no required arguments, and must
311 // return void.
312 template<typename StoredFunction>
313 class RunnableFunction : public Runnable
314 {
315 public:
316 template <typename F>
RunnableFunction(F && aFunction)317 explicit RunnableFunction(F&& aFunction)
318 : mFunction(Forward<F>(aFunction))
319 { }
320
Run()321 NS_IMETHOD Run() override {
322 static_assert(IsVoid<decltype(mFunction())>::value,
323 "The lambda must return void!");
324 mFunction();
325 return NS_OK;
326 }
327 private:
328 StoredFunction mFunction;
329 };
330
331 } // namespace detail
332
333 } // namespace mozilla
334
335 template<typename Function>
336 already_AddRefed<mozilla::Runnable>
NS_NewRunnableFunction(Function && aFunction)337 NS_NewRunnableFunction(Function&& aFunction)
338 {
339 return do_AddRef(new mozilla::detail::RunnableFunction
340 // Make sure we store a non-reference in nsRunnableFunction.
341 <typename mozilla::RemoveReference<Function>::Type>
342 // But still forward aFunction to move if possible.
343 (mozilla::Forward<Function>(aFunction)));
344 }
345
346 // An event that can be used to call a method on a class. The class type must
347 // support reference counting. This event supports Revoke for use
348 // with nsRevocableEventPtr.
349 template<class ClassType,
350 typename ReturnType = void,
351 bool Owning = true,
352 bool Cancelable = false>
353 class nsRunnableMethod : public mozilla::Conditional<!Cancelable,
354 mozilla::Runnable,
355 mozilla::CancelableRunnable>::Type
356 {
357 public:
358 virtual void Revoke() = 0;
359
360 // These ReturnTypeEnforcer classes set up a blacklist for return types that
361 // we know are not safe. The default ReturnTypeEnforcer compiles just fine but
362 // already_AddRefed will not.
363 template<typename OtherReturnType>
364 class ReturnTypeEnforcer
365 {
366 public:
367 typedef int ReturnTypeIsSafe;
368 };
369
370 template<class T>
371 class ReturnTypeEnforcer<already_AddRefed<T>>
372 {
373 // No ReturnTypeIsSafe makes this illegal!
374 };
375
376 // Make sure this return type is safe.
377 typedef typename ReturnTypeEnforcer<ReturnType>::ReturnTypeIsSafe check;
378 };
379
380 template<class ClassType, bool Owning>
381 struct nsRunnableMethodReceiver
382 {
383 RefPtr<ClassType> mObj;
nsRunnableMethodReceivernsRunnableMethodReceiver384 explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
~nsRunnableMethodReceivernsRunnableMethodReceiver385 ~nsRunnableMethodReceiver() { Revoke(); }
GetnsRunnableMethodReceiver386 ClassType* Get() const { return mObj.get(); }
RevokensRunnableMethodReceiver387 void Revoke() { mObj = nullptr; }
388 };
389
390 template<class ClassType>
391 struct nsRunnableMethodReceiver<ClassType, false>
392 {
393 ClassType* MOZ_NON_OWNING_REF mObj;
394 explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
395 ClassType* Get() const { return mObj; }
396 void Revoke() { mObj = nullptr; }
397 };
398
399 template<typename Method, bool Owning, bool Cancelable> struct nsRunnableMethodTraits;
400
401 template<class C, typename R, bool Owning, bool Cancelable, typename... As>
402 struct nsRunnableMethodTraits<R(C::*)(As...), Owning, Cancelable>
403 {
404 typedef C class_type;
405 typedef R return_type;
406 typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
407 static const bool can_cancel = Cancelable;
408 };
409
410 template<class C, typename R, bool Owning, bool Cancelable, typename... As>
411 struct nsRunnableMethodTraits<R(C::*)(As...) const, Owning, Cancelable>
412 {
413 typedef const C class_type;
414 typedef R return_type;
415 typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
416 static const bool can_cancel = Cancelable;
417 };
418
419 #ifdef NS_HAVE_STDCALL
420 template<class C, typename R, bool Owning, bool Cancelable, typename... As>
421 struct nsRunnableMethodTraits<R(__stdcall C::*)(As...), Owning, Cancelable>
422 {
423 typedef C class_type;
424 typedef R return_type;
425 typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
426 static const bool can_cancel = Cancelable;
427 };
428
429 template<class C, typename R, bool Owning, bool Cancelable>
430 struct nsRunnableMethodTraits<R(NS_STDCALL C::*)(), Owning, Cancelable>
431 {
432 typedef C class_type;
433 typedef R return_type;
434 typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
435 static const bool can_cancel = Cancelable;
436 };
437 template<class C, typename R, bool Owning, bool Cancelable, typename... As>
438 struct nsRunnableMethodTraits<R(__stdcall C::*)(As...) const, Owning, Cancelable>
439 {
440 typedef const C class_type;
441 typedef R return_type;
442 typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
443 static const bool can_cancel = Cancelable;
444 };
445
446 template<class C, typename R, bool Owning, bool Cancelable>
447 struct nsRunnableMethodTraits<R(NS_STDCALL C::*)() const, Owning, Cancelable>
448 {
449 typedef const C class_type;
450 typedef R return_type;
451 typedef nsRunnableMethod<C, R, Owning, Cancelable> base_type;
452 static const bool can_cancel = Cancelable;
453 };
454 #endif
455
456
457 // IsParameterStorageClass<T>::value is true if T is a parameter-storage class
458 // that will be recognized by NS_New[NonOwning]RunnableMethodWithArg[s] to
459 // force a specific storage&passing strategy (instead of inferring one,
460 // see ParameterStorage).
461 // When creating a new storage class, add a specialization for it to be
462 // recognized.
463 template<typename T>
464 struct IsParameterStorageClass : public mozilla::FalseType {};
465
466 // StoreXPassByY structs used to inform nsRunnableMethodArguments how to
467 // store arguments, and how to pass them to the target method.
468
469 template<typename T>
470 struct StoreCopyPassByValue
471 {
472 typedef T stored_type;
473 typedef T passed_type;
474 stored_type m;
475 template <typename A>
476 MOZ_IMPLICIT StoreCopyPassByValue(A&& a) : m(mozilla::Forward<A>(a)) {}
477 passed_type PassAsParameter() { return m; }
478 };
479 template<typename S>
480 struct IsParameterStorageClass<StoreCopyPassByValue<S>>
481 : public mozilla::TrueType {};
482
483 template<typename T>
484 struct StoreCopyPassByConstLRef
485 {
486 typedef T stored_type;
487 typedef const T& passed_type;
488 stored_type m;
489 template <typename A>
490 MOZ_IMPLICIT StoreCopyPassByConstLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
491 passed_type PassAsParameter() { return m; }
492 };
493 template<typename S>
494 struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>>
495 : public mozilla::TrueType {};
496
497 template<typename T>
498 struct StoreCopyPassByLRef
499 {
500 typedef T stored_type;
501 typedef T& passed_type;
502 stored_type m;
503 template <typename A>
504 MOZ_IMPLICIT StoreCopyPassByLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
505 passed_type PassAsParameter() { return m; }
506 };
507 template<typename S>
508 struct IsParameterStorageClass<StoreCopyPassByLRef<S>>
509 : public mozilla::TrueType {};
510
511 template<typename T>
512 struct StoreCopyPassByRRef
513 {
514 typedef T stored_type;
515 typedef T&& passed_type;
516 stored_type m;
517 template <typename A>
518 MOZ_IMPLICIT StoreCopyPassByRRef(A&& a) : m(mozilla::Forward<A>(a)) {}
519 passed_type PassAsParameter() { return mozilla::Move(m); }
520 };
521 template<typename S>
522 struct IsParameterStorageClass<StoreCopyPassByRRef<S>>
523 : public mozilla::TrueType {};
524
525 template<typename T>
526 struct StoreRefPassByLRef
527 {
528 typedef T& stored_type;
529 typedef T& passed_type;
530 stored_type m;
531 template <typename A>
532 MOZ_IMPLICIT StoreRefPassByLRef(A& a) : m(a) {}
533 passed_type PassAsParameter() { return m; }
534 };
535 template<typename S>
536 struct IsParameterStorageClass<StoreRefPassByLRef<S>>
537 : public mozilla::TrueType {};
538
539 template<typename T>
540 struct StoreConstRefPassByConstLRef
541 {
542 typedef const T& stored_type;
543 typedef const T& passed_type;
544 stored_type m;
545 template <typename A>
546 MOZ_IMPLICIT StoreConstRefPassByConstLRef(const A& a) : m(a) {}
547 passed_type PassAsParameter() { return m; }
548 };
549 template<typename S>
550 struct IsParameterStorageClass<StoreConstRefPassByConstLRef<S>>
551 : public mozilla::TrueType {};
552
553 template<typename T>
554 struct StorensRefPtrPassByPtr
555 {
556 typedef RefPtr<T> stored_type;
557 typedef T* passed_type;
558 stored_type m;
559 template <typename A>
560 MOZ_IMPLICIT StorensRefPtrPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
561 passed_type PassAsParameter() { return m.get(); }
562 };
563 template<typename S>
564 struct IsParameterStorageClass<StorensRefPtrPassByPtr<S>>
565 : public mozilla::TrueType {};
566
567 template<typename T>
568 struct StorePtrPassByPtr
569 {
570 typedef T* stored_type;
571 typedef T* passed_type;
572 stored_type m;
573 template <typename A>
574 MOZ_IMPLICIT StorePtrPassByPtr(A a) : m(a) {}
575 passed_type PassAsParameter() { return m; }
576 };
577 template<typename S>
578 struct IsParameterStorageClass<StorePtrPassByPtr<S>>
579 : public mozilla::TrueType {};
580
581 template<typename T>
582 struct StoreConstPtrPassByConstPtr
583 {
584 typedef const T* stored_type;
585 typedef const T* passed_type;
586 stored_type m;
587 template <typename A>
588 MOZ_IMPLICIT StoreConstPtrPassByConstPtr(A a) : m(a) {}
589 passed_type PassAsParameter() { return m; }
590 };
591 template<typename S>
592 struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>>
593 : public mozilla::TrueType {};
594
595 template<typename T>
596 struct StoreCopyPassByConstPtr
597 {
598 typedef T stored_type;
599 typedef const T* passed_type;
600 stored_type m;
601 template <typename A>
602 MOZ_IMPLICIT StoreCopyPassByConstPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
603 passed_type PassAsParameter() { return &m; }
604 };
605 template<typename S>
606 struct IsParameterStorageClass<StoreCopyPassByConstPtr<S>>
607 : public mozilla::TrueType {};
608
609 template<typename T>
610 struct StoreCopyPassByPtr
611 {
612 typedef T stored_type;
613 typedef T* passed_type;
614 stored_type m;
615 template <typename A>
616 MOZ_IMPLICIT StoreCopyPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
617 passed_type PassAsParameter() { return &m; }
618 };
619 template<typename S>
620 struct IsParameterStorageClass<StoreCopyPassByPtr<S>>
621 : public mozilla::TrueType {};
622
623 namespace detail {
624
625 template<typename TWithoutPointer>
626 struct NonnsISupportsPointerStorageClass
627 : mozilla::Conditional<mozilla::IsConst<TWithoutPointer>::value,
628 StoreConstPtrPassByConstPtr<
629 typename mozilla::RemoveConst<TWithoutPointer>::Type>,
630 StorePtrPassByPtr<TWithoutPointer>>
631 {};
632
633 template<typename>
634 struct SFINAE1True : mozilla::TrueType
635 {};
636
637 template<class T>
638 static auto HasRefCountMethodsTest(int)
639 -> SFINAE1True<decltype(mozilla::DeclVal<T>().AddRef(),
640 mozilla::DeclVal<T>().Release())>;
641 template<class>
642 static auto HasRefCountMethodsTest(long) -> mozilla::FalseType;
643
644 template<class T>
645 struct HasRefCountMethods : decltype(HasRefCountMethodsTest<T>(0))
646 {};
647
648 template<typename T>
649 struct IsRefcountedSmartPointer : public mozilla::FalseType
650 {};
651
652 template<typename T>
653 struct IsRefcountedSmartPointer<RefPtr<T>> : public mozilla::TrueType
654 {};
655
656 template<typename T>
657 struct IsRefcountedSmartPointer<nsCOMPtr<T>> : public mozilla::TrueType
658 {};
659
660 template<typename T>
661 struct StripSmartPointer
662 {
663 typedef void Type;
664 };
665
666 template<typename T>
667 struct StripSmartPointer<RefPtr<T>>
668 {
669 typedef T Type;
670 };
671
672 template<typename T>
673 struct StripSmartPointer<nsCOMPtr<T>>
674 {
675 typedef T Type;
676 };
677
678 template<typename TWithoutPointer>
679 struct PointerStorageClass
680 : mozilla::Conditional<HasRefCountMethods<TWithoutPointer>::value,
681 StorensRefPtrPassByPtr<TWithoutPointer>,
682 typename NonnsISupportsPointerStorageClass<
683 TWithoutPointer
684 >::Type>
685 {};
686
687 template<typename TWithoutRef>
688 struct LValueReferenceStorageClass
689 : mozilla::Conditional<mozilla::IsConst<TWithoutRef>::value,
690 StoreConstRefPassByConstLRef<
691 typename mozilla::RemoveConst<TWithoutRef>::Type>,
692 StoreRefPassByLRef<TWithoutRef>>
693 {};
694
695 template<typename T>
696 struct SmartPointerStorageClass
697 : mozilla::Conditional<IsRefcountedSmartPointer<T>::value,
698 StorensRefPtrPassByPtr<
699 typename StripSmartPointer<T>::Type>,
700 StoreCopyPassByValue<T>>
701 {};
702
703 template<typename T>
704 struct NonLValueReferenceStorageClass
705 : mozilla::Conditional<mozilla::IsRvalueReference<T>::value,
706 StoreCopyPassByRRef<
707 typename mozilla::RemoveReference<T>::Type>,
708 typename SmartPointerStorageClass<T>::Type>
709 {};
710
711 template<typename T>
712 struct NonPointerStorageClass
713 : mozilla::Conditional<mozilla::IsLvalueReference<T>::value,
714 typename LValueReferenceStorageClass<
715 typename mozilla::RemoveReference<T>::Type
716 >::Type,
717 typename NonLValueReferenceStorageClass<T>::Type>
718 {};
719
720 template<typename T>
721 struct NonParameterStorageClass
722 : mozilla::Conditional<mozilla::IsPointer<T>::value,
723 typename PointerStorageClass<
724 typename mozilla::RemovePointer<T>::Type
725 >::Type,
726 typename NonPointerStorageClass<T>::Type>
727 {};
728
729 // Choose storage&passing strategy based on preferred storage type:
730 // - If IsParameterStorageClass<T>::value is true, use as-is.
731 // - RC* -> StorensRefPtrPassByPtr<RC> : Store RefPtr<RC>, pass RC*
732 // ^^ RC quacks like a ref-counted type (i.e., has AddRef and Release methods)
733 // - const T* -> StoreConstPtrPassByConstPtr<T> : Store const T*, pass const T*
734 // - T* -> StorePtrPassByPtr<T> : Store T*, pass T*.
735 // - const T& -> StoreConstRefPassByConstLRef<T>: Store const T&, pass const T&.
736 // - T& -> StoreRefPassByLRef<T> : Store T&, pass T&.
737 // - T&& -> StoreCopyPassByRRef<T> : Store T, pass Move(T).
738 // - RefPtr<T>, nsCOMPtr<T>
739 // -> StorensRefPtrPassByPtr<T> : Store RefPtr<T>, pass T*
740 // - Other T -> StoreCopyPassByValue<T> : Store T, pass T.
741 // Other available explicit options:
742 // - StoreCopyPassByConstLRef<T> : Store T, pass const T&.
743 // - StoreCopyPassByLRef<T> : Store T, pass T& (of copy!)
744 // - StoreCopyPassByConstPtr<T> : Store T, pass const T*
745 // - StoreCopyPassByPtr<T> : Store T, pass T* (of copy!)
746 // Or create your own class with PassAsParameter() method, optional
747 // clean-up in destructor, and with associated IsParameterStorageClass<>.
748 template<typename T>
749 struct ParameterStorage
750 : mozilla::Conditional<IsParameterStorageClass<T>::value,
751 T,
752 typename NonParameterStorageClass<T>::Type>
753 {};
754
755 } /* namespace detail */
756
757 namespace mozilla {
758
759 namespace detail {
760
761 // struct used to store arguments and later apply them to a method.
762 template <typename... Ts>
763 struct RunnableMethodArguments final
764 {
765 Tuple<typename ::detail::ParameterStorage<Ts>::Type...> mArguments;
766 template <typename... As>
767 explicit RunnableMethodArguments(As&&... aArguments)
768 : mArguments(Forward<As>(aArguments)...)
769 {}
770 template<typename C, typename M, typename... Args, size_t... Indices>
771 static auto
772 applyImpl(C* o, M m, Tuple<Args...>& args, IndexSequence<Indices...>)
773 -> decltype(((*o).*m)(Get<Indices>(args).PassAsParameter()...))
774 {
775 return ((*o).*m)(Get<Indices>(args).PassAsParameter()...);
776 }
777 template<class C, typename M> auto apply(C* o, M m)
778 -> decltype(applyImpl(o, m, mArguments,
779 typename IndexSequenceFor<Ts...>::Type()))
780 {
781 return applyImpl(o, m, mArguments,
782 typename IndexSequenceFor<Ts...>::Type());
783 }
784 };
785
786 template<typename Method, bool Owning, bool Cancelable, typename... Storages>
787 class RunnableMethodImpl final
788 : public ::nsRunnableMethodTraits<Method, Owning, Cancelable>::base_type
789 {
790 typedef typename ::nsRunnableMethodTraits<Method, Owning, Cancelable>::class_type
791 ClassType;
792 ::nsRunnableMethodReceiver<ClassType, Owning> mReceiver;
793 Method mMethod;
794 RunnableMethodArguments<Storages...> mArgs;
795 private:
796 virtual ~RunnableMethodImpl() { Revoke(); };
797 public:
798 template<typename... Args>
799 explicit RunnableMethodImpl(ClassType* aObj, Method aMethod,
800 Args&&... aArgs)
801 : mReceiver(aObj)
802 , mMethod(aMethod)
803 , mArgs(Forward<Args>(aArgs)...)
804 {
805 static_assert(sizeof...(Storages) == sizeof...(Args), "Storages and Args should have equal sizes");
806 }
807 NS_IMETHOD Run()
808 {
809 if (MOZ_LIKELY(mReceiver.Get())) {
810 mArgs.apply(mReceiver.Get(), mMethod);
811 }
812 return NS_OK;
813 }
814 nsresult Cancel() {
815 static_assert(Cancelable, "Don't use me!");
816 Revoke();
817 return NS_OK;
818 }
819 void Revoke() { mReceiver.Revoke(); }
820 };
821
822 } // namespace detail
823
824 // Use this template function like so:
825 //
826 // nsCOMPtr<nsIRunnable> event =
827 // mozilla::NewRunnableMethod(myObject, &MyClass::HandleEvent);
828 // NS_DispatchToCurrentThread(event);
829 //
830 // Statically enforced constraints:
831 // - myObject must be of (or implicitly convertible to) type MyClass
832 // - MyClass must define AddRef and Release methods
833 //
834
835 template<typename PtrType, typename Method>
836 already_AddRefed<typename ::nsRunnableMethodTraits<Method, true, false>::base_type>
837 NewRunnableMethod(PtrType aPtr, Method aMethod)
838 {
839 return do_AddRef(new detail::RunnableMethodImpl<Method, true, false>(aPtr, aMethod));
840 }
841
842 template<typename PtrType, typename Method>
843 already_AddRefed<typename ::nsRunnableMethodTraits<Method, true, true>::base_type>
844 NewCancelableRunnableMethod(PtrType aPtr, Method aMethod)
845 {
846 return do_AddRef(new detail::RunnableMethodImpl<Method, true, true>(aPtr, aMethod));
847 }
848
849 template<typename PtrType, typename Method>
850 already_AddRefed<typename ::nsRunnableMethodTraits<Method, false, false>::base_type>
851 NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod)
852 {
853 return do_AddRef(new detail::RunnableMethodImpl<Method, false, false>(aPtr, aMethod));
854 }
855
856 template<typename PtrType, typename Method>
857 already_AddRefed<typename ::nsRunnableMethodTraits<Method, false, true>::base_type>
858 NewNonOwningCancelableRunnableMethod(PtrType&& aPtr, Method aMethod)
859 {
860 return do_AddRef(new detail::RunnableMethodImpl<Method, false, true>(aPtr, aMethod));
861 }
862
863 // Similar to NewRunnableMethod. Call like so:
864 // nsCOMPtr<nsIRunnable> event =
865 // NewRunnableMethod<Types,...>(myObject, &MyClass::HandleEvent, myArg1,...);
866 // 'Types' are the stored type for each argument, see ParameterStorage for details.
867 template<typename... Storages, typename Method, typename PtrType, typename... Args>
868 already_AddRefed<typename ::nsRunnableMethodTraits<Method, true, false>::base_type>
869 NewRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs)
870 {
871 static_assert(sizeof...(Storages) == sizeof...(Args),
872 "<Storages...> size should be equal to number of arguments");
873 return do_AddRef(new detail::RunnableMethodImpl<Method, true, false, Storages...>(
874 aPtr, aMethod, mozilla::Forward<Args>(aArgs)...));
875 }
876
877 template<typename... Storages, typename Method, typename PtrType, typename... Args>
878 already_AddRefed<typename ::nsRunnableMethodTraits<Method, false, false>::base_type>
879 NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs)
880 {
881 static_assert(sizeof...(Storages) == sizeof...(Args),
882 "<Storages...> size should be equal to number of arguments");
883 return do_AddRef(new detail::RunnableMethodImpl<Method, false, false, Storages...>(
884 aPtr, aMethod, mozilla::Forward<Args>(aArgs)...));
885 }
886
887 template<typename... Storages, typename Method, typename PtrType, typename... Args>
888 already_AddRefed<typename ::nsRunnableMethodTraits<Method, true, true>::base_type>
889 NewCancelableRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs)
890 {
891 static_assert(sizeof...(Storages) == sizeof...(Args),
892 "<Storages...> size should be equal to number of arguments");
893 return do_AddRef(new detail::RunnableMethodImpl<Method, true, true, Storages...>(
894 aPtr, aMethod, mozilla::Forward<Args>(aArgs)...));
895 }
896
897 template<typename... Storages, typename Method, typename PtrType, typename... Args>
898 already_AddRefed<typename ::nsRunnableMethodTraits<Method, false, true>::base_type>
899 NewNonOwningCancelableRunnableMethod(PtrType&& aPtr, Method aMethod,
900 Args&&... aArgs)
901 {
902 static_assert(sizeof...(Storages) == sizeof...(Args),
903 "<Storages...> size should be equal to number of arguments");
904 return do_AddRef(new detail::RunnableMethodImpl<Method, false, true, Storages...>(
905 aPtr, aMethod, mozilla::Forward<Args>(aArgs)...));
906 }
907
908 } // namespace mozilla
909
910 #endif // XPCOM_GLUE_AVOID_NSPR
911
912 // This class is designed to be used when you have an event class E that has a
913 // pointer back to resource class R. If R goes away while E is still pending,
914 // then it is important to "revoke" E so that it does not try use R after R has
915 // been destroyed. nsRevocableEventPtr makes it easy for R to manage such
916 // situations:
917 //
918 // class R;
919 //
920 // class E : public mozilla::Runnable {
921 // public:
922 // void Revoke() {
923 // mResource = nullptr;
924 // }
925 // private:
926 // R *mResource;
927 // };
928 //
929 // class R {
930 // public:
931 // void EventHandled() {
932 // mEvent.Forget();
933 // }
934 // private:
935 // nsRevocableEventPtr<E> mEvent;
936 // };
937 //
938 // void R::PostEvent() {
939 // // Make sure any pending event is revoked.
940 // mEvent->Revoke();
941 //
942 // nsCOMPtr<nsIRunnable> event = new E();
943 // if (NS_SUCCEEDED(NS_DispatchToCurrentThread(event))) {
944 // // Keep pointer to event so we can revoke it.
945 // mEvent = event;
946 // }
947 // }
948 //
949 // NS_IMETHODIMP E::Run() {
950 // if (!mResource)
951 // return NS_OK;
952 // ...
953 // mResource->EventHandled();
954 // return NS_OK;
955 // }
956 //
957 template<class T>
958 class nsRevocableEventPtr
959 {
960 public:
961 nsRevocableEventPtr() : mEvent(nullptr) {}
962 ~nsRevocableEventPtr() { Revoke(); }
963
964 const nsRevocableEventPtr& operator=(T* aEvent)
965 {
966 if (mEvent != aEvent) {
967 Revoke();
968 mEvent = aEvent;
969 }
970 return *this;
971 }
972
973 const nsRevocableEventPtr& operator=(already_AddRefed<T> aEvent)
974 {
975 RefPtr<T> event = aEvent;
976 if (mEvent != event) {
977 Revoke();
978 mEvent = event.forget();
979 }
980 return *this;
981 }
982
983 void Revoke()
984 {
985 if (mEvent) {
986 mEvent->Revoke();
987 mEvent = nullptr;
988 }
989 }
990
991 void Forget() { mEvent = nullptr; }
992 bool IsPending() { return mEvent != nullptr; }
993 T* get() { return mEvent; }
994
995 private:
996 // Not implemented
997 nsRevocableEventPtr(const nsRevocableEventPtr&);
998 nsRevocableEventPtr& operator=(const nsRevocableEventPtr&);
999
1000 RefPtr<T> mEvent;
1001 };
1002
1003 /**
1004 * A simple helper to suffix thread pool name
1005 * with incremental numbers.
1006 */
1007 class nsThreadPoolNaming
1008 {
1009 public:
1010 nsThreadPoolNaming() : mCounter(0) {}
1011
1012 /**
1013 * Creates and sets next thread name as "<aPoolName> #<n>"
1014 * on the specified thread. If no thread is specified (aThread
1015 * is null) then the name is synchronously set on the current thread.
1016 */
1017 void SetThreadPoolName(const nsACString& aPoolName,
1018 nsIThread* aThread = nullptr);
1019
1020 private:
1021 mozilla::Atomic<uint32_t> mCounter;
1022
1023 nsThreadPoolNaming(const nsThreadPoolNaming&) = delete;
1024 void operator=(const nsThreadPoolNaming&) = delete;
1025 };
1026
1027 /**
1028 * Thread priority in most operating systems affect scheduling, not IO. This
1029 * helper is used to set the current thread to low IO priority for the lifetime
1030 * of the created object. You can only use this low priority IO setting within
1031 * the context of the current thread.
1032 */
1033 class MOZ_STACK_CLASS nsAutoLowPriorityIO
1034 {
1035 public:
1036 nsAutoLowPriorityIO();
1037 ~nsAutoLowPriorityIO();
1038
1039 private:
1040 bool lowIOPrioritySet;
1041 #if defined(XP_MACOSX)
1042 int oldPriority;
1043 #endif
1044 };
1045
1046 void
1047 NS_SetMainThread();
1048
1049 #endif // nsThreadUtils_h__
1050