xpcom/glue/nsThreadUtils.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     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/. */
     7 #ifndef nsThreadUtils_h__
     8 #define nsThreadUtils_h__
    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 "nsStringGlue.h"
    18 #include "nsCOMPtr.h"
    19 #include "nsAutoPtr.h"
    20 #include "mozilla/Likely.h"
    22 //-----------------------------------------------------------------------------
    23 // These methods are alternatives to the methods on nsIThreadManager, provided
    24 // for convenience.
    26 /**
    27  * Set name of the target thread.  This operation is asynchronous.
    28  */
    29 extern NS_COM_GLUE void
    30 NS_SetThreadName(nsIThread *thread, const nsACString &name);
    32 /**
    33  * Static length version of the above function checking length of the
    34  * name at compile time.
    35  */
    36 template <size_t LEN>
    37 inline NS_COM_GLUE void
    38 NS_SetThreadName(nsIThread *thread, const char (&name)[LEN])
    39 {
    40   static_assert(LEN <= 16,
    41                 "Thread name must be no more than 16 characters");
    42   NS_SetThreadName(thread, nsDependentCString(name));
    43 }
    45 /**
    46  * Create a new thread, and optionally provide an initial event for the thread.
    47  *
    48  * @param result
    49  *   The resulting nsIThread object.
    50  * @param initialEvent
    51  *   The initial event to run on this thread.  This parameter may be null.
    52  * @param stackSize
    53  *   The size in bytes to reserve for the thread's stack.
    54  *
    55  * @returns NS_ERROR_INVALID_ARG
    56  *   Indicates that the given name is not unique.
    57  */
    58 extern NS_COM_GLUE NS_METHOD
    59 NS_NewThread(nsIThread **result,
    60              nsIRunnable *initialEvent = nullptr,
    61              uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE);
    63 /**
    64  * Creates a named thread, otherwise the same as NS_NewThread
    65  */
    66 template <size_t LEN>
    67 inline NS_METHOD
    68 NS_NewNamedThread(const char (&name)[LEN],
    69                   nsIThread **result,
    70                   nsIRunnable *initialEvent = nullptr,
    71                   uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE)
    72 {
    73   // Hold a ref while dispatching the initial event to match NS_NewThread()
    74   nsCOMPtr<nsIThread> thread;
    75   nsresult rv = NS_NewThread(getter_AddRefs(thread), nullptr, stackSize);
    76   if (NS_WARN_IF(NS_FAILED(rv)))
    77     return rv;
    78   NS_SetThreadName<LEN>(thread, name);
    79   if (initialEvent) {
    80     rv = thread->Dispatch(initialEvent, NS_DISPATCH_NORMAL);
    81     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Initial event dispatch failed");
    82   }
    84   *result = nullptr;
    85   thread.swap(*result);
    86   return rv;
    87 }
    89 /**
    90  * Get a reference to the current thread.
    91  *
    92  * @param result
    93  *   The resulting nsIThread object.
    94  */
    95 extern NS_COM_GLUE NS_METHOD
    96 NS_GetCurrentThread(nsIThread **result);
    98 /**
    99  * Dispatch the given event to the current thread.
   100  *
   101  * @param event
   102  *   The event to dispatch.
   103  *
   104  * @returns NS_ERROR_INVALID_ARG
   105  *   If event is null.
   106  */
   107 extern NS_COM_GLUE NS_METHOD
   108 NS_DispatchToCurrentThread(nsIRunnable *event);
   110 /**
   111  * Dispatch the given event to the main thread.
   112  *
   113  * @param event
   114  *   The event to dispatch.
   115  * @param dispatchFlags
   116  *   The flags to pass to the main thread's dispatch method.
   117  *
   118  * @returns NS_ERROR_INVALID_ARG
   119  *   If event is null.
   120  */
   121 extern NS_COM_GLUE NS_METHOD
   122 NS_DispatchToMainThread(nsIRunnable *event,
   123                         uint32_t dispatchFlags = NS_DISPATCH_NORMAL);
   125 #ifndef XPCOM_GLUE_AVOID_NSPR
   126 /**
   127  * Process all pending events for the given thread before returning.  This
   128  * method simply calls ProcessNextEvent on the thread while HasPendingEvents
   129  * continues to return true and the time spent in NS_ProcessPendingEvents
   130  * does not exceed the given timeout value.
   131  *
   132  * @param thread
   133  *   The thread object for which to process pending events.  If null, then
   134  *   events will be processed for the current thread.
   135  * @param timeout
   136  *   The maximum number of milliseconds to spend processing pending events.
   137  *   Events are not pre-empted to honor this timeout.  Rather, the timeout
   138  *   value is simply used to determine whether or not to process another event.
   139  *   Pass PR_INTERVAL_NO_TIMEOUT to specify no timeout.
   140  */
   141 extern NS_COM_GLUE NS_METHOD
   142 NS_ProcessPendingEvents(nsIThread *thread,
   143                         PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);
   144 #endif
   146 /**
   147  * Shortcut for nsIThread::HasPendingEvents.
   148  *
   149  * It is an error to call this function when the given thread is not the
   150  * current thread.  This function will return false if called from some
   151  * other thread.
   152  *
   153  * @param thread
   154  *   The current thread or null.
   155  *
   156  * @returns
   157  *   A boolean value that if "true" indicates that there are pending events
   158  *   in the current thread's event queue.
   159  */
   160 extern NS_COM_GLUE bool
   161 NS_HasPendingEvents(nsIThread *thread = nullptr);
   163 /**
   164  * Shortcut for nsIThread::ProcessNextEvent.
   165  *   
   166  * It is an error to call this function when the given thread is not the
   167  * current thread.  This function will simply return false if called
   168  * from some other thread.
   169  *
   170  * @param thread
   171  *   The current thread or null.
   172  * @param mayWait
   173  *   A boolean parameter that if "true" indicates that the method may block
   174  *   the calling thread to wait for a pending event.
   175  *
   176  * @returns
   177  *   A boolean value that if "true" indicates that an event from the current
   178  *   thread's event queue was processed.
   179  */
   180 extern NS_COM_GLUE bool
   181 NS_ProcessNextEvent(nsIThread *thread = nullptr, bool mayWait = true);
   183 //-----------------------------------------------------------------------------
   184 // Helpers that work with nsCOMPtr:
   186 inline already_AddRefed<nsIThread>
   187 do_GetCurrentThread() {
   188   nsIThread *thread = nullptr;
   189   NS_GetCurrentThread(&thread);
   190   return already_AddRefed<nsIThread>(thread);
   191 }
   193 inline already_AddRefed<nsIThread>
   194 do_GetMainThread() {
   195   nsIThread *thread = nullptr;
   196   NS_GetMainThread(&thread);
   197   return already_AddRefed<nsIThread>(thread);
   198 }
   200 //-----------------------------------------------------------------------------
   202 #ifdef MOZILLA_INTERNAL_API
   203 // Fast access to the current thread.  Do not release the returned pointer!  If
   204 // you want to use this pointer from some other thread, then you will need to
   205 // AddRef it.  Otherwise, you should only consider this pointer valid from code
   206 // running on the current thread.
   207 extern NS_COM_GLUE nsIThread *NS_GetCurrentThread();
   208 #endif
   210 //-----------------------------------------------------------------------------
   212 #ifndef XPCOM_GLUE_AVOID_NSPR
   214 #undef  IMETHOD_VISIBILITY
   215 #define IMETHOD_VISIBILITY NS_COM_GLUE
   217 // This class is designed to be subclassed.
   218 class NS_COM_GLUE nsRunnable : public nsIRunnable
   219 {
   220 public:
   221   NS_DECL_THREADSAFE_ISUPPORTS
   222   NS_DECL_NSIRUNNABLE
   224   nsRunnable() {
   225   }
   227 protected:
   228   virtual ~nsRunnable() {
   229   }
   230 };
   232 // This class is designed to be subclassed.
   233 class NS_COM_GLUE nsCancelableRunnable : public nsICancelableRunnable
   234 {
   235 public:
   236   NS_DECL_THREADSAFE_ISUPPORTS
   237   NS_DECL_NSIRUNNABLE
   238   NS_DECL_NSICANCELABLERUNNABLE
   240   nsCancelableRunnable() {
   241   }
   243 protected:
   244   virtual ~nsCancelableRunnable() {
   245   }
   246 };
   248 #undef  IMETHOD_VISIBILITY
   249 #define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN
   251 // An event that can be used to call a method on a class.  The class type must
   252 // support reference counting. This event supports Revoke for use
   253 // with nsRevocableEventPtr.
   254 template <class ClassType,
   255           typename ReturnType = void,
   256           bool Owning = true>
   257 class nsRunnableMethod : public nsRunnable
   258 {
   259 public:
   260   virtual void Revoke() = 0;
   262   // These ReturnTypeEnforcer classes set up a blacklist for return types that
   263   // we know are not safe. The default ReturnTypeEnforcer compiles just fine but
   264   // already_AddRefed will not.
   265   template <typename OtherReturnType>
   266   class ReturnTypeEnforcer
   267   {
   268   public:
   269     typedef int ReturnTypeIsSafe;
   270   };
   272   template <class T>
   273   class ReturnTypeEnforcer<already_AddRefed<T> >
   274   {
   275     // No ReturnTypeIsSafe makes this illegal!
   276   };
   278   // Make sure this return type is safe.
   279   typedef typename ReturnTypeEnforcer<ReturnType>::ReturnTypeIsSafe check;
   280 };
   282 template <class ClassType, typename Arg, bool Owning>
   283 struct nsRunnableMethodReceiver {
   284   ClassType *mObj;
   285   Arg mArg;
   286   nsRunnableMethodReceiver(ClassType *obj, Arg arg)
   287     : mObj(obj)
   288     , mArg(arg)
   289   { NS_IF_ADDREF(mObj); }
   290  ~nsRunnableMethodReceiver() {  Revoke(); }
   291   void Revoke() { NS_IF_RELEASE(mObj); }
   292 };
   294 template <class ClassType, bool Owning>
   295 struct nsRunnableMethodReceiver<ClassType, void, Owning> {
   296   ClassType *mObj;
   297   nsRunnableMethodReceiver(ClassType *obj) : mObj(obj)
   298     { NS_IF_ADDREF(mObj); }
   299   ~nsRunnableMethodReceiver() { Revoke(); }
   300   void Revoke() { NS_IF_RELEASE(mObj); }
   301 };
   303 template <class ClassType>
   304 struct nsRunnableMethodReceiver<ClassType, void, false> {
   305   ClassType *mObj;
   306   nsRunnableMethodReceiver(ClassType *obj) : mObj(obj) {}
   307   void Revoke() { mObj = nullptr; }
   308 };
   310 template <typename Method, bool Owning> struct nsRunnableMethodTraits;
   312 template <class C, typename R, typename A, bool Owning>
   313 struct nsRunnableMethodTraits<R (C::*)(A), Owning> {
   314   typedef C class_type;
   315   typedef R return_type;
   316   typedef A arg_type;
   317   typedef nsRunnableMethod<C, R, Owning> base_type;
   318 };
   320 template <class C, typename R, bool Owning>
   321 struct nsRunnableMethodTraits<R (C::*)(), Owning> {
   322   typedef C class_type;
   323   typedef R return_type;
   324   typedef void arg_type;
   325   typedef nsRunnableMethod<C, R, Owning> base_type;
   326 };
   328 #ifdef NS_HAVE_STDCALL
   329 template <class C, typename R, typename A, bool Owning>
   330 struct nsRunnableMethodTraits<R (__stdcall C::*)(A), Owning> {
   331   typedef C class_type;
   332   typedef R return_type;
   333   typedef A arg_type;
   334   typedef nsRunnableMethod<C, R, Owning> base_type;
   335 };
   337 template <class C, typename R, bool Owning>
   338 struct nsRunnableMethodTraits<R (NS_STDCALL C::*)(), Owning> {
   339   typedef C class_type;
   340   typedef R return_type;
   341   typedef void arg_type;
   342   typedef nsRunnableMethod<C, R, Owning> base_type;
   343 };
   344 #endif
   346 template <typename Method, typename Arg, bool Owning>
   347 class nsRunnableMethodImpl
   348   : public nsRunnableMethodTraits<Method, Owning>::base_type
   349 {
   350   typedef typename nsRunnableMethodTraits<Method, Owning>::class_type ClassType;
   351   nsRunnableMethodReceiver<ClassType, Arg, Owning> mReceiver;
   352   Method mMethod;
   353 public:
   354   nsRunnableMethodImpl(ClassType *obj,
   355                        Method method,
   356                        Arg arg)
   357     : mReceiver(obj, arg)
   358     , mMethod(method)
   359   {}
   360   NS_IMETHOD Run() {
   361     if (MOZ_LIKELY(mReceiver.mObj))
   362       ((*mReceiver.mObj).*mMethod)(mReceiver.mArg);
   363     return NS_OK;
   364   }
   365   void Revoke() {
   366     mReceiver.Revoke();
   367   }
   368 };
   370 template <typename Method, bool Owning>
   371 class nsRunnableMethodImpl<Method, void, Owning>
   372   : public nsRunnableMethodTraits<Method, Owning>::base_type
   373 {
   374   typedef typename nsRunnableMethodTraits<Method, Owning>::class_type ClassType;
   375   nsRunnableMethodReceiver<ClassType, void, Owning> mReceiver;
   376   Method mMethod;
   378 public:
   379   nsRunnableMethodImpl(ClassType *obj,
   380                        Method method)
   381     : mReceiver(obj)
   382     , mMethod(method)
   383   {}
   385   NS_IMETHOD Run() {
   386     if (MOZ_LIKELY(mReceiver.mObj))
   387       ((*mReceiver.mObj).*mMethod)();
   388     return NS_OK;
   389   }
   391   void Revoke() {
   392     mReceiver.Revoke();
   393   }
   394 };
   396 // Use this template function like so:
   397 //
   398 //   nsCOMPtr<nsIRunnable> event =
   399 //     NS_NewRunnableMethod(myObject, &MyClass::HandleEvent);
   400 //   NS_DispatchToCurrentThread(event);
   401 //
   402 // Statically enforced constraints:
   403 //  - myObject must be of (or implicitly convertible to) type MyClass
   404 //  - MyClass must defined AddRef and Release methods
   405 //
   406 template<typename PtrType, typename Method>
   407 typename nsRunnableMethodTraits<Method, true>::base_type*
   408 NS_NewRunnableMethod(PtrType ptr, Method method)
   409 {
   410   return new nsRunnableMethodImpl<Method, void, true>(ptr, method);
   411 }
   413 template<typename T>
   414 struct dependent_type
   415 {
   416   typedef T type;
   417 };
   420 // Similar to NS_NewRunnableMethod. Call like so:
   421 // Type myArg;
   422 // nsCOMPtr<nsIRunnable> event =
   423 //   NS_NewRunnableMethodWithArg<Type>(myObject, &MyClass::HandleEvent, myArg);
   424 template<typename Arg, typename Method, typename PtrType>
   425 typename nsRunnableMethodTraits<Method, true>::base_type*
   426 NS_NewRunnableMethodWithArg(PtrType ptr, Method method, typename dependent_type<Arg>::type arg)
   427 {
   428   return new nsRunnableMethodImpl<Method, Arg, true>(ptr, method, arg);
   429 }
   431 template<typename PtrType, typename Method>
   432 typename nsRunnableMethodTraits<Method, false>::base_type*
   433 NS_NewNonOwningRunnableMethod(PtrType ptr, Method method)
   434 {
   435   return new nsRunnableMethodImpl<Method, void, false>(ptr, method);
   436 }
   438 #endif  // XPCOM_GLUE_AVOID_NSPR
   440 // This class is designed to be used when you have an event class E that has a
   441 // pointer back to resource class R.  If R goes away while E is still pending,
   442 // then it is important to "revoke" E so that it does not try use R after R has
   443 // been destroyed.  nsRevocableEventPtr makes it easy for R to manage such
   444 // situations:
   445 //
   446 //   class R;
   447 //
   448 //   class E : public nsRunnable {
   449 //   public:
   450 //     void Revoke() {
   451 //       mResource = nullptr;
   452 //     }
   453 //   private:
   454 //     R *mResource;
   455 //   };
   456 //
   457 //   class R {
   458 //   public:
   459 //     void EventHandled() {
   460 //       mEvent.Forget();
   461 //     }
   462 //   private:
   463 //     nsRevocableEventPtr<E> mEvent;
   464 //   };
   465 //
   466 //   void R::PostEvent() {
   467 //     // Make sure any pending event is revoked.
   468 //     mEvent->Revoke();
   469 //
   470 //     nsCOMPtr<nsIRunnable> event = new E();
   471 //     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(event))) {
   472 //       // Keep pointer to event so we can revoke it.
   473 //       mEvent = event;
   474 //     }
   475 //   }
   476 //
   477 //   NS_IMETHODIMP E::Run() {
   478 //     if (!mResource)
   479 //       return NS_OK;
   480 //     ...
   481 //     mResource->EventHandled();
   482 //     return NS_OK;
   483 //   }
   484 //
   485 template <class T>
   486 class nsRevocableEventPtr {
   487 public:
   488   nsRevocableEventPtr()
   489     : mEvent(nullptr) {
   490   }
   492   ~nsRevocableEventPtr() {
   493     Revoke();
   494   }
   496   const nsRevocableEventPtr& operator=(T *event) {
   497     if (mEvent != event) {
   498       Revoke();
   499       mEvent = event;
   500     }
   501     return *this;
   502   }
   504   void Revoke() {
   505     if (mEvent) {
   506       mEvent->Revoke();
   507       mEvent = nullptr;
   508     }
   509   }
   511   void Forget() {
   512     mEvent = nullptr;
   513   }
   515   bool IsPending() {
   516     return mEvent != nullptr;
   517   }
   519   T *get() { return mEvent; }
   521 private:
   522   // Not implemented
   523   nsRevocableEventPtr(const nsRevocableEventPtr&);
   524   nsRevocableEventPtr& operator=(const nsRevocableEventPtr&);
   526   nsRefPtr<T> mEvent;
   527 };
   529 /**
   530  * A simple helper to suffix thread pool name
   531  * with incremental numbers.
   532  */
   533 class nsThreadPoolNaming
   534 {
   535 public:
   536   nsThreadPoolNaming() : mCounter(0) {}
   538   /**
   539    * Creates and sets next thread name as "<aPoolName> #<n>"
   540    * on the specified thread.  If no thread is specified (aThread
   541    * is null) then the name is synchronously set on the current thread.
   542    */
   543   void SetThreadPoolName(const nsACString & aPoolName,
   544                          nsIThread * aThread = nullptr);
   546 private:
   547   volatile uint32_t mCounter;
   549   nsThreadPoolNaming(const nsThreadPoolNaming &) MOZ_DELETE;
   550   void operator=(const nsThreadPoolNaming &) MOZ_DELETE;
   551 };
   553 /**
   554  * Thread priority in most operating systems affect scheduling, not IO.  This
   555  * helper is used to set the current thread to low IO priority for the lifetime
   556  * of the created object.  You can only use this low priority IO setting within
   557  * the context of the current thread.
   558  */
   559 class MOZ_STACK_CLASS nsAutoLowPriorityIO
   560 {
   561 public:
   562   nsAutoLowPriorityIO();
   563   ~nsAutoLowPriorityIO();
   565 private:
   566   bool lowIOPrioritySet;
   567 #if defined(XP_MACOSX)
   568   int oldPriority;
   569 #endif
   570 };
   574 #endif  // nsThreadUtils_h__

mercurial