• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "async_lock.h"
17 #include "async_lock_manager.h"
18 #include "tools/log.h"
19 
20 namespace Commonlibrary::Concurrent::LocksModule {
21 using namespace Commonlibrary::Concurrent::Common::Helper;
22 
AsyncLock(const std::string & lockName)23 AsyncLock::AsyncLock(const std::string &lockName)
24 {
25     lockName_ = lockName;
26     anonymousLockId_ = 0;
27 }
28 
AsyncLock(uint32_t lockId)29 AsyncLock::AsyncLock(uint32_t lockId)
30 {
31     lockName_ = "";
32     anonymousLockId_ = lockId;
33 }
34 
LockAsync(napi_env env,napi_ref cb,LockMode mode,const LockOptions & options)35 napi_value AsyncLock::LockAsync(napi_env env, napi_ref cb, LockMode mode, const LockOptions &options)
36 {
37     napi_value promise;
38     napi_deferred deferred;
39     napi_create_promise(env, &deferred, &promise);
40     if (!NativeEngine::IsAlive(reinterpret_cast<NativeEngine *>(env))) {
41         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "env is not alive");
42         return nullptr;
43     }
44     if (!CanAcquireLock(mode) && options.isAvailable) {
45         napi_value err;
46         NAPI_CALL(env, napi_create_string_utf8(env, "The lock is acquired", NAPI_AUTO_LENGTH, &err));
47         napi_reject_deferred(env, deferred, err);
48     } else {
49         LockRequest *lockRequest =
50             new LockRequest(this, AsyncLockManager::GetCurrentTid(env), env, cb, mode, options, deferred);
51         std::unique_lock<std::mutex> lock(asyncLockMutex_);
52         pendingList_.push_back(lockRequest);
53         ProcessPendingLockRequestUnsafe(env, lockRequest);
54     }
55     return promise;
56 }
57 
CleanUpLockRequestOnCompletion(LockRequest * lockRequest)58 void AsyncLock::CleanUpLockRequestOnCompletion(LockRequest* lockRequest)
59 {
60     std::unique_lock<std::mutex> lock(asyncLockMutex_);
61     auto it = std::find(heldList_.begin(), heldList_.end(), lockRequest);
62     if (it == heldList_.end()) {
63         HILOG_FATAL("Lock is not found");
64         return;
65     }
66     heldList_.erase(it);
67     if (heldList_.empty()) {
68         // There are may be other shared lock requests in the heldList_.
69         // IF so, we mustn't change the status.
70         lockStatus_ = LOCK_MODE_UNLOCK;
71     }
72     napi_env env = lockRequest->GetEnv();
73     delete lockRequest;
74     if (pendingList_.empty()) {
75         if (refCount_ == 0 && heldList_.empty()) {
76             lock.unlock();
77             AsyncLockManager::CheckAndRemoveLock(this);
78         }
79         return;
80     }
81     ProcessPendingLockRequestUnsafe(env);
82 }
83 
CleanUpLockRequest(LockRequest * lockRequest)84 bool AsyncLock::CleanUpLockRequest(LockRequest *lockRequest)
85 {
86     std::unique_lock<std::mutex> lock(asyncLockMutex_);
87     auto it = std::find(pendingList_.begin(), pendingList_.end(), lockRequest);
88     if (it == pendingList_.end()) {
89         // the lock got held while we were waiting on the mutex, no-op
90         return false;
91     }
92     // we won the race, need to remove the request from the queue and handle the time out event
93     pendingList_.erase(it);
94     return true;
95 }
96 
97 template <bool isAsync>
ProcessLockRequest(napi_env env,LockRequest * lockRequest)98 void AsyncLock::ProcessLockRequest(napi_env env, LockRequest *lockRequest)
99 {
100     heldList_.push_back(lockRequest);
101     pendingList_.pop_front();
102     asyncLockMutex_.unlock();
103     if constexpr (isAsync) {
104         lockRequest->CallCallbackAsync();
105     } else {
106         lockRequest->CallCallback();
107     }
108     asyncLockMutex_.lock();
109 }
110 
ProcessPendingLockRequest(napi_env env,LockRequest * syncLockRequest)111 void AsyncLock::ProcessPendingLockRequest(napi_env env, LockRequest* syncLockRequest)
112 {
113     std::unique_lock<std::mutex> lock(asyncLockMutex_);
114     if (pendingList_.empty()) {
115         if (refCount_ == 0 && heldList_.empty()) {
116             lock.unlock();
117             AsyncLockManager::CheckAndRemoveLock(this);
118         }
119         return;
120     }
121     ProcessPendingLockRequestUnsafe(env, syncLockRequest);
122 }
123 
ProcessPendingLockRequestUnsafe(napi_env env,LockRequest * syncLockRequest)124 void AsyncLock::ProcessPendingLockRequestUnsafe(napi_env env, LockRequest *syncLockRequest)
125 {
126     LockRequest *lockRequest = pendingList_.front();
127     if (!CanAcquireLockUnsafe(lockRequest->GetMode())) {
128         return;
129     }
130     lockStatus_ = lockRequest->GetMode();
131     if (lockStatus_ == LOCK_MODE_SHARED) {
132         do {
133             if (syncLockRequest == lockRequest) {
134                 ProcessLockRequest<false>(env, lockRequest);
135             } else {
136                 ProcessLockRequest<true>(env, lockRequest);
137             }
138             if (pendingList_.empty()) {
139                 break;
140             }
141             lockRequest = pendingList_.front();
142         } while (lockRequest->GetMode() == LOCK_MODE_SHARED);
143     } else {
144         ProcessLockRequest<true>(env, lockRequest);
145     }
146 }
147 
CanAcquireLockUnsafe(LockMode mode)148 bool AsyncLock::CanAcquireLockUnsafe(LockMode mode)
149 {
150     if (heldList_.empty()) {
151         return true;
152     }
153     if (mode == LOCK_MODE_SHARED && lockStatus_ == LOCK_MODE_SHARED) {
154         return true;
155     }
156     if (lockStatus_ == LOCK_MODE_UNLOCK) {
157         return true;
158     }
159     return false;
160 }
161 
CanAcquireLock(LockMode mode)162 bool AsyncLock::CanAcquireLock(LockMode mode)
163 {
164     std::unique_lock<std::mutex> lock(asyncLockMutex_);
165     return CanAcquireLockUnsafe(mode);
166 }
167 
FillLockState(napi_env env,napi_value held,napi_value pending)168 napi_status AsyncLock::FillLockState(napi_env env, napi_value held, napi_value pending)
169 {
170     std::unique_lock<std::mutex> lock(asyncLockMutex_);
171     uint32_t idx = 0;
172     for (LockRequest *rq : heldList_) {
173         napi_value info = CreateLockInfo(env, rq);
174         bool pendingException = false;
175         napi_is_exception_pending(env, &pendingException);
176         if (pendingException) {
177             return napi_pending_exception;
178         }
179         napi_value index;
180         napi_create_int32(env, idx, &index);
181         napi_status status = napi_set_property(env, held, index, info);
182         if (status != napi_ok) {
183             return status;
184         }
185         ++idx;
186     }
187     idx = 0;
188     for (LockRequest *rq : pendingList_) {
189         napi_value info = CreateLockInfo(env, rq);
190         bool pendingException = false;
191         napi_is_exception_pending(env, &pendingException);
192         if (pendingException) {
193             return napi_pending_exception;
194         }
195         napi_value index;
196         napi_create_int32(env, idx, &index);
197         napi_status status = napi_set_property(env, pending, index, info);
198         if (status != napi_ok) {
199             return status;
200         }
201         ++idx;
202     }
203     return napi_ok;
204 }
205 
CreateLockInfo(napi_env env,const LockRequest * rq)206 napi_value AsyncLock::CreateLockInfo(napi_env env, const LockRequest *rq)
207 {
208     napi_value info;
209     NAPI_CALL(env, napi_create_object(env, &info));
210     napi_value name;
211     NAPI_CALL(env, napi_create_string_utf8(env, lockName_.c_str(), NAPI_AUTO_LENGTH, &name));
212     napi_value mode;
213     NAPI_CALL(env, napi_create_int32(env, rq->GetMode(), &mode));
214     napi_value tid;
215     NAPI_CALL(env, napi_create_int32(env, rq->GetTid(), &tid));
216 
217     napi_property_descriptor properties[] = {
218         DECLARE_NAPI_PROPERTY("name", name),
219         DECLARE_NAPI_PROPERTY("mode", mode),
220         DECLARE_NAPI_PROPERTY("contextId", tid),
221     };
222     NAPI_CALL(env, napi_define_properties(env, info, sizeof(properties) / sizeof(properties[0]), properties));
223     return info;
224 }
225 
IsReadyForDeletion()226 bool AsyncLock::IsReadyForDeletion()
227 {
228     std::unique_lock<std::mutex> lock(asyncLockMutex_);
229     return refCount_ == 0 && pendingList_.empty() && heldList_.empty();
230 }
231 
IncRefCount()232 uint32_t AsyncLock::IncRefCount()
233 {
234     std::unique_lock<std::mutex> lock(asyncLockMutex_);
235     return ++refCount_;
236 }
237 
DecRefCount()238 uint32_t AsyncLock::DecRefCount()
239 {
240     std::unique_lock<std::mutex> lock(asyncLockMutex_);
241     return --refCount_;
242 }
243 
GetSatisfiedRequestInfos()244 std::vector<RequestCreationInfo> AsyncLock::GetSatisfiedRequestInfos()
245 {
246     std::vector<RequestCreationInfo> result;
247     std::unique_lock<std::mutex> lock(asyncLockMutex_);
248     for (auto *request : heldList_) {
249         result.push_back(RequestCreationInfo { request->GetTid(), request->GetCreationStacktrace() });
250     }
251     return result;
252 }
253 
GetPendingRequestInfos()254 std::vector<RequestCreationInfo> AsyncLock::GetPendingRequestInfos()
255 {
256     std::vector<RequestCreationInfo> result;
257     std::unique_lock<std::mutex> lock(asyncLockMutex_);
258     for (auto *request : pendingList_) {
259         result.push_back(RequestCreationInfo { request->GetTid(), request->GetCreationStacktrace() });
260     }
261     return result;
262 }
263 
264 } // namespace Commonlibrary::Concurrent::LocksModule
265