LCOV - code coverage report
Current view: top level - js/src/threading - Thread.h (source / functions) Hit Total Coverage
Test: output.info Lines: 29 33 87.9 %
Date: 2017-07-14 16:53:18 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          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 threading_Thread_h
       8             : #define threading_Thread_h
       9             : 
      10             : #include "mozilla/Atomics.h"
      11             : #include "mozilla/Attributes.h"
      12             : #include "mozilla/HashFunctions.h"
      13             : #include "mozilla/IndexSequence.h"
      14             : #include "mozilla/TimeStamp.h"
      15             : #include "mozilla/Tuple.h"
      16             : 
      17             : #include <stdint.h>
      18             : 
      19             : #include "js/Utility.h"
      20             : 
      21             : #ifdef XP_WIN
      22             : # define THREAD_RETURN_TYPE unsigned int
      23             : # define THREAD_CALL_API __stdcall
      24             : #else
      25             : # define THREAD_RETURN_TYPE void*
      26             : # define THREAD_CALL_API
      27             : #endif
      28             : 
      29             : namespace js {
      30             : namespace detail {
      31             : template <typename F, typename... Args>
      32             : class ThreadTrampoline;
      33             : } // namespace detail
      34             : 
      35             : // Execute the given functor concurrent with the currently executing instruction
      36             : // stream and within the current address space. Use with care.
      37             : class Thread
      38             : {
      39             : public:
      40             :   struct Hasher;
      41             : 
      42             :   class Id
      43             :   {
      44             :     friend struct Hasher;
      45             :     class PlatformData;
      46             :     void* platformData_[2];
      47             : 
      48             :   public:
      49             :     Id();
      50             : 
      51             :     Id(const Id&) = default;
      52             :     Id(Id&&) = default;
      53             :     Id& operator=(const Id&) = default;
      54             :     Id& operator=(Id&&) = default;
      55             : 
      56             :     bool operator==(const Id& aOther) const;
      57         108 :     bool operator!=(const Id& aOther) const { return !operator==(aOther); }
      58             : 
      59             :     inline PlatformData* platformData();
      60             :     inline const PlatformData* platformData() const;
      61             :   };
      62             : 
      63             :   // Provides optional parameters to a Thread.
      64             :   class Options
      65             :   {
      66             :     size_t stackSize_;
      67             : 
      68             :   public:
      69         108 :     Options() : stackSize_(0) {}
      70             : 
      71          36 :     Options& setStackSize(size_t sz) { stackSize_ = sz; return *this; }
      72          72 :     size_t stackSize() const { return stackSize_; }
      73             :   };
      74             : 
      75             :   // A js::HashTable hash policy for keying hash tables by js::Thread::Id.
      76             :   struct Hasher
      77             :   {
      78             :     typedef Id Lookup;
      79             : 
      80             :     static HashNumber hash(const Lookup& l);
      81             : 
      82             :     static bool match(const Id& key, const Lookup& lookup) {
      83             :       return key == lookup;
      84             :     }
      85             :   };
      86             : 
      87             :   // Create a Thread in an initially unjoinable state. A thread of execution can
      88             :   // be created for this Thread by calling |init|. Some of the thread's
      89             :   // properties may be controlled by passing options to this constructor.
      90             :   template <typename O = Options,
      91             :             // SFINAE to make sure we don't try and treat functors for the other
      92             :             // constructor as an Options and vice versa.
      93             :             typename NonConstO = typename mozilla::RemoveConst<O>::Type,
      94             :             typename DerefO = typename mozilla::RemoveReference<NonConstO>::Type,
      95             :             typename = typename mozilla::EnableIf<mozilla::IsSame<DerefO, Options>::value,
      96             :                                                   void*>::Type>
      97          36 :   explicit Thread(O&& options = Options())
      98             :     : id_(Id())
      99          36 :     , options_(mozilla::Forward<O>(options))
     100          36 :   { }
     101             : 
     102             :   // Start a thread of execution at functor |f| with parameters |args|. This
     103             :   // method will return false if thread creation fails. This Thread must not
     104             :   // already have been created. Note that the arguments must be either POD or
     105             :   // rvalue references (mozilla::Move). Attempting to pass a reference will
     106             :   // result in the value being copied, which may not be the intended behavior.
     107             :   // See the comment below on ThreadTrampoline::args for an explanation.
     108             :   template <typename F, typename... Args>
     109          36 :   MOZ_MUST_USE bool init(F&& f, Args&&... args) {
     110          36 :     MOZ_RELEASE_ASSERT(!joinable());
     111             :     using Trampoline = detail::ThreadTrampoline<F, Args...>;
     112          72 :     AutoEnterOOMUnsafeRegion oom;
     113          36 :     auto trampoline = js_new<Trampoline>(mozilla::Forward<F>(f),
     114          36 :                                          mozilla::Forward<Args>(args)...);
     115          36 :     if (!trampoline)
     116           0 :       oom.crash("js::Thread::init");
     117          72 :     return create(Trampoline::Start, trampoline);
     118             :   }
     119             : 
     120             :   // The thread must be joined or detached before destruction.
     121         144 :   ~Thread() {
     122          72 :     MOZ_RELEASE_ASSERT(!joinable());
     123          72 :   }
     124             : 
     125             :   // Move the thread into the detached state without blocking. In the detatched
     126             :   // state, the thread continues to run until it exits, but cannot be joined.
     127             :   // After this method returns, this Thread no longer represents a thread of
     128             :   // execution. When the thread exits, its resources will be cleaned up by the
     129             :   // system. At process exit, if the thread is still running, the thread's TLS
     130             :   // storage will be destructed, but the thread stack will *not* be unrolled.
     131             :   void detach();
     132             : 
     133             :   // Block the current thread until this Thread returns from the functor it was
     134             :   // created with. The thread's resources will be cleaned up before this
     135             :   // function returns. After this method returns, this Thread no longer
     136             :   // represents a thread of execution.
     137             :   void join();
     138             : 
     139             :   // Return true if this thread has not yet been joined or detached. If this
     140             :   // method returns false, this Thread does not have an associated thread of
     141             :   // execution, for example, if it has been previously moved or joined.
     142         108 :   bool joinable() const {
     143         108 :     return get_id() != Id();
     144             :   }
     145             : 
     146             :   // Returns the id of this thread if this represents a thread of execution or
     147             :   // the default constructed Id() if not. The thread ID is guaranteed to
     148             :   // uniquely identify a thread and can be compared with the == operator.
     149         279 :   Id get_id() const { return id_; }
     150             : 
     151             :   // Allow threads to be moved so that they can be stored in containers.
     152             :   Thread(Thread&& aOther);
     153             :   Thread& operator=(Thread&& aOther);
     154             : 
     155             : private:
     156             :   // Disallow copy as that's not sensible for unique resources.
     157             :   Thread(const Thread&) = delete;
     158             :   void operator=(const Thread&) = delete;
     159             : 
     160             :   // Provide a process global ID to each thread.
     161             :   Id id_;
     162             : 
     163             :   // Overridable thread creation options.
     164             :   Options options_;
     165             : 
     166             :   // Dispatch to per-platform implementation of thread creation.
     167             :   MOZ_MUST_USE bool create(THREAD_RETURN_TYPE (THREAD_CALL_API *aMain)(void*), void* aArg);
     168             : };
     169             : 
     170             : namespace ThisThread {
     171             : 
     172             : // Return the thread id of the calling thread.
     173             : Thread::Id GetId();
     174             : 
     175             : // Set the current thread name. Note that setting the thread name may not be
     176             : // available on all platforms; on these platforms setName() will simply do
     177             : // nothing.
     178             : void SetName(const char* name);
     179             : 
     180             : // Get the current thread name. As with SetName, not available on all
     181             : // platforms. On these platforms getName() will give back an empty string (by
     182             : // storing NUL in nameBuffer[0]). 'len' is the bytes available to be written in
     183             : // 'nameBuffer', including the terminating NUL.
     184             : void GetName(char* nameBuffer, size_t len);
     185             : 
     186             : } // namespace ThisThread
     187             : 
     188             : namespace detail {
     189             : 
     190             : // Platform thread APIs allow passing a single void* argument to the target
     191             : // thread. This class is responsible for safely ferrying the arg pack and
     192             : // functor across that void* membrane and running it in the other thread.
     193             : template <typename F, typename... Args>
     194             : class ThreadTrampoline
     195             : {
     196             :   // The functor to call.
     197             :   F f;
     198             : 
     199             :   // A std::decay copy of the arguments, as specified by std::thread. Using an
     200             :   // rvalue reference for the arguments to Thread and ThreadTrampoline gives us
     201             :   // move semantics for large structures, allowing us to quickly and easily pass
     202             :   // enormous amounts of data to a new thread. Unfortunately, there is a
     203             :   // downside: rvalue references becomes lvalue references when used with POD
     204             :   // types. This becomes dangerous when attempting to pass POD stored on the
     205             :   // stack to the new thread; the rvalue reference will implicitly become an
     206             :   // lvalue reference to the stack location. Thus, the value may not exist if
     207             :   // the parent thread leaves the frame before the read happens in the new
     208             :   // thread. To avoid this dangerous and highly non-obvious footgun, the
     209             :   // standard requires a "decay" copy of the arguments at the cost of making it
     210             :   // impossible to pass references between threads.
     211             :   mozilla::Tuple<typename mozilla::Decay<Args>::Type...> args;
     212             : 
     213             : public:
     214             :   // Note that this template instatiation duplicates and is identical to the
     215             :   // class template instantiation. It is required for perfect forwarding of
     216             :   // rvalue references, which is only enabled for calls to a function template,
     217             :   // even if the class template arguments are correct.
     218             :   template <typename G, typename... ArgsT>
     219          36 :   explicit ThreadTrampoline(G&& aG, ArgsT&&... aArgsT)
     220          36 :     : f(mozilla::Forward<F>(aG)),
     221          36 :       args(mozilla::Forward<Args>(aArgsT)...)
     222             :   {
     223          36 :   }
     224             : 
     225          36 :   static THREAD_RETURN_TYPE THREAD_CALL_API Start(void* aPack) {
     226          36 :     auto* pack = static_cast<ThreadTrampoline<F, Args...>*>(aPack);
     227          36 :     pack->callMain(typename mozilla::IndexSequenceFor<Args...>::Type());
     228           0 :     js_delete(pack);
     229           0 :     return 0;
     230             :   }
     231             : 
     232             :   template<size_t ...Indices>
     233          35 :   void callMain(mozilla::IndexSequence<Indices...>) {
     234          35 :     f(mozilla::Get<Indices>(args)...);
     235           0 :   }
     236             : };
     237             : 
     238             : } // namespace detail
     239             : } // namespace js
     240             : 
     241             : #undef THREAD_RETURN_TYPE
     242             : 
     243             : #endif // threading_Thread_h

Generated by: LCOV version 1.13