Coverage Report

Created: 2025-12-30 08:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/node_locks.h
Line
Count
Source
1
#ifndef SRC_NODE_LOCKS_H_
2
#define SRC_NODE_LOCKS_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include <deque>
7
#include <string>
8
#include <unordered_map>
9
#include <unordered_set>
10
11
#include "base_object.h"
12
#include "env.h"
13
#include "node_mutex.h"
14
#include "v8.h"
15
16
namespace node::worker::locks {
17
18
class Lock final : public MemoryRetainer {
19
 public:
20
  enum class Mode { Shared, Exclusive };
21
22
  Lock(Environment* env,
23
       const std::u16string& name,
24
       Mode mode,
25
       const std::string& client_id,
26
       v8::Local<v8::Promise::Resolver> waiting,
27
       v8::Local<v8::Promise::Resolver> released);
28
0
  ~Lock() = default;
29
30
  Lock(const Lock&) = delete;
31
  Lock& operator=(const Lock&) = delete;
32
33
  // Resource name for this lock as DOMString
34
0
  const std::u16string& name() const { return name_; }
35
  // Lock mode (shared or exclusive).
36
0
  Mode mode() const { return mode_; }
37
  // Client identifier string.
38
0
  const std::string& client_id() const { return client_id_; }
39
  // Environment that owns this lock.
40
0
  Environment* env() const { return env_; }
41
42
  // Returns true if this lock was stolen by another request.
43
0
  bool is_stolen() const { return stolen_; }
44
  // Marks this lock as stolen.
45
0
  void mark_stolen() { stolen_ = true; }
46
47
  // Promise that resolves when the user callback completes.
48
0
  v8::Local<v8::Promise::Resolver> waiting_promise() {
49
0
    return waiting_promise_.Get(env_->isolate());
50
0
  }
51
  // Promise that resolves when the lock is finally released.
52
0
  v8::Local<v8::Promise::Resolver> released_promise() {
53
0
    return released_promise_.Get(env_->isolate());
54
0
  }
55
56
  void MemoryInfo(node::MemoryTracker* tracker) const override;
57
  SET_MEMORY_INFO_NAME(Lock)
58
  SET_SELF_SIZE(Lock)
59
60
 private:
61
  Environment* env_;
62
  std::u16string name_;
63
  Mode mode_;
64
  std::string client_id_;
65
  bool stolen_ = false;
66
  v8::Global<v8::Promise::Resolver> waiting_promise_;
67
  v8::Global<v8::Promise::Resolver> released_promise_;
68
};
69
70
class LockHolder final : public BaseObject {
71
 public:
72
  LockHolder(Environment* env,
73
             v8::Local<v8::Object> obj,
74
             std::shared_ptr<Lock> lock)
75
0
      : BaseObject(env, obj), lock_(std::move(lock)) {
76
0
    MakeWeak();
77
0
  }
78
79
0
  ~LockHolder() = default;
80
81
  LockHolder(const LockHolder&) = delete;
82
  LockHolder& operator=(const LockHolder&) = delete;
83
84
0
  std::shared_ptr<Lock> lock() const { return lock_; }
85
86
  void MemoryInfo(node::MemoryTracker* tracker) const override;
87
  SET_MEMORY_INFO_NAME(LockHolder)
88
  SET_SELF_SIZE(LockHolder)
89
90
  static BaseObjectPtr<LockHolder> Create(Environment* env,
91
                                          std::shared_ptr<Lock> lock);
92
93
 private:
94
  static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
95
      Environment* env);
96
97
  std::shared_ptr<Lock> lock_;
98
};
99
100
class LockRequest final {
101
 public:
102
  LockRequest(Environment* env,
103
              v8::Local<v8::Promise::Resolver> waiting,
104
              v8::Local<v8::Promise::Resolver> released,
105
              v8::Local<v8::Function> callback,
106
              const std::u16string& name,
107
              Lock::Mode mode,
108
              std::string client_id,
109
              bool steal,
110
              bool if_available);
111
0
  ~LockRequest() = default;
112
113
  LockRequest(const LockRequest&) = delete;
114
  LockRequest& operator=(const LockRequest&) = delete;
115
116
0
  const std::u16string& name() const { return name_; }
117
0
  Lock::Mode mode() const { return mode_; }
118
0
  const std::string& client_id() const { return client_id_; }
119
0
  bool steal() const { return steal_; }
120
  // Returns true if this is an ifAvailable request.
121
0
  bool if_available() const { return if_available_; }
122
0
  Environment* env() const { return env_; }
123
124
0
  v8::Local<v8::Promise::Resolver> waiting_promise() {
125
0
    return waiting_promise_.Get(env_->isolate());
126
0
  }
127
0
  v8::Local<v8::Promise::Resolver> released_promise() {
128
0
    return released_promise_.Get(env_->isolate());
129
0
  }
130
0
  v8::Local<v8::Function> callback() { return callback_.Get(env_->isolate()); }
131
132
 private:
133
  Environment* env_;
134
  std::u16string name_;
135
  Lock::Mode mode_;
136
  std::string client_id_;
137
  bool steal_;
138
  bool if_available_;
139
  v8::Global<v8::Promise::Resolver> waiting_promise_;
140
  v8::Global<v8::Promise::Resolver> released_promise_;
141
  v8::Global<v8::Function> callback_;
142
};
143
144
class LockManager final {
145
 public:
146
  static void Request(const v8::FunctionCallbackInfo<v8::Value>& args);
147
  static void Query(const v8::FunctionCallbackInfo<v8::Value>& args);
148
149
  void ProcessQueue(Environment* env);
150
  void CleanupEnvironment(Environment* env);
151
152
  static void OnEnvironmentCleanup(void* arg);
153
0
  static LockManager* GetCurrent() { return &current_; }
154
  void ReleaseLockAndProcessQueue(Environment* env,
155
                                  std::shared_ptr<Lock> lock,
156
                                  v8::Local<v8::Value> result,
157
                                  bool was_rejected = false);
158
159
 private:
160
72
  LockManager() = default;
161
0
  ~LockManager() = default;
162
163
  LockManager(const LockManager&) = delete;
164
  LockManager& operator=(const LockManager&) = delete;
165
166
  bool IsGrantable(const LockRequest* req) const;
167
  void CleanupStolenLocks(Environment* env);
168
  void ReleaseLock(Lock* lock);
169
  void WakeEnvironment(Environment* env);
170
171
  static LockManager current_;
172
173
  mutable Mutex mutex_;
174
  // All entries for a given Environment* are purged in CleanupEnvironment().
175
  std::unordered_map<std::u16string, std::deque<std::shared_ptr<Lock>>>
176
      held_locks_;
177
  std::deque<std::unique_ptr<LockRequest>> pending_queue_;
178
  std::unordered_set<Environment*> registered_envs_;
179
};
180
181
}  // namespace node::worker::locks
182
183
#endif  // NODE_WANT_INTERNALS
184
#endif  // SRC_NODE_LOCKS_H_