1 // Copyright 2021 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef INCLUDE_V8_LOCKER_H_ 6 #define INCLUDE_V8_LOCKER_H_ 7 8 #include "v8config.h" // NOLINT(build/include_directory) 9 10 namespace v8 { 11 12 namespace internal { 13 class Isolate; 14 } // namespace internal 15 16 class Isolate; 17 18 /** 19 * Multiple threads in V8 are allowed, but only one thread at a time is allowed 20 * to use any given V8 isolate, see the comments in the Isolate class. The 21 * definition of 'using a V8 isolate' includes accessing handles or holding onto 22 * object pointers obtained from V8 handles while in the particular V8 isolate. 23 * It is up to the user of V8 to ensure, perhaps with locking, that this 24 * constraint is not violated. In addition to any other synchronization 25 * mechanism that may be used, the v8::Locker and v8::Unlocker classes must be 26 * used to signal thread switches to V8. 27 * 28 * v8::Locker is a scoped lock object. While it's active, i.e. between its 29 * construction and destruction, the current thread is allowed to use the locked 30 * isolate. V8 guarantees that an isolate can be locked by at most one thread at 31 * any time. In other words, the scope of a v8::Locker is a critical section. 32 * 33 * Sample usage: 34 * \code 35 * ... 36 * { 37 * v8::Locker locker(isolate); 38 * v8::Isolate::Scope isolate_scope(isolate); 39 * ... 40 * // Code using V8 and isolate goes here. 41 * ... 42 * } // Destructor called here 43 * \endcode 44 * 45 * If you wish to stop using V8 in a thread A you can do this either by 46 * destroying the v8::Locker object as above or by constructing a v8::Unlocker 47 * object: 48 * 49 * \code 50 * { 51 * isolate->Exit(); 52 * v8::Unlocker unlocker(isolate); 53 * ... 54 * // Code not using V8 goes here while V8 can run in another thread. 55 * ... 56 * } // Destructor called here. 57 * isolate->Enter(); 58 * \endcode 59 * 60 * The Unlocker object is intended for use in a long-running callback from V8, 61 * where you want to release the V8 lock for other threads to use. 62 * 63 * The v8::Locker is a recursive lock, i.e. you can lock more than once in a 64 * given thread. This can be useful if you have code that can be called either 65 * from code that holds the lock or from code that does not. The Unlocker is 66 * not recursive so you can not have several Unlockers on the stack at once, and 67 * you cannot use an Unlocker in a thread that is not inside a Locker's scope. 68 * 69 * An unlocker will unlock several lockers if it has to and reinstate the 70 * correct depth of locking on its destruction, e.g.: 71 * 72 * \code 73 * // V8 not locked. 74 * { 75 * v8::Locker locker(isolate); 76 * Isolate::Scope isolate_scope(isolate); 77 * // V8 locked. 78 * { 79 * v8::Locker another_locker(isolate); 80 * // V8 still locked (2 levels). 81 * { 82 * isolate->Exit(); 83 * v8::Unlocker unlocker(isolate); 84 * // V8 not locked. 85 * } 86 * isolate->Enter(); 87 * // V8 locked again (2 levels). 88 * } 89 * // V8 still locked (1 level). 90 * } 91 * // V8 Now no longer locked. 92 * \endcode 93 */ 94 class V8_EXPORT Unlocker { 95 public: 96 /** 97 * Initialize Unlocker for a given Isolate. 98 */ Unlocker(Isolate * isolate)99 V8_INLINE explicit Unlocker(Isolate* isolate) { Initialize(isolate); } 100 101 ~Unlocker(); 102 103 private: 104 void Initialize(Isolate* isolate); 105 106 internal::Isolate* isolate_; 107 }; 108 109 class V8_EXPORT Locker { 110 public: 111 /** 112 * Initialize Locker for a given Isolate. 113 */ Locker(Isolate * isolate)114 V8_INLINE explicit Locker(Isolate* isolate) { Initialize(isolate); } 115 116 ~Locker(); 117 118 /** 119 * Returns whether or not the locker for a given isolate, is locked by the 120 * current thread. 121 */ 122 static bool IsLocked(Isolate* isolate); 123 124 /** 125 * Returns whether any v8::Locker has ever been used in this process. 126 * TODO(cbruni, chromium:1240851): Fix locking checks on a per-thread basis. 127 * The current implementation is quite confusing and leads to unexpected 128 * results if anybody uses v8::Locker in the current process. 129 */ 130 V8_DEPRECATE_SOON("This method will be removed.") 131 static bool WasEverUsed(); 132 V8_DEPRECATED("Use WasEverUsed instead") 133 static bool IsActive(); 134 135 // Disallow copying and assigning. 136 Locker(const Locker&) = delete; 137 void operator=(const Locker&) = delete; 138 139 private: 140 void Initialize(Isolate* isolate); 141 142 bool has_lock_; 143 bool top_level_; 144 internal::Isolate* isolate_; 145 }; 146 147 } // namespace v8 148 149 #endif // INCLUDE_V8_LOCKER_H_ 150