/src/node/deps/v8/include/v8-locker.h
Line | Count | Source (jump to first uncovered line) |
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 | | */ |
99 | 0 | 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 | | */ |
114 | 0 | 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 | | // Disallow copying and assigning. |
125 | | Locker(const Locker&) = delete; |
126 | | void operator=(const Locker&) = delete; |
127 | | |
128 | | private: |
129 | | void Initialize(Isolate* isolate); |
130 | | |
131 | | bool has_lock_; |
132 | | bool top_level_; |
133 | | internal::Isolate* isolate_; |
134 | | }; |
135 | | |
136 | | } // namespace v8 |
137 | | |
138 | | #endif // INCLUDE_V8_LOCKER_H_ |