LCOV - code coverage report
Current view: top level - js/src/threading - ProtectedData.h (source / functions) Hit Total Coverage
Test: output.info Lines: 55 62 88.7 %
Date: 2017-07-14 16:53:18 Functions: 957 1287 74.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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_ProtectedData_h
       8             : #define threading_ProtectedData_h
       9             : 
      10             : #include "threading/Thread.h"
      11             : 
      12             : namespace js {
      13             : 
      14             : // This file provides classes for encapsulating pieces of data with a check
      15             : // that ensures the data is only accessed if certain conditions are met.
      16             : // Checking is only done in debug builds; in release builds these classes
      17             : // have no space or time overhead. These classes are mainly used for ensuring
      18             : // that data is used in threadsafe ways.
      19             : //
      20             : // ProtectedData does not by itself ensure that data is threadsafe: it only
      21             : // documents and checks synchronization constraints that need to be established
      22             : // by the code using the data. If a mutex can be created and directly
      23             : // associated with the data, consider using the ExclusiveData class instead.
      24             : // Otherwise, ProtectedData should be used to document whatever synchronization
      25             : // method is used.
      26             : 
      27             : // Protected data checks are enabled in debug builds, except on android where
      28             : // they cause some permatimeouts in automation.
      29             : #if defined(DEBUG) && !defined(ANDROID)
      30             : #define JS_HAS_PROTECTED_DATA_CHECKS
      31             : #endif
      32             : 
      33             : #define DECLARE_ONE_BOOL_OPERATOR(OP, T)        \
      34             :     template <typename U>                       \
      35             :     bool operator OP(const U& other) const { return ref() OP static_cast<T>(other); }
      36             : 
      37             : #define DECLARE_BOOL_OPERATORS(T)               \
      38             :     DECLARE_ONE_BOOL_OPERATOR(==, T)            \
      39             :     DECLARE_ONE_BOOL_OPERATOR(!=, T)            \
      40             :     DECLARE_ONE_BOOL_OPERATOR(<=, T)            \
      41             :     DECLARE_ONE_BOOL_OPERATOR(>=, T)            \
      42             :     DECLARE_ONE_BOOL_OPERATOR(<, T)             \
      43             :     DECLARE_ONE_BOOL_OPERATOR(>, T)
      44             : 
      45             : // Mark a region of code that should be treated as single threaded and suppress
      46             : // any ProtectedData checks.
      47             : //
      48             : // Note that in practice there may be multiple threads running when this class
      49             : // is used, due to the presence of multiple runtimes in the process. When each
      50             : // process has only a single runtime this will no longer be a concern.
      51             : class MOZ_RAII AutoNoteSingleThreadedRegion
      52             : {
      53             :   public:
      54             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
      55             :     static mozilla::Atomic<size_t> count;
      56          10 :     AutoNoteSingleThreadedRegion() { count++; }
      57          10 :     ~AutoNoteSingleThreadedRegion() { count--; }
      58             : #else
      59             :     AutoNoteSingleThreadedRegion() {}
      60             : #endif
      61             : };
      62             : 
      63             : // Class for protected data that may be written to any number of times. Checks
      64             : // occur when the data is both read from and written to.
      65             : template <typename Check, typename T>
      66           0 : class ProtectedData
      67             : {
      68             :     typedef ProtectedData<Check, T> ThisType;
      69             : 
      70             :   public:
      71             :     template <typename... Args>
      72        5420 :     explicit ProtectedData(const Check& check, Args&&... args)
      73        4259 :       : value(mozilla::Forward<Args>(args)...)
      74             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
      75        5420 :       , check(check)
      76             : #endif
      77        5420 :     {}
      78             : 
      79     9460240 :     DECLARE_BOOL_OPERATORS(T)
      80             : 
      81    79794616 :     operator const T&() const { return ref(); }
      82     3182277 :     const T& operator->() const { return ref(); }
      83             : 
      84             :     template <typename U>
      85             :     ThisType& operator=(const U& p) { this->ref() = p; return *this; }
      86             : 
      87        1010 :     template <typename U> T& operator +=(const U& rhs) { return ref() += rhs; }
      88         995 :     template <typename U> T& operator -=(const U& rhs) { return ref() -= rhs; }
      89           0 :     template <typename U> T& operator *=(const U& rhs) { return ref() *= rhs; }
      90             :     template <typename U> T& operator /=(const U& rhs) { return ref() /= rhs; }
      91           0 :     template <typename U> T& operator &=(const U& rhs) { return ref() &= rhs; }
      92           0 :     template <typename U> T& operator |=(const U& rhs) { return ref() |= rhs; }
      93       44452 :     T& operator ++() { return ++ref(); }
      94      128060 :     T& operator --() { return --ref(); }
      95     4332210 :     T operator ++(int) { return ref()++; }
      96     4246163 :     T operator --(int) { return ref()--; }
      97             : 
      98    16175354 :     T& ref() {
      99             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     100    16175354 :         if (!AutoNoteSingleThreadedRegion::count)
     101    15024945 :             check.check();
     102             : #endif
     103    16177302 :         return value;
     104             :     }
     105             : 
     106    92459991 :     const T& ref() const {
     107             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     108    92459991 :         if (!AutoNoteSingleThreadedRegion::count)
     109    90982859 :             check.check();
     110             : #endif
     111    92479954 :         return value;
     112             :     }
     113             : 
     114         285 :     T& refNoCheck() { return value; }
     115          60 :     const T& refNoCheck() const { return value; }
     116             : 
     117             :   private:
     118             :     T value;
     119             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     120             :     Check check;
     121             : #endif
     122             : };
     123             : 
     124             : // Intermediate class for protected data whose checks take no constructor arguments.
     125             : template <typename Check, typename T>
     126           0 : class ProtectedDataNoCheckArgs : public ProtectedData<Check, T>
     127             : {
     128             :     typedef ProtectedDataNoCheckArgs<Check, T> ThisType;
     129             : 
     130             :   public:
     131             :     template <typename... Args>
     132        4023 :     explicit ProtectedDataNoCheckArgs(Args&&... args)
     133        4023 :       : ProtectedData<Check, T>(Check(), mozilla::Forward<Args>(args)...)
     134        4023 :     {}
     135             : 
     136             :     template <typename U>
     137      683652 :     ThisType& operator=(const U& p) { this->ref() = p; return *this; }
     138             : };
     139             : 
     140             : class ZoneGroup;
     141             : 
     142             : // Intermediate class for protected data whose checks take a ZoneGroup constructor argument.
     143             : template <typename Check, typename T>
     144           0 : class ProtectedDataZoneGroupArg : public ProtectedData<Check, T>
     145             : {
     146             :     typedef ProtectedDataZoneGroupArg<Check, T> ThisType;
     147             : 
     148             :   public:
     149             :     template <typename... Args>
     150        1397 :     explicit ProtectedDataZoneGroupArg(ZoneGroup* group, Args&&... args)
     151        1397 :       : ProtectedData<Check, T>(Check(group), mozilla::Forward<Args>(args)...)
     152        1397 :     {}
     153             : 
     154             :     template <typename U>
     155      740480 :     ThisType& operator=(const U& p) { this->ref() = p; return *this; }
     156             : };
     157             : 
     158             : class CheckUnprotected
     159             : {
     160             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     161             :   public:
     162    59955459 :     inline void check() const {}
     163             : #endif
     164             : };
     165             : 
     166             : // Data with a no-op check that permits all accesses. This is tantamount to not
     167             : // using ProtectedData at all, but is in place to document points which need
     168             : // to be fixed in order for runtimes to be multithreaded (see bug 1323066).
     169             : template <typename T>
     170             : using UnprotectedData = ProtectedDataNoCheckArgs<CheckUnprotected, T>;
     171             : 
     172             : class CheckThreadLocal
     173             : {
     174             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     175             :     Thread::Id id;
     176             : 
     177             :   public:
     178        2840 :     CheckThreadLocal()
     179        2840 :       : id(ThisThread::GetId())
     180        2840 :     {}
     181             : 
     182             :     void check() const;
     183             : #endif
     184             : };
     185             : 
     186             : // Data which may only be accessed by the thread on which it is created.
     187             : template <typename T>
     188             : using ThreadLocalData = ProtectedDataNoCheckArgs<CheckThreadLocal, T>;
     189             : 
     190             : // Enum describing which helper threads (GC tasks or Ion compilations) may
     191             : // access data even though they do not have exclusive access to any zone group.
     192             : enum class AllowedHelperThread
     193             : {
     194             :     None,
     195             :     GCTask,
     196             :     IonCompile,
     197             :     GCTaskOrIonCompile
     198             : };
     199             : 
     200             : template <AllowedHelperThread Helper>
     201             : class CheckActiveThread
     202             : {
     203             :   public:
     204             :     void check() const;
     205             : };
     206             : 
     207             : // Data which may only be accessed by the runtime's cooperatively scheduled
     208             : // active thread.
     209             : template <typename T>
     210             : using ActiveThreadData =
     211             :     ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::None>, T>;
     212             : 
     213             : // Data which may only be accessed by the runtime's cooperatively scheduled
     214             : // active thread, or by various helper thread tasks.
     215             : template <typename T>
     216             : using ActiveThreadOrGCTaskData =
     217             :     ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::GCTask>, T>;
     218             : template <typename T>
     219             : using ActiveThreadOrIonCompileData =
     220             :     ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::IonCompile>, T>;
     221             : 
     222             : template <AllowedHelperThread Helper>
     223             : class CheckZoneGroup
     224             : {
     225             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     226             :     ZoneGroup* group;
     227             : 
     228             :   public:
     229        1397 :     explicit CheckZoneGroup(ZoneGroup* group) : group(group) {}
     230             :     void check() const;
     231             : #else
     232             :   public:
     233             :     explicit CheckZoneGroup(ZoneGroup* group) {}
     234             : #endif
     235             : };
     236             : 
     237             : // Data which may only be accessed by threads with exclusive access to the
     238             : // associated zone group, or by the runtime's cooperatively scheduled
     239             : // active thread for zone groups which are not in use by a helper thread.
     240             : template <typename T>
     241             : using ZoneGroupData =
     242             :     ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedHelperThread::None>, T>;
     243             : 
     244             : // Data which may only be accessed by threads with exclusive access to the
     245             : // associated zone group, or by various helper thread tasks.
     246             : template <typename T>
     247             : using ZoneGroupOrGCTaskData =
     248             :     ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedHelperThread::GCTask>, T>;
     249             : template <typename T>
     250             : using ZoneGroupOrIonCompileData =
     251             :     ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedHelperThread::IonCompile>, T>;
     252             : template <typename T>
     253             : using ZoneGroupOrGCTaskOrIonCompileData =
     254             :     ProtectedDataZoneGroupArg<CheckZoneGroup<AllowedHelperThread::GCTaskOrIonCompile>, T>;
     255             : 
     256             : // Runtime wide locks which might protect some data.
     257             : enum class GlobalLock
     258             : {
     259             :     GCLock,
     260             :     ExclusiveAccessLock,
     261             :     HelperThreadLock
     262             : };
     263             : 
     264             : template <GlobalLock Lock, AllowedHelperThread Helper>
     265             : class CheckGlobalLock
     266             : {
     267             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     268             :   public:
     269             :     void check() const;
     270             : #endif
     271             : };
     272             : 
     273             : // Data which may only be accessed while holding the GC lock.
     274             : template <typename T>
     275             : using GCLockData =
     276             :     ProtectedDataNoCheckArgs<CheckGlobalLock<GlobalLock::GCLock, AllowedHelperThread::None>, T>;
     277             : 
     278             : // Data which may only be accessed while holding the exclusive access lock.
     279             : template <typename T>
     280             : using ExclusiveAccessLockData =
     281             :     ProtectedDataNoCheckArgs<CheckGlobalLock<GlobalLock::ExclusiveAccessLock, AllowedHelperThread::None>, T>;
     282             : 
     283             : // Data which may only be accessed while holding the exclusive access lock or
     284             : // by GC helper thread tasks (at which point a foreground thread should be
     285             : // holding the exclusive access lock, though we do not check this).
     286             : template <typename T>
     287             : using ExclusiveAccessLockOrGCTaskData =
     288             :     ProtectedDataNoCheckArgs<CheckGlobalLock<GlobalLock::ExclusiveAccessLock, AllowedHelperThread::GCTask>, T>;
     289             : 
     290             : // Data which may only be accessed while holding the helper thread lock.
     291             : template <typename T>
     292             : using HelperThreadLockData =
     293             :     ProtectedDataNoCheckArgs<CheckGlobalLock<GlobalLock::HelperThreadLock, AllowedHelperThread::None>, T>;
     294             : 
     295             : // Class for protected data that is only written to once. 'const' may sometimes
     296             : // be usable instead of this class, but in cases where the data cannot be set
     297             : // to its final value in its constructor this class is helpful. Protected data
     298             : // checking only occurs when writes are performed, not reads. Steps may need to
     299             : // be taken to ensure that reads do not occur until the written value is fully
     300             : // initialized, as such guarantees are not provided by this class.
     301             : template <typename Check, typename T>
     302           0 : class ProtectedDataWriteOnce
     303             : {
     304             :     typedef ProtectedDataWriteOnce<Check, T> ThisType;
     305             : 
     306             :   public:
     307             :     template <typename... Args>
     308         232 :     explicit ProtectedDataWriteOnce(Args&&... args)
     309         188 :       : value(mozilla::Forward<Args>(args)...)
     310             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     311         232 :       , nwrites(0)
     312             : #endif
     313         232 :     {}
     314             : 
     315    35908619 :     DECLARE_BOOL_OPERATORS(T)
     316             : 
     317     7950228 :     operator const T&() const { return ref(); }
     318       29956 :     const T& operator->() const { return ref(); }
     319             : 
     320             :     template <typename U>
     321         165 :     ThisType& operator=(const U& p) {
     322         165 :         if (ref() != p)
     323         129 :             this->writeRef() = p;
     324         165 :         return *this;
     325             :     }
     326             : 
     327    43912258 :     const T& ref() const { return value; }
     328             : 
     329         137 :     T& writeRef() {
     330             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     331         137 :         if (!AutoNoteSingleThreadedRegion::count)
     332          22 :             check.check();
     333             :         // Despite the WriteOnce name, actually allow two writes to accommodate
     334             :         // data that is cleared during teardown.
     335         137 :         MOZ_ASSERT(++nwrites <= 2);
     336             : #endif
     337         137 :         return value;
     338             :     }
     339             : 
     340             :   private:
     341             :     T value;
     342             : #ifdef JS_HAS_PROTECTED_DATA_CHECKS
     343             :     Check check;
     344             :     size_t nwrites;
     345             : #endif
     346             : };
     347             : 
     348             : // Data that is written once with no requirements for exclusive access when
     349             : // that write occurs.
     350             : template <typename T>
     351             : using WriteOnceData = ProtectedDataWriteOnce<CheckUnprotected, T>;
     352             : 
     353             : // Data that is written once, and only while holding the exclusive access lock.
     354             : template <typename T>
     355             : using ExclusiveAccessLockWriteOnceData =
     356             :     ProtectedDataWriteOnce<CheckGlobalLock<GlobalLock::ExclusiveAccessLock, AllowedHelperThread::None>, T>;
     357             : 
     358             : #undef DECLARE_ASSIGNMENT_OPERATOR
     359             : #undef DECLARE_ONE_BOOL_OPERATOR
     360             : #undef DECLARE_BOOL_OPERATORS
     361             : 
     362             : } // namespace js
     363             : 
     364             : #endif // threading_ProtectedData_h

Generated by: LCOV version 1.13