14d6c458bSopenharmony_ci/* 24d6c458bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 34d6c458bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44d6c458bSopenharmony_ci * you may not use this file except in compliance with the License. 54d6c458bSopenharmony_ci * You may obtain a copy of the License at 64d6c458bSopenharmony_ci * 74d6c458bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84d6c458bSopenharmony_ci * 94d6c458bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104d6c458bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114d6c458bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124d6c458bSopenharmony_ci * See the License for the specific language governing permissions and 134d6c458bSopenharmony_ci * limitations under the License. 144d6c458bSopenharmony_ci */ 154d6c458bSopenharmony_ci 164d6c458bSopenharmony_ci#include <uv.h> 174d6c458bSopenharmony_ci#include "async_lock.h" 184d6c458bSopenharmony_ci#include "async_lock_manager.h" 194d6c458bSopenharmony_ci#include "helper/error_helper.h" 204d6c458bSopenharmony_ci#include "helper/napi_helper.h" 214d6c458bSopenharmony_ci#include "helper/object_helper.h" 224d6c458bSopenharmony_ci#include "tools/log.h" 234d6c458bSopenharmony_ci 244d6c458bSopenharmony_cinamespace Commonlibrary::Concurrent::LocksModule { 254d6c458bSopenharmony_ciusing namespace Commonlibrary::Concurrent::Common::Helper; 264d6c458bSopenharmony_ci 274d6c458bSopenharmony_ciAsyncLock::AsyncLock(const std::string &lockName) 284d6c458bSopenharmony_ci{ 294d6c458bSopenharmony_ci lockName_ = lockName; 304d6c458bSopenharmony_ci anonymousLockId_ = 0; 314d6c458bSopenharmony_ci} 324d6c458bSopenharmony_ci 334d6c458bSopenharmony_ciAsyncLock::AsyncLock(uint32_t lockId) 344d6c458bSopenharmony_ci{ 354d6c458bSopenharmony_ci lockName_ = ""; 364d6c458bSopenharmony_ci anonymousLockId_ = lockId; 374d6c458bSopenharmony_ci} 384d6c458bSopenharmony_ci 394d6c458bSopenharmony_cinapi_value AsyncLock::LockAsync(napi_env env, napi_ref cb, LockMode mode, const LockOptions &options) 404d6c458bSopenharmony_ci{ 414d6c458bSopenharmony_ci napi_value promise; 424d6c458bSopenharmony_ci napi_deferred deferred; 434d6c458bSopenharmony_ci napi_create_promise(env, &deferred, &promise); 444d6c458bSopenharmony_ci LockRequest *lockRequest = 454d6c458bSopenharmony_ci new LockRequest(this, AsyncLockManager::GetCurrentTid(env), env, cb, mode, options, deferred); 464d6c458bSopenharmony_ci std::unique_lock<std::mutex> lock(asyncLockMutex_); 474d6c458bSopenharmony_ci if (!CanAcquireLock(lockRequest) && options.isAvailable) { 484d6c458bSopenharmony_ci napi_value err; 494d6c458bSopenharmony_ci NAPI_CALL(env, napi_create_string_utf8(env, "The lock is acquired", NAPI_AUTO_LENGTH, &err)); 504d6c458bSopenharmony_ci napi_reject_deferred(env, deferred, err); 514d6c458bSopenharmony_ci } else { 524d6c458bSopenharmony_ci lockRequest->OnQueued(options.timeoutMillis); 534d6c458bSopenharmony_ci pendingList_.push_back(lockRequest); 544d6c458bSopenharmony_ci ProcessPendingLockRequestUnsafe(env, lockRequest); 554d6c458bSopenharmony_ci } 564d6c458bSopenharmony_ci return promise; 574d6c458bSopenharmony_ci} 584d6c458bSopenharmony_ci 594d6c458bSopenharmony_civoid AsyncLock::CleanUpLockRequestOnCompletion(LockRequest* lockRequest) 604d6c458bSopenharmony_ci{ 614d6c458bSopenharmony_ci std::unique_lock<std::mutex> lock(asyncLockMutex_); 624d6c458bSopenharmony_ci auto it = std::find(heldList_.begin(), heldList_.end(), lockRequest); 634d6c458bSopenharmony_ci if (it == heldList_.end()) { 644d6c458bSopenharmony_ci HILOG_FATAL("Lock is not found"); 654d6c458bSopenharmony_ci return; 664d6c458bSopenharmony_ci } 674d6c458bSopenharmony_ci heldList_.erase(it); 684d6c458bSopenharmony_ci if (heldList_.empty()) { 694d6c458bSopenharmony_ci // There are may be other shared lock requests in the heldList_. 704d6c458bSopenharmony_ci // IF so, we mustn't change the status. 714d6c458bSopenharmony_ci lockStatus_ = LOCK_MODE_UNLOCK; 724d6c458bSopenharmony_ci } 734d6c458bSopenharmony_ci napi_env env = lockRequest->GetEnv(); 744d6c458bSopenharmony_ci delete lockRequest; 754d6c458bSopenharmony_ci ProcessPendingLockRequestUnsafe(env); 764d6c458bSopenharmony_ci} 774d6c458bSopenharmony_ci 784d6c458bSopenharmony_cibool AsyncLock::CleanUpLockRequestOnTimeout(LockRequest* lockRequest) 794d6c458bSopenharmony_ci{ 804d6c458bSopenharmony_ci std::unique_lock<std::mutex> lock(asyncLockMutex_); 814d6c458bSopenharmony_ci auto it = std::find(pendingList_.begin(), pendingList_.end(), lockRequest); 824d6c458bSopenharmony_ci if (it == pendingList_.end()) { 834d6c458bSopenharmony_ci // the lock got held while we were waiting on the mutex, no-op 844d6c458bSopenharmony_ci return false; 854d6c458bSopenharmony_ci } 864d6c458bSopenharmony_ci // we won the race, need to remove the request from the queue and handle the time out event 874d6c458bSopenharmony_ci pendingList_.erase(it); 884d6c458bSopenharmony_ci return true; 894d6c458bSopenharmony_ci} 904d6c458bSopenharmony_ci 914d6c458bSopenharmony_citemplate<bool isAsync> 924d6c458bSopenharmony_civoid AsyncLock::ProcessLockRequest(LockRequest* lockRequest) 934d6c458bSopenharmony_ci{ 944d6c458bSopenharmony_ci lockRequest->OnSatisfied(); 954d6c458bSopenharmony_ci heldList_.push_back(lockRequest); 964d6c458bSopenharmony_ci pendingList_.pop_front(); 974d6c458bSopenharmony_ci asyncLockMutex_.unlock(); 984d6c458bSopenharmony_ci if constexpr (isAsync) { 994d6c458bSopenharmony_ci lockRequest->CallCallbackAsync(); 1004d6c458bSopenharmony_ci } else { 1014d6c458bSopenharmony_ci lockRequest->CallCallback(); 1024d6c458bSopenharmony_ci } 1034d6c458bSopenharmony_ci asyncLockMutex_.lock(); 1044d6c458bSopenharmony_ci} 1054d6c458bSopenharmony_ci 1064d6c458bSopenharmony_civoid AsyncLock::ProcessPendingLockRequest(napi_env env, LockRequest* syncLockRequest) 1074d6c458bSopenharmony_ci{ 1084d6c458bSopenharmony_ci std::unique_lock<std::mutex> lock(asyncLockMutex_); 1094d6c458bSopenharmony_ci ProcessPendingLockRequestUnsafe(env, syncLockRequest); 1104d6c458bSopenharmony_ci} 1114d6c458bSopenharmony_ci 1124d6c458bSopenharmony_civoid AsyncLock::ProcessPendingLockRequestUnsafe(napi_env env, LockRequest* syncLockRequest) 1134d6c458bSopenharmony_ci{ 1144d6c458bSopenharmony_ci if (pendingList_.empty()) { 1154d6c458bSopenharmony_ci if (refCount_ == 0) { 1164d6c458bSopenharmony_ci // No more refs to the lock. We need to delete the instance but we cannot do it right now 1174d6c458bSopenharmony_ci // because asyncLockMutex_ is acquired. Do it asynchronously. 1184d6c458bSopenharmony_ci AsyncDestroy(env); 1194d6c458bSopenharmony_ci } 1204d6c458bSopenharmony_ci return; 1214d6c458bSopenharmony_ci } 1224d6c458bSopenharmony_ci LockRequest *lockRequest = pendingList_.front(); 1234d6c458bSopenharmony_ci if (!CanAcquireLock(lockRequest)) { 1244d6c458bSopenharmony_ci return; 1254d6c458bSopenharmony_ci } 1264d6c458bSopenharmony_ci lockStatus_ = lockRequest->GetMode(); 1274d6c458bSopenharmony_ci if (lockStatus_ == LOCK_MODE_SHARED) { 1284d6c458bSopenharmony_ci do { 1294d6c458bSopenharmony_ci if (syncLockRequest == lockRequest) { 1304d6c458bSopenharmony_ci ProcessLockRequest<false>(lockRequest); 1314d6c458bSopenharmony_ci } else { 1324d6c458bSopenharmony_ci ProcessLockRequest<true>(lockRequest); 1334d6c458bSopenharmony_ci } 1344d6c458bSopenharmony_ci if (pendingList_.empty()) { 1354d6c458bSopenharmony_ci break; 1364d6c458bSopenharmony_ci } 1374d6c458bSopenharmony_ci lockRequest = pendingList_.front(); 1384d6c458bSopenharmony_ci } while (lockRequest->GetMode() == LOCK_MODE_SHARED); 1394d6c458bSopenharmony_ci } else { 1404d6c458bSopenharmony_ci ProcessLockRequest<true>(lockRequest); 1414d6c458bSopenharmony_ci } 1424d6c458bSopenharmony_ci} 1434d6c458bSopenharmony_ci 1444d6c458bSopenharmony_cibool AsyncLock::CanAcquireLock(LockRequest *lockRequest) 1454d6c458bSopenharmony_ci{ 1464d6c458bSopenharmony_ci if (heldList_.empty()) { 1474d6c458bSopenharmony_ci return true; 1484d6c458bSopenharmony_ci } 1494d6c458bSopenharmony_ci if (lockRequest->GetMode() == LOCK_MODE_SHARED && lockStatus_ == LOCK_MODE_SHARED) { 1504d6c458bSopenharmony_ci return true; 1514d6c458bSopenharmony_ci } 1524d6c458bSopenharmony_ci if (lockStatus_ == LOCK_MODE_UNLOCK) { 1534d6c458bSopenharmony_ci return true; 1544d6c458bSopenharmony_ci } 1554d6c458bSopenharmony_ci return false; 1564d6c458bSopenharmony_ci} 1574d6c458bSopenharmony_ci 1584d6c458bSopenharmony_cinapi_status AsyncLock::FillLockState(napi_env env, napi_value held, napi_value pending) 1594d6c458bSopenharmony_ci{ 1604d6c458bSopenharmony_ci std::unique_lock<std::mutex> lock(asyncLockMutex_); 1614d6c458bSopenharmony_ci uint32_t idx = 0; 1624d6c458bSopenharmony_ci for (LockRequest *rq : heldList_) { 1634d6c458bSopenharmony_ci napi_value info = CreateLockInfo(env, rq); 1644d6c458bSopenharmony_ci bool pendingException = false; 1654d6c458bSopenharmony_ci napi_is_exception_pending(env, &pendingException); 1664d6c458bSopenharmony_ci if (pendingException) { 1674d6c458bSopenharmony_ci return napi_pending_exception; 1684d6c458bSopenharmony_ci } 1694d6c458bSopenharmony_ci napi_value index; 1704d6c458bSopenharmony_ci napi_create_int32(env, idx, &index); 1714d6c458bSopenharmony_ci napi_status status = napi_set_property(env, held, index, info); 1724d6c458bSopenharmony_ci if (status != napi_ok) { 1734d6c458bSopenharmony_ci return status; 1744d6c458bSopenharmony_ci } 1754d6c458bSopenharmony_ci ++idx; 1764d6c458bSopenharmony_ci } 1774d6c458bSopenharmony_ci idx = 0; 1784d6c458bSopenharmony_ci for (LockRequest *rq : pendingList_) { 1794d6c458bSopenharmony_ci napi_value info = CreateLockInfo(env, rq); 1804d6c458bSopenharmony_ci bool pendingException = false; 1814d6c458bSopenharmony_ci napi_is_exception_pending(env, &pendingException); 1824d6c458bSopenharmony_ci if (pendingException) { 1834d6c458bSopenharmony_ci return napi_pending_exception; 1844d6c458bSopenharmony_ci } 1854d6c458bSopenharmony_ci napi_value index; 1864d6c458bSopenharmony_ci napi_create_int32(env, idx, &index); 1874d6c458bSopenharmony_ci napi_status status = napi_set_property(env, pending, index, info); 1884d6c458bSopenharmony_ci if (status != napi_ok) { 1894d6c458bSopenharmony_ci return status; 1904d6c458bSopenharmony_ci } 1914d6c458bSopenharmony_ci ++idx; 1924d6c458bSopenharmony_ci } 1934d6c458bSopenharmony_ci return napi_ok; 1944d6c458bSopenharmony_ci} 1954d6c458bSopenharmony_ci 1964d6c458bSopenharmony_cinapi_value AsyncLock::CreateLockInfo(napi_env env, const LockRequest *rq) 1974d6c458bSopenharmony_ci{ 1984d6c458bSopenharmony_ci napi_value info; 1994d6c458bSopenharmony_ci NAPI_CALL(env, napi_create_object(env, &info)); 2004d6c458bSopenharmony_ci napi_value name; 2014d6c458bSopenharmony_ci NAPI_CALL(env, napi_create_string_utf8(env, lockName_.c_str(), NAPI_AUTO_LENGTH, &name)); 2024d6c458bSopenharmony_ci napi_value mode; 2034d6c458bSopenharmony_ci NAPI_CALL(env, napi_create_int32(env, rq->GetMode(), &mode)); 2044d6c458bSopenharmony_ci napi_value tid; 2054d6c458bSopenharmony_ci NAPI_CALL(env, napi_create_int32(env, rq->GetTid(), &tid)); 2064d6c458bSopenharmony_ci 2074d6c458bSopenharmony_ci napi_property_descriptor properties[] = { 2084d6c458bSopenharmony_ci DECLARE_NAPI_PROPERTY("name", name), 2094d6c458bSopenharmony_ci DECLARE_NAPI_PROPERTY("mode", mode), 2104d6c458bSopenharmony_ci DECLARE_NAPI_PROPERTY("contextId", tid), 2114d6c458bSopenharmony_ci }; 2124d6c458bSopenharmony_ci NAPI_CALL(env, napi_define_properties(env, info, sizeof(properties) / sizeof(properties[0]), properties)); 2134d6c458bSopenharmony_ci return info; 2144d6c458bSopenharmony_ci} 2154d6c458bSopenharmony_ci 2164d6c458bSopenharmony_civoid AsyncLock::AsyncDestroy(napi_env env) 2174d6c458bSopenharmony_ci{ 2184d6c458bSopenharmony_ci napi_value resourceName; 2194d6c458bSopenharmony_ci napi_create_string_utf8(env, "AsyncLock::AsyncDestroyCallback", NAPI_AUTO_LENGTH, &resourceName); 2204d6c458bSopenharmony_ci auto *data = new std::pair<AsyncLock *, napi_async_work>(); 2214d6c458bSopenharmony_ci data->first = this; 2224d6c458bSopenharmony_ci napi_async_work &work = data->second; 2234d6c458bSopenharmony_ci napi_status status = napi_create_async_work( 2244d6c458bSopenharmony_ci env, nullptr, resourceName, [](napi_env, void *) {}, AsyncDestroyCallback, data, &work); 2254d6c458bSopenharmony_ci if (status != napi_ok) { 2264d6c458bSopenharmony_ci HILOG_FATAL("Internal error: cannot create async work"); 2274d6c458bSopenharmony_ci } 2284d6c458bSopenharmony_ci status = napi_queue_async_work(env, work); 2294d6c458bSopenharmony_ci if (status != napi_ok) { 2304d6c458bSopenharmony_ci HILOG_FATAL("Internal error: cannot queue async work"); 2314d6c458bSopenharmony_ci } 2324d6c458bSopenharmony_ci} 2334d6c458bSopenharmony_ci 2344d6c458bSopenharmony_civoid AsyncLock::AsyncDestroyCallback(napi_env env, napi_status, void *data) 2354d6c458bSopenharmony_ci{ 2364d6c458bSopenharmony_ci auto *lockAndWork = reinterpret_cast<std::pair<AsyncLock *, napi_async_work> *>(data); 2374d6c458bSopenharmony_ci delete lockAndWork->first; 2384d6c458bSopenharmony_ci napi_delete_async_work(env, lockAndWork->second); 2394d6c458bSopenharmony_ci delete lockAndWork; 2404d6c458bSopenharmony_ci} 2414d6c458bSopenharmony_ci 2424d6c458bSopenharmony_ciuint32_t AsyncLock::IncRefCount() 2434d6c458bSopenharmony_ci{ 2444d6c458bSopenharmony_ci std::unique_lock<std::mutex> lock(asyncLockMutex_); 2454d6c458bSopenharmony_ci return ++refCount_; 2464d6c458bSopenharmony_ci} 2474d6c458bSopenharmony_ci 2484d6c458bSopenharmony_ciuint32_t AsyncLock::DecRefCount() 2494d6c458bSopenharmony_ci{ 2504d6c458bSopenharmony_ci asyncLockMutex_.lock(); 2514d6c458bSopenharmony_ci uint32_t count = --refCount_; 2524d6c458bSopenharmony_ci if (count == 0) { 2534d6c458bSopenharmony_ci // No refs to the instance. We can delete it right now if there are no more lock requests. 2544d6c458bSopenharmony_ci // In case there are some lock requests, the last processed lock request will delete the instance. 2554d6c458bSopenharmony_ci if (pendingList_.size() == 0 && heldList_.size() == 0) { 2564d6c458bSopenharmony_ci asyncLockMutex_.unlock(); 2574d6c458bSopenharmony_ci delete this; 2584d6c458bSopenharmony_ci return 0; 2594d6c458bSopenharmony_ci } 2604d6c458bSopenharmony_ci } 2614d6c458bSopenharmony_ci asyncLockMutex_.unlock(); 2624d6c458bSopenharmony_ci return count; 2634d6c458bSopenharmony_ci} 2644d6c458bSopenharmony_ci 2654d6c458bSopenharmony_cistd::vector<RequestCreationInfo> AsyncLock::GetSatisfiedRequestInfos() 2664d6c458bSopenharmony_ci{ 2674d6c458bSopenharmony_ci std::vector<RequestCreationInfo> result; 2684d6c458bSopenharmony_ci std::unique_lock<std::mutex> lock(asyncLockMutex_); 2694d6c458bSopenharmony_ci for (auto *request : heldList_) { 2704d6c458bSopenharmony_ci result.push_back(RequestCreationInfo { request->GetTid(), request->GetCreationStacktrace() }); 2714d6c458bSopenharmony_ci } 2724d6c458bSopenharmony_ci return result; 2734d6c458bSopenharmony_ci} 2744d6c458bSopenharmony_ci 2754d6c458bSopenharmony_cistd::vector<RequestCreationInfo> AsyncLock::GetPendingRequestInfos() 2764d6c458bSopenharmony_ci{ 2774d6c458bSopenharmony_ci std::vector<RequestCreationInfo> result; 2784d6c458bSopenharmony_ci std::unique_lock<std::mutex> lock(asyncLockMutex_); 2794d6c458bSopenharmony_ci for (auto *request : pendingList_) { 2804d6c458bSopenharmony_ci result.push_back(RequestCreationInfo { request->GetTid(), request->GetCreationStacktrace() }); 2814d6c458bSopenharmony_ci } 2824d6c458bSopenharmony_ci return result; 2834d6c458bSopenharmony_ci} 2844d6c458bSopenharmony_ci 2854d6c458bSopenharmony_ci} // namespace Commonlibrary::Concurrent::LocksModule 286