From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- xpcom/glue/nsThreadUtils.h | 1049 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1049 insertions(+) create mode 100644 xpcom/glue/nsThreadUtils.h (limited to 'xpcom/glue/nsThreadUtils.h') diff --git a/xpcom/glue/nsThreadUtils.h b/xpcom/glue/nsThreadUtils.h new file mode 100644 index 000000000..cbd7f7842 --- /dev/null +++ b/xpcom/glue/nsThreadUtils.h @@ -0,0 +1,1049 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsThreadUtils_h__ +#define nsThreadUtils_h__ + +#include "prthread.h" +#include "prinrval.h" +#include "MainThreadUtils.h" +#include "nsIThreadManager.h" +#include "nsIThread.h" +#include "nsIRunnable.h" +#include "nsICancelableRunnable.h" +#include "nsIIdlePeriod.h" +#include "nsIIncrementalRunnable.h" +#include "nsStringGlue.h" +#include "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "mozilla/Atomics.h" +#include "mozilla/IndexSequence.h" +#include "mozilla/Likely.h" +#include "mozilla/Move.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/Tuple.h" +#include "mozilla/TypeTraits.h" + +//----------------------------------------------------------------------------- +// These methods are alternatives to the methods on nsIThreadManager, provided +// for convenience. + +/** + * Set name of the target thread. This operation is asynchronous. + */ +extern void NS_SetThreadName(nsIThread* aThread, const nsACString& aName); + +/** + * Static length version of the above function checking length of the + * name at compile time. + */ +template +inline void +NS_SetThreadName(nsIThread* aThread, const char (&aName)[LEN]) +{ + static_assert(LEN <= 16, + "Thread name must be no more than 16 characters"); + NS_SetThreadName(aThread, nsDependentCString(aName)); +} + +/** + * Create a new thread, and optionally provide an initial event for the thread. + * + * @param aResult + * The resulting nsIThread object. + * @param aInitialEvent + * The initial event to run on this thread. This parameter may be null. + * @param aStackSize + * The size in bytes to reserve for the thread's stack. + * + * @returns NS_ERROR_INVALID_ARG + * Indicates that the given name is not unique. + */ +extern nsresult +NS_NewThread(nsIThread** aResult, + nsIRunnable* aInitialEvent = nullptr, + uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE); + +/** + * Creates a named thread, otherwise the same as NS_NewThread + */ +template +inline nsresult +NS_NewNamedThread(const char (&aName)[LEN], + nsIThread** aResult, + nsIRunnable* aInitialEvent = nullptr, + uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE) +{ + // Hold a ref while dispatching the initial event to match NS_NewThread() + nsCOMPtr thread; + nsresult rv = NS_NewThread(getter_AddRefs(thread), nullptr, aStackSize); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + NS_SetThreadName(thread, aName); + if (aInitialEvent) { + rv = thread->Dispatch(aInitialEvent, NS_DISPATCH_NORMAL); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Initial event dispatch failed"); + } + + *aResult = nullptr; + thread.swap(*aResult); + return rv; +} + +/** + * Get a reference to the current thread. + * + * @param aResult + * The resulting nsIThread object. + */ +extern nsresult NS_GetCurrentThread(nsIThread** aResult); + +/** + * Dispatch the given event to the current thread. + * + * @param aEvent + * The event to dispatch. + * + * @returns NS_ERROR_INVALID_ARG + * If event is null. + */ +extern nsresult NS_DispatchToCurrentThread(nsIRunnable* aEvent); +extern nsresult +NS_DispatchToCurrentThread(already_AddRefed&& aEvent); + +/** + * Dispatch the given event to the main thread. + * + * @param aEvent + * The event to dispatch. + * @param aDispatchFlags + * The flags to pass to the main thread's dispatch method. + * + * @returns NS_ERROR_INVALID_ARG + * If event is null. + */ +extern nsresult +NS_DispatchToMainThread(nsIRunnable* aEvent, + uint32_t aDispatchFlags = NS_DISPATCH_NORMAL); +extern nsresult +NS_DispatchToMainThread(already_AddRefed&& aEvent, + uint32_t aDispatchFlags = NS_DISPATCH_NORMAL); + +extern nsresult +NS_DelayedDispatchToCurrentThread( + already_AddRefed&& aEvent, uint32_t aDelayMs); + +extern nsresult +NS_IdleDispatchToCurrentThread(already_AddRefed&& aEvent); + +#ifndef XPCOM_GLUE_AVOID_NSPR +/** + * Process all pending events for the given thread before returning. This + * method simply calls ProcessNextEvent on the thread while HasPendingEvents + * continues to return true and the time spent in NS_ProcessPendingEvents + * does not exceed the given timeout value. + * + * @param aThread + * The thread object for which to process pending events. If null, then + * events will be processed for the current thread. + * @param aTimeout + * The maximum number of milliseconds to spend processing pending events. + * Events are not pre-empted to honor this timeout. Rather, the timeout + * value is simply used to determine whether or not to process another event. + * Pass PR_INTERVAL_NO_TIMEOUT to specify no timeout. + */ +extern nsresult +NS_ProcessPendingEvents(nsIThread* aThread, + PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT); +#endif + +/** + * Shortcut for nsIThread::HasPendingEvents. + * + * It is an error to call this function when the given thread is not the + * current thread. This function will return false if called from some + * other thread. + * + * @param aThread + * The current thread or null. + * + * @returns + * A boolean value that if "true" indicates that there are pending events + * in the current thread's event queue. + */ +extern bool NS_HasPendingEvents(nsIThread* aThread = nullptr); + +/** + * Shortcut for nsIThread::ProcessNextEvent. + * + * It is an error to call this function when the given thread is not the + * current thread. This function will simply return false if called + * from some other thread. + * + * @param aThread + * The current thread or null. + * @param aMayWait + * A boolean parameter that if "true" indicates that the method may block + * the calling thread to wait for a pending event. + * + * @returns + * A boolean value that if "true" indicates that an event from the current + * thread's event queue was processed. + */ +extern bool NS_ProcessNextEvent(nsIThread* aThread = nullptr, + bool aMayWait = true); + +//----------------------------------------------------------------------------- +// Helpers that work with nsCOMPtr: + +inline already_AddRefed +do_GetCurrentThread() +{ + nsIThread* thread = nullptr; + NS_GetCurrentThread(&thread); + return already_AddRefed(thread); +} + +inline already_AddRefed +do_GetMainThread() +{ + nsIThread* thread = nullptr; + NS_GetMainThread(&thread); + return already_AddRefed(thread); +} + +//----------------------------------------------------------------------------- + +#ifdef MOZILLA_INTERNAL_API +// Fast access to the current thread. Do not release the returned pointer! If +// you want to use this pointer from some other thread, then you will need to +// AddRef it. Otherwise, you should only consider this pointer valid from code +// running on the current thread. +extern nsIThread* NS_GetCurrentThread(); +#endif + +//----------------------------------------------------------------------------- + +#ifndef XPCOM_GLUE_AVOID_NSPR + +namespace mozilla { + +// This class is designed to be subclassed. +class IdlePeriod : public nsIIdlePeriod +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIIDLEPERIOD + + IdlePeriod() {} + +protected: + virtual ~IdlePeriod() {} +private: + IdlePeriod(const IdlePeriod&) = delete; + IdlePeriod& operator=(const IdlePeriod&) = delete; + IdlePeriod& operator=(const IdlePeriod&&) = delete; +}; + +// This class is designed to be subclassed. +class Runnable : public nsIRunnable +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIRUNNABLE + + Runnable() {} + +protected: + virtual ~Runnable() {} +private: + Runnable(const Runnable&) = delete; + Runnable& operator=(const Runnable&) = delete; + Runnable& operator=(const Runnable&&) = delete; +}; + +// This class is designed to be subclassed. +class CancelableRunnable : public Runnable, + public nsICancelableRunnable +{ +public: + NS_DECL_ISUPPORTS_INHERITED + // nsICancelableRunnable + virtual nsresult Cancel() override; + + CancelableRunnable() {} + +protected: + virtual ~CancelableRunnable() {} +private: + CancelableRunnable(const CancelableRunnable&) = delete; + CancelableRunnable& operator=(const CancelableRunnable&) = delete; + CancelableRunnable& operator=(const CancelableRunnable&&) = delete; +}; + +// This class is designed to be subclassed. +class IncrementalRunnable : public CancelableRunnable, + public nsIIncrementalRunnable +{ +public: + NS_DECL_ISUPPORTS_INHERITED + // nsIIncrementalRunnable + virtual void SetDeadline(TimeStamp aDeadline) override; + + IncrementalRunnable() {} + +protected: + virtual ~IncrementalRunnable() {} +private: + IncrementalRunnable(const IncrementalRunnable&) = delete; + IncrementalRunnable& operator=(const IncrementalRunnable&) = delete; + IncrementalRunnable& operator=(const IncrementalRunnable&&) = delete; +}; + +namespace detail { + +// An event that can be used to call a C++11 functions or function objects, +// including lambdas. The function must have no required arguments, and must +// return void. +template +class RunnableFunction : public Runnable +{ +public: + template + explicit RunnableFunction(F&& aFunction) + : mFunction(Forward(aFunction)) + { } + + NS_IMETHOD Run() override { + static_assert(IsVoid::value, + "The lambda must return void!"); + mFunction(); + return NS_OK; + } +private: + StoredFunction mFunction; +}; + +} // namespace detail + +} // namespace mozilla + +template +already_AddRefed +NS_NewRunnableFunction(Function&& aFunction) +{ + return do_AddRef(new mozilla::detail::RunnableFunction + // Make sure we store a non-reference in nsRunnableFunction. + ::Type> + // But still forward aFunction to move if possible. + (mozilla::Forward(aFunction))); +} + +// An event that can be used to call a method on a class. The class type must +// support reference counting. This event supports Revoke for use +// with nsRevocableEventPtr. +template +class nsRunnableMethod : public mozilla::Conditional::Type +{ +public: + virtual void Revoke() = 0; + + // These ReturnTypeEnforcer classes set up a blacklist for return types that + // we know are not safe. The default ReturnTypeEnforcer compiles just fine but + // already_AddRefed will not. + template + class ReturnTypeEnforcer + { + public: + typedef int ReturnTypeIsSafe; + }; + + template + class ReturnTypeEnforcer> + { + // No ReturnTypeIsSafe makes this illegal! + }; + + // Make sure this return type is safe. + typedef typename ReturnTypeEnforcer::ReturnTypeIsSafe check; +}; + +template +struct nsRunnableMethodReceiver +{ + RefPtr mObj; + explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {} + ~nsRunnableMethodReceiver() { Revoke(); } + ClassType* Get() const { return mObj.get(); } + void Revoke() { mObj = nullptr; } +}; + +template +struct nsRunnableMethodReceiver +{ + ClassType* MOZ_NON_OWNING_REF mObj; + explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {} + ClassType* Get() const { return mObj; } + void Revoke() { mObj = nullptr; } +}; + +template struct nsRunnableMethodTraits; + +template +struct nsRunnableMethodTraits +{ + typedef C class_type; + typedef R return_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; +}; + +template +struct nsRunnableMethodTraits +{ + typedef const C class_type; + typedef R return_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; +}; + +#ifdef NS_HAVE_STDCALL +template +struct nsRunnableMethodTraits +{ + typedef C class_type; + typedef R return_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; +}; + +template +struct nsRunnableMethodTraits +{ + typedef C class_type; + typedef R return_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; +}; +template +struct nsRunnableMethodTraits +{ + typedef const C class_type; + typedef R return_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; +}; + +template +struct nsRunnableMethodTraits +{ + typedef const C class_type; + typedef R return_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; +}; +#endif + + +// IsParameterStorageClass::value is true if T is a parameter-storage class +// that will be recognized by NS_New[NonOwning]RunnableMethodWithArg[s] to +// force a specific storage&passing strategy (instead of inferring one, +// see ParameterStorage). +// When creating a new storage class, add a specialization for it to be +// recognized. +template +struct IsParameterStorageClass : public mozilla::FalseType {}; + +// StoreXPassByY structs used to inform nsRunnableMethodArguments how to +// store arguments, and how to pass them to the target method. + +template +struct StoreCopyPassByValue +{ + typedef T stored_type; + typedef T passed_type; + stored_type m; + template + MOZ_IMPLICIT StoreCopyPassByValue(A&& a) : m(mozilla::Forward(a)) {} + passed_type PassAsParameter() { return m; } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StoreCopyPassByConstLRef +{ + typedef T stored_type; + typedef const T& passed_type; + stored_type m; + template + MOZ_IMPLICIT StoreCopyPassByConstLRef(A&& a) : m(mozilla::Forward(a)) {} + passed_type PassAsParameter() { return m; } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StoreCopyPassByLRef +{ + typedef T stored_type; + typedef T& passed_type; + stored_type m; + template + MOZ_IMPLICIT StoreCopyPassByLRef(A&& a) : m(mozilla::Forward(a)) {} + passed_type PassAsParameter() { return m; } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StoreCopyPassByRRef +{ + typedef T stored_type; + typedef T&& passed_type; + stored_type m; + template + MOZ_IMPLICIT StoreCopyPassByRRef(A&& a) : m(mozilla::Forward(a)) {} + passed_type PassAsParameter() { return mozilla::Move(m); } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StoreRefPassByLRef +{ + typedef T& stored_type; + typedef T& passed_type; + stored_type m; + template + MOZ_IMPLICIT StoreRefPassByLRef(A& a) : m(a) {} + passed_type PassAsParameter() { return m; } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StoreConstRefPassByConstLRef +{ + typedef const T& stored_type; + typedef const T& passed_type; + stored_type m; + template + MOZ_IMPLICIT StoreConstRefPassByConstLRef(const A& a) : m(a) {} + passed_type PassAsParameter() { return m; } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StorensRefPtrPassByPtr +{ + typedef RefPtr stored_type; + typedef T* passed_type; + stored_type m; + template + MOZ_IMPLICIT StorensRefPtrPassByPtr(A&& a) : m(mozilla::Forward(a)) {} + passed_type PassAsParameter() { return m.get(); } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StorePtrPassByPtr +{ + typedef T* stored_type; + typedef T* passed_type; + stored_type m; + template + MOZ_IMPLICIT StorePtrPassByPtr(A a) : m(a) {} + passed_type PassAsParameter() { return m; } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StoreConstPtrPassByConstPtr +{ + typedef const T* stored_type; + typedef const T* passed_type; + stored_type m; + template + MOZ_IMPLICIT StoreConstPtrPassByConstPtr(A a) : m(a) {} + passed_type PassAsParameter() { return m; } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StoreCopyPassByConstPtr +{ + typedef T stored_type; + typedef const T* passed_type; + stored_type m; + template + MOZ_IMPLICIT StoreCopyPassByConstPtr(A&& a) : m(mozilla::Forward(a)) {} + passed_type PassAsParameter() { return &m; } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +template +struct StoreCopyPassByPtr +{ + typedef T stored_type; + typedef T* passed_type; + stored_type m; + template + MOZ_IMPLICIT StoreCopyPassByPtr(A&& a) : m(mozilla::Forward(a)) {} + passed_type PassAsParameter() { return &m; } +}; +template +struct IsParameterStorageClass> + : public mozilla::TrueType {}; + +namespace detail { + +template +struct NonnsISupportsPointerStorageClass + : mozilla::Conditional::value, + StoreConstPtrPassByConstPtr< + typename mozilla::RemoveConst::Type>, + StorePtrPassByPtr> +{}; + +template +struct SFINAE1True : mozilla::TrueType +{}; + +template +static auto HasRefCountMethodsTest(int) + -> SFINAE1True().AddRef(), + mozilla::DeclVal().Release())>; +template +static auto HasRefCountMethodsTest(long) -> mozilla::FalseType; + +template +struct HasRefCountMethods : decltype(HasRefCountMethodsTest(0)) +{}; + +template +struct IsRefcountedSmartPointer : public mozilla::FalseType +{}; + +template +struct IsRefcountedSmartPointer> : public mozilla::TrueType +{}; + +template +struct IsRefcountedSmartPointer> : public mozilla::TrueType +{}; + +template +struct StripSmartPointer +{ + typedef void Type; +}; + +template +struct StripSmartPointer> +{ + typedef T Type; +}; + +template +struct StripSmartPointer> +{ + typedef T Type; +}; + +template +struct PointerStorageClass + : mozilla::Conditional::value, + StorensRefPtrPassByPtr, + typename NonnsISupportsPointerStorageClass< + TWithoutPointer + >::Type> +{}; + +template +struct LValueReferenceStorageClass + : mozilla::Conditional::value, + StoreConstRefPassByConstLRef< + typename mozilla::RemoveConst::Type>, + StoreRefPassByLRef> +{}; + +template +struct SmartPointerStorageClass + : mozilla::Conditional::value, + StorensRefPtrPassByPtr< + typename StripSmartPointer::Type>, + StoreCopyPassByValue> +{}; + +template +struct NonLValueReferenceStorageClass + : mozilla::Conditional::value, + StoreCopyPassByRRef< + typename mozilla::RemoveReference::Type>, + typename SmartPointerStorageClass::Type> +{}; + +template +struct NonPointerStorageClass + : mozilla::Conditional::value, + typename LValueReferenceStorageClass< + typename mozilla::RemoveReference::Type + >::Type, + typename NonLValueReferenceStorageClass::Type> +{}; + +template +struct NonParameterStorageClass + : mozilla::Conditional::value, + typename PointerStorageClass< + typename mozilla::RemovePointer::Type + >::Type, + typename NonPointerStorageClass::Type> +{}; + +// Choose storage&passing strategy based on preferred storage type: +// - If IsParameterStorageClass::value is true, use as-is. +// - RC* -> StorensRefPtrPassByPtr : Store RefPtr, pass RC* +// ^^ RC quacks like a ref-counted type (i.e., has AddRef and Release methods) +// - const T* -> StoreConstPtrPassByConstPtr : Store const T*, pass const T* +// - T* -> StorePtrPassByPtr : Store T*, pass T*. +// - const T& -> StoreConstRefPassByConstLRef: Store const T&, pass const T&. +// - T& -> StoreRefPassByLRef : Store T&, pass T&. +// - T&& -> StoreCopyPassByRRef : Store T, pass Move(T). +// - RefPtr, nsCOMPtr +// -> StorensRefPtrPassByPtr : Store RefPtr, pass T* +// - Other T -> StoreCopyPassByValue : Store T, pass T. +// Other available explicit options: +// - StoreCopyPassByConstLRef : Store T, pass const T&. +// - StoreCopyPassByLRef : Store T, pass T& (of copy!) +// - StoreCopyPassByConstPtr : Store T, pass const T* +// - StoreCopyPassByPtr : Store T, pass T* (of copy!) +// Or create your own class with PassAsParameter() method, optional +// clean-up in destructor, and with associated IsParameterStorageClass<>. +template +struct ParameterStorage + : mozilla::Conditional::value, + T, + typename NonParameterStorageClass::Type> +{}; + +} /* namespace detail */ + +namespace mozilla { + +namespace detail { + +// struct used to store arguments and later apply them to a method. +template +struct RunnableMethodArguments final +{ + Tuple::Type...> mArguments; + template + explicit RunnableMethodArguments(As&&... aArguments) + : mArguments(Forward(aArguments)...) + {} + template + static auto + applyImpl(C* o, M m, Tuple& args, IndexSequence) + -> decltype(((*o).*m)(Get(args).PassAsParameter()...)) + { + return ((*o).*m)(Get(args).PassAsParameter()...); + } + template auto apply(C* o, M m) + -> decltype(applyImpl(o, m, mArguments, + typename IndexSequenceFor::Type())) + { + return applyImpl(o, m, mArguments, + typename IndexSequenceFor::Type()); + } +}; + +template +class RunnableMethodImpl final + : public ::nsRunnableMethodTraits::base_type +{ + typedef typename ::nsRunnableMethodTraits::class_type + ClassType; + ::nsRunnableMethodReceiver mReceiver; + Method mMethod; + RunnableMethodArguments mArgs; +private: + virtual ~RunnableMethodImpl() { Revoke(); }; +public: + template + explicit RunnableMethodImpl(ClassType* aObj, Method aMethod, + Args&&... aArgs) + : mReceiver(aObj) + , mMethod(aMethod) + , mArgs(Forward(aArgs)...) + { + static_assert(sizeof...(Storages) == sizeof...(Args), "Storages and Args should have equal sizes"); + } + NS_IMETHOD Run() + { + if (MOZ_LIKELY(mReceiver.Get())) { + mArgs.apply(mReceiver.Get(), mMethod); + } + return NS_OK; + } + nsresult Cancel() { + static_assert(Cancelable, "Don't use me!"); + Revoke(); + return NS_OK; + } + void Revoke() { mReceiver.Revoke(); } +}; + +} // namespace detail + +// Use this template function like so: +// +// nsCOMPtr event = +// mozilla::NewRunnableMethod(myObject, &MyClass::HandleEvent); +// NS_DispatchToCurrentThread(event); +// +// Statically enforced constraints: +// - myObject must be of (or implicitly convertible to) type MyClass +// - MyClass must define AddRef and Release methods +// + +template +already_AddRefed::base_type> +NewRunnableMethod(PtrType aPtr, Method aMethod) +{ + return do_AddRef(new detail::RunnableMethodImpl(aPtr, aMethod)); +} + +template +already_AddRefed::base_type> +NewCancelableRunnableMethod(PtrType aPtr, Method aMethod) +{ + return do_AddRef(new detail::RunnableMethodImpl(aPtr, aMethod)); +} + +template +already_AddRefed::base_type> +NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod) +{ + return do_AddRef(new detail::RunnableMethodImpl(aPtr, aMethod)); +} + +template +already_AddRefed::base_type> +NewNonOwningCancelableRunnableMethod(PtrType&& aPtr, Method aMethod) +{ + return do_AddRef(new detail::RunnableMethodImpl(aPtr, aMethod)); +} + +// Similar to NewRunnableMethod. Call like so: +// nsCOMPtr event = +// NewRunnableMethod(myObject, &MyClass::HandleEvent, myArg1,...); +// 'Types' are the stored type for each argument, see ParameterStorage for details. +template +already_AddRefed::base_type> +NewRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs) +{ + static_assert(sizeof...(Storages) == sizeof...(Args), + " size should be equal to number of arguments"); + return do_AddRef(new detail::RunnableMethodImpl( + aPtr, aMethod, mozilla::Forward(aArgs)...)); +} + +template +already_AddRefed::base_type> +NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs) +{ + static_assert(sizeof...(Storages) == sizeof...(Args), + " size should be equal to number of arguments"); + return do_AddRef(new detail::RunnableMethodImpl( + aPtr, aMethod, mozilla::Forward(aArgs)...)); +} + +template +already_AddRefed::base_type> +NewCancelableRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs) +{ + static_assert(sizeof...(Storages) == sizeof...(Args), + " size should be equal to number of arguments"); + return do_AddRef(new detail::RunnableMethodImpl( + aPtr, aMethod, mozilla::Forward(aArgs)...)); +} + +template +already_AddRefed::base_type> +NewNonOwningCancelableRunnableMethod(PtrType&& aPtr, Method aMethod, + Args&&... aArgs) +{ + static_assert(sizeof...(Storages) == sizeof...(Args), + " size should be equal to number of arguments"); + return do_AddRef(new detail::RunnableMethodImpl( + aPtr, aMethod, mozilla::Forward(aArgs)...)); +} + +} // namespace mozilla + +#endif // XPCOM_GLUE_AVOID_NSPR + +// This class is designed to be used when you have an event class E that has a +// pointer back to resource class R. If R goes away while E is still pending, +// then it is important to "revoke" E so that it does not try use R after R has +// been destroyed. nsRevocableEventPtr makes it easy for R to manage such +// situations: +// +// class R; +// +// class E : public mozilla::Runnable { +// public: +// void Revoke() { +// mResource = nullptr; +// } +// private: +// R *mResource; +// }; +// +// class R { +// public: +// void EventHandled() { +// mEvent.Forget(); +// } +// private: +// nsRevocableEventPtr mEvent; +// }; +// +// void R::PostEvent() { +// // Make sure any pending event is revoked. +// mEvent->Revoke(); +// +// nsCOMPtr event = new E(); +// if (NS_SUCCEEDED(NS_DispatchToCurrentThread(event))) { +// // Keep pointer to event so we can revoke it. +// mEvent = event; +// } +// } +// +// NS_IMETHODIMP E::Run() { +// if (!mResource) +// return NS_OK; +// ... +// mResource->EventHandled(); +// return NS_OK; +// } +// +template +class nsRevocableEventPtr +{ +public: + nsRevocableEventPtr() : mEvent(nullptr) {} + ~nsRevocableEventPtr() { Revoke(); } + + const nsRevocableEventPtr& operator=(T* aEvent) + { + if (mEvent != aEvent) { + Revoke(); + mEvent = aEvent; + } + return *this; + } + + const nsRevocableEventPtr& operator=(already_AddRefed aEvent) + { + RefPtr event = aEvent; + if (mEvent != event) { + Revoke(); + mEvent = event.forget(); + } + return *this; + } + + void Revoke() + { + if (mEvent) { + mEvent->Revoke(); + mEvent = nullptr; + } + } + + void Forget() { mEvent = nullptr; } + bool IsPending() { return mEvent != nullptr; } + T* get() { return mEvent; } + +private: + // Not implemented + nsRevocableEventPtr(const nsRevocableEventPtr&); + nsRevocableEventPtr& operator=(const nsRevocableEventPtr&); + + RefPtr mEvent; +}; + +/** + * A simple helper to suffix thread pool name + * with incremental numbers. + */ +class nsThreadPoolNaming +{ +public: + nsThreadPoolNaming() : mCounter(0) {} + + /** + * Creates and sets next thread name as " #" + * on the specified thread. If no thread is specified (aThread + * is null) then the name is synchronously set on the current thread. + */ + void SetThreadPoolName(const nsACString& aPoolName, + nsIThread* aThread = nullptr); + +private: + mozilla::Atomic mCounter; + + nsThreadPoolNaming(const nsThreadPoolNaming&) = delete; + void operator=(const nsThreadPoolNaming&) = delete; +}; + +/** + * Thread priority in most operating systems affect scheduling, not IO. This + * helper is used to set the current thread to low IO priority for the lifetime + * of the created object. You can only use this low priority IO setting within + * the context of the current thread. + */ +class MOZ_STACK_CLASS nsAutoLowPriorityIO +{ +public: + nsAutoLowPriorityIO(); + ~nsAutoLowPriorityIO(); + +private: + bool lowIOPrioritySet; +#if defined(XP_MACOSX) + int oldPriority; +#endif +}; + +void +NS_SetMainThread(); + +#endif // nsThreadUtils_h__ -- cgit v1.2.3