diff --git a/js_concurrent_module/utils/locks/async_lock.cpp b/js_concurrent_module/utils/locks/async_lock.cpp index 61821fdeb6e31c636e2517be1ef841fb3446caee..8b2c1ab78eba174a88391a7654dee9524e11d65d 100644 --- a/js_concurrent_module/utils/locks/async_lock.cpp +++ b/js_concurrent_module/utils/locks/async_lock.cpp @@ -45,9 +45,8 @@ napi_value AsyncLock::LockAsync(napi_env env, napi_ref cb, LockMode mode, const NAPI_CALL(env, napi_create_string_utf8(env, "The lock is acquired", NAPI_AUTO_LENGTH, &err)); napi_reject_deferred(env, deferred, err); } else { - lockRequest->OnQueued(env, options.timeoutMillis); pendingList_.push_back(lockRequest); - ProcessPendingLockRequestUnsafe(env, lockRequest); + ProcessPendingLockRequestUnsafe(lockRequest); } return promise; } @@ -61,13 +60,12 @@ void AsyncLock::CleanUpLockRequestOnCompletion(LockRequest* lockRequest) return; } heldList_.erase(it); + delete lockRequest; if (heldList_.empty()) { // There are may be other shared lock requests in the heldList_. // IF so, we mustn't change the status. lockStatus_ = LOCK_MODE_UNLOCK; } - napi_env env = lockRequest->GetEnv(); - delete lockRequest; if (pendingList_.empty()) { if (refCount_ == 0 && heldList_.empty()) { lock.unlock(); @@ -75,38 +73,48 @@ void AsyncLock::CleanUpLockRequestOnCompletion(LockRequest* lockRequest) } return; } - ProcessPendingLockRequestUnsafe(env); + ProcessPendingLockRequestUnsafe(); } -bool AsyncLock::CleanUpLockRequestOnTimeout(LockRequest* lockRequest) +void AsyncLock::FindAndAbortRequest(LockRequest *lockRequest, LockRequestFinishReason reason) { std::unique_lock lock(asyncLockMutex_); auto it = std::find(pendingList_.begin(), pendingList_.end(), lockRequest); if (it == pendingList_.end()) { // the lock got held while we were waiting on the mutex, no-op - return false; + return; } // we won the race, need to remove the request from the queue and handle the time out event pendingList_.erase(it); - return true; + asyncLockMutex_.unlock(); + lockRequest->Finish(reason); + asyncLockMutex_.lock(); + delete lockRequest; + if (pendingList_.empty()) { + if (refCount_ == 0 && heldList_.empty()) { + lock.unlock(); + AsyncLockManager::CheckAndRemoveLock(this); + } + return; + } + ProcessPendingLockRequestUnsafe(); } template -void AsyncLock::ProcessLockRequest(napi_env env, LockRequest *lockRequest) +void AsyncLock::ProcessLockRequest(LockRequest *lockRequest) { - lockRequest->OnSatisfied(env); heldList_.push_back(lockRequest); pendingList_.pop_front(); asyncLockMutex_.unlock(); if constexpr (isAsync) { - lockRequest->CallCallbackAsync(); + lockRequest->Finish(LockRequestFinishReason::ASYNC_CALLBACK); } else { - lockRequest->CallCallback(); + lockRequest->Finish(LockRequestFinishReason::CALLBACK); } asyncLockMutex_.lock(); } -void AsyncLock::ProcessPendingLockRequest(napi_env env, LockRequest* syncLockRequest) +void AsyncLock::ProcessPendingLockRequest(LockRequest *syncLockRequest) { std::unique_lock lock(asyncLockMutex_); if (pendingList_.empty()) { @@ -116,10 +124,10 @@ void AsyncLock::ProcessPendingLockRequest(napi_env env, LockRequest* syncLockReq } return; } - ProcessPendingLockRequestUnsafe(env, syncLockRequest); + ProcessPendingLockRequestUnsafe(syncLockRequest); } -void AsyncLock::ProcessPendingLockRequestUnsafe(napi_env env, LockRequest *syncLockRequest) +void AsyncLock::ProcessPendingLockRequestUnsafe(LockRequest *syncLockRequest) { LockRequest *lockRequest = pendingList_.front(); if (!CanAcquireLock(lockRequest)) { @@ -129,9 +137,9 @@ void AsyncLock::ProcessPendingLockRequestUnsafe(napi_env env, LockRequest *syncL if (lockStatus_ == LOCK_MODE_SHARED) { do { if (syncLockRequest == lockRequest) { - ProcessLockRequest(env, lockRequest); + ProcessLockRequest(lockRequest); } else { - ProcessLockRequest(env, lockRequest); + ProcessLockRequest(lockRequest); } if (pendingList_.empty()) { break; @@ -139,7 +147,7 @@ void AsyncLock::ProcessPendingLockRequestUnsafe(napi_env env, LockRequest *syncL lockRequest = pendingList_.front(); } while (lockRequest->GetMode() == LOCK_MODE_SHARED); } else { - ProcessLockRequest(env, lockRequest); + ProcessLockRequest(lockRequest); } } diff --git a/js_concurrent_module/utils/locks/async_lock.h b/js_concurrent_module/utils/locks/async_lock.h index e6feddc6865b281263770b8cf63ed814aca7f30f..ab493981d77f48d9b2d29429607b03c6e934d871 100644 --- a/js_concurrent_module/utils/locks/async_lock.h +++ b/js_concurrent_module/utils/locks/async_lock.h @@ -39,9 +39,9 @@ public: napi_value LockAsync(napi_env env, napi_ref cb, LockMode mode, const LockOptions &options); void CleanUpLockRequestOnCompletion(LockRequest* lockRequest); - bool CleanUpLockRequestOnTimeout(LockRequest* lockRequest); + void FindAndAbortRequest(LockRequest *lockRequest, LockRequestFinishReason reason); napi_status FillLockState(napi_env env, napi_value held, napi_value pending); - void ProcessPendingLockRequest(napi_env env, LockRequest* syncLockRequest = nullptr); + void ProcessPendingLockRequest(LockRequest* syncLockRequest = nullptr); // Increment the reference counter uint32_t IncRefCount(); @@ -67,8 +67,8 @@ private: bool CanAcquireLock(LockRequest *lockRequest); napi_value CreateLockInfo(napi_env env, const LockRequest *rq); template - void ProcessLockRequest(napi_env env, LockRequest *lockRequest); - void ProcessPendingLockRequestUnsafe(napi_env env, LockRequest* syncLockRequest = nullptr); + void ProcessLockRequest(LockRequest *lockRequest); + void ProcessPendingLockRequestUnsafe(LockRequest* syncLockRequest = nullptr); std::list pendingList_ {}; std::list heldList_ {}; diff --git a/js_concurrent_module/utils/locks/lock_request.cpp b/js_concurrent_module/utils/locks/lock_request.cpp index e4d871450c2e85a5beb13e268592313511174c98..b612998f7ee10081a57497f07ba74df851550acc 100644 --- a/js_concurrent_module/utils/locks/lock_request.cpp +++ b/js_concurrent_module/utils/locks/lock_request.cpp @@ -13,9 +13,10 @@ * limitations under the License. */ +#include "lock_request.h" #include "async_lock_manager.h" #include "helper/hitrace_helper.h" -#include "js_concurrent_module/utils/locks/weak_wrap.h" +#include "napi/native_common.h" #include "tools/log.h" namespace Commonlibrary::Concurrent::LocksModule { @@ -31,118 +32,147 @@ LockRequest::LockRequest(AsyncLock *lock, tid_t tid, napi_env env, napi_ref cb, mode_(mode), options_(options), deferred_(deferred), - work_(nullptr), - timeoutActive_(false), engineId_(engine_->GetId()) { - // timeout timer initialization: just fill the data fields, do not arm it - timeoutTimer_ = new uv_timer_t(); - uv_timer_init(NapiHelper::GetLibUV(env), timeoutTimer_); - RequestTimeoutData *data = new RequestTimeoutData(lock, this); - timeoutTimer_->data = data; - // saving the creation point (file, function and line) for future use NativeEngine *engine = reinterpret_cast(env); engine->BuildJsStackTrace(creationStacktrace_); - NAPI_CALL_RETURN_VOID(env_, napi_add_env_cleanup_hook(env_, EnvCleanUp, this)); - napi_value resourceName; - napi_create_string_utf8(env, "AsyncLock::AsyncCallback", NAPI_AUTO_LENGTH, &resourceName); - napi_status status = napi_create_async_work(env_, nullptr, resourceName, AsyncLockManager::EmptyExecuteCallback, - AsyncAfterWorkCallback, this, &work_); - if (status != napi_ok) { - HILOG_FATAL("Internal error: cannot create async work"); - } + AddEnvCleanupHook(); + CreateReference(); + InitTimer(); + InitAsyncHandle(); } -void LockRequest::EnvCleanUp(void *arg) +LockRequest::~LockRequest() { - LockRequest *lockRequest = static_cast(arg); - std::unique_lock guard(lockRequest->lockRequestMutex_); - napi_delete_reference(lockRequest->env_, lockRequest->callback_); - lockRequest->callback_ = nullptr; - lockRequest->env_ = nullptr; - lockRequest->CleanTimer(); + CloseTimer(); + CloseAsyncHandle(); } -void LockRequest::CleanTimer() +void LockRequest::Finish(LockRequestFinishReason reason) { - if (stopTimerTsfn_ != nullptr) { - NAPI_CALL_RETURN_VOID(env_, napi_release_threadsafe_function(stopTimerTsfn_, napi_tsfn_abort)); - stopTimerTsfn_ = nullptr; + switch (reason) { + case LockRequestFinishReason::ASYNC_CALLBACK: { + if (NativeEngine::IsAlive(engine_) && engineId_ == engine_->GetId()) { + SendAsyncHandle(); + } else { + lock_->CleanUpLockRequestOnCompletion(this); + } + break; + } + case LockRequestFinishReason::CALLBACK: + RemoveEnvCleanupHook(); + StopTimer(); + CallCallback(); + break; + case LockRequestFinishReason::TIMEOUT: + RemoveEnvCleanupHook(); + DeleteReference(); + HandleRequestTimeout(); + break; + case LockRequestFinishReason::ENV_CLEANUP: + DeleteReference(); + StopTimer(); + break; + default: + HILOG_FATAL("Internal error: invalid enum LockRequestFinishReason %{public}hhu", reason); } - RequestTimeoutData *data = static_cast(timeoutTimer_->data); - delete data; - timeoutTimer_->data = nullptr; - uv_close(reinterpret_cast(timeoutTimer_), DeallocateTimeoutTimerCallback); } -void LockRequest::DeallocateTimeoutTimerCallback(uv_handle_t* handle) +void LockRequest::InitTimer() { - delete handle; + if (options_.timeoutMillis <= 0) { + return; + } + timeoutTimer_ = new uv_timer_t(); + int status = uv_timer_init(NapiHelper::GetLibUV(env_), timeoutTimer_); + if (status != 0) { + HILOG_FATAL("Internal error: unable to initialize the AsyncLock timeout timer %{public}d", status); + return; + } + timeoutTimer_->data = this; + status = uv_timer_start( + timeoutTimer_, + [](uv_timer_t *handle) { + LockRequest *lockRequest = static_cast(handle->data); + lockRequest->lock_->FindAndAbortRequest(lockRequest, LockRequestFinishReason::TIMEOUT); + }, + options_.timeoutMillis, 0); + if (status != 0) { + HILOG_FATAL("Internal error: unable to start the AsyncLock timeout timer %{public}d", status); + } } -LockRequest::~LockRequest() +void LockRequest::StopTimer() { - std::unique_lock guard(lockRequestMutex_); - if (env_ == nullptr) { + if (timeoutTimer_ == nullptr) { return; } - CleanTimer(); + int status = uv_timer_stop(static_cast(timeoutTimer_)); + if (status != 0) { + HILOG_FATAL("Internal error: unable to stop the AsyncLock timeout timer %{public}d", status); + } } -void LockRequest::AsyncAfterWorkCallback(napi_env env, [[maybe_unused]] napi_status status, void *data) +void LockRequest::CloseTimer() { - LockRequest* lockRequest = reinterpret_cast(data); - std::unique_lock lock(lockRequest->lockRequestMutex_); - napi_delete_async_work(env, lockRequest->work_); - lockRequest->work_ = nullptr; - if (lockRequest->env_ == nullptr) { - lock.unlock(); - HILOG_ERROR("AsyncCallback is called after env cleaned up"); - lockRequest->lock_->CleanUpLockRequestOnCompletion(lockRequest); + if (timeoutTimer_ == nullptr) { return; } - lock.unlock(); - lockRequest->CallCallback(); + timeoutTimer_->data = nullptr; + uv_close(reinterpret_cast(timeoutTimer_), [](uv_handle_t *handle) { delete handle; }); } -napi_value LockRequest::FinallyCallback(napi_env env, napi_callback_info info) +void LockRequest::InitAsyncHandle() { - LockRequest *lockRequest = nullptr; + asyncHandle_ = new uv_async_t(); + int status = uv_async_init(NapiHelper::GetLibUV(env_), asyncHandle_, [](uv_async_t *handle) { + LockRequest *lockRequest = static_cast(handle->data); + lockRequest->Finish(LockRequestFinishReason::CALLBACK); + }); + if (status != 0) { + HILOG_FATAL("Internal error: unable to initialize the AsyncLock async handle %{public}d", status); + } + asyncHandle_->data = this; +} - NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, nullptr, reinterpret_cast(&lockRequest))); - HITRACE_HELPER_METER_NAME("AsyncLock FinallyCallback, " + lockRequest->GetLockInfo()); - lockRequest->lock_->CleanUpLockRequestOnCompletion(lockRequest); +void LockRequest::SendAsyncHandle() +{ + int status = uv_async_send(asyncHandle_); + if (status != 0) { + HILOG_FATAL("Internal error: unable to send the AsyncLock async handle %{public}d", status); + } +} - napi_value undefined; - napi_get_undefined(env, &undefined); - return undefined; +void LockRequest::CloseAsyncHandle() +{ + asyncHandle_->data = nullptr; + uv_close(reinterpret_cast(asyncHandle_), [](uv_handle_t *handle) { delete handle; }); } -void LockRequest::CallCallbackAsync() +void LockRequest::AddEnvCleanupHook() { - lockRequestMutex_.lock(); - if (env_ == nullptr || !NativeEngine::IsAlive(engine_) || engineId_ != engine_->GetId()) { - lockRequestMutex_.unlock(); - HILOG_ERROR("Callback is called after env cleaned up"); - lock_->CleanUpLockRequestOnCompletion(this); - return; - } - napi_status status = napi_queue_async_work(env_, work_); - lockRequestMutex_.unlock(); - if (status != napi_ok) { - HILOG_FATAL("Internal error: cannot queue async work"); - } + NAPI_CALL_RETURN_VOID(env_, napi_add_env_cleanup_hook(env_, EnvCleanup, this)); +} + +void LockRequest::RemoveEnvCleanupHook() +{ + NAPI_CALL_RETURN_VOID(env_, napi_remove_env_cleanup_hook(env_, EnvCleanup, this)); +} + +void LockRequest::CreateReference() {} + +void LockRequest::DeleteReference() +{ + NAPI_CALL_RETURN_VOID(env_, napi_delete_reference(env_, callback_)); } void LockRequest::CallCallback() { HITRACE_HELPER_METER_NAME("AsyncLock Callback, " + GetLockInfo()); - napi_remove_env_cleanup_hook(env_, EnvCleanUp, this); if (AbortIfNeeded()) { - napi_delete_reference(env_, callback_); - callback_ = nullptr; + DeleteReference(); lock_->CleanUpLockRequestOnCompletion(this); return; } @@ -150,48 +180,31 @@ void LockRequest::CallCallback() NAPI_CALL_RETURN_VOID(env_, napi_get_reference_value(env_, callback_, &cb)); napi_value result; napi_status status = napi_call_function(env_, nullptr, cb, 0, nullptr, &result); - napi_delete_reference(env_, callback_); - callback_ = nullptr; if (status == napi_ok) { - napi_resolve_deferred(env_, deferred_, result); + NAPI_CALL_RETURN_VOID(env_, napi_resolve_deferred(env_, deferred_, result)); bool isPromise = false; - napi_is_promise(env_, result, &isPromise); + NAPI_CALL_RETURN_VOID(env_, napi_is_promise(env_, result, &isPromise)); if (isPromise) { - // Save lock_ and env_ into locals. If the callback returns fulfilled promise, - // the lock request will be destroyed during napi_call_function(finallyFn). - napi_env env = env_; - // Increament reference counter for the lock. Do it to prevent lock destruction. napi_value finallyFn; - napi_get_named_property(env, result, "finally", &finallyFn); + NAPI_CALL_RETURN_VOID(env_, napi_get_named_property(env_, result, "finally", &finallyFn)); napi_value finallyCallback; - napi_create_function(env, nullptr, 0, FinallyCallback, this, &finallyCallback); + NAPI_CALL_RETURN_VOID(env_, + napi_create_function(env_, nullptr, 0, FinallyCallback, this, &finallyCallback)); napi_value finallyPromise; - napi_call_function(env, result, finallyFn, 1, &finallyCallback, &finallyPromise); + NAPI_CALL_RETURN_VOID(env_, + napi_call_function(env_, result, finallyFn, 1, &finallyCallback, &finallyPromise)); return; } } else { napi_value err; - napi_get_and_clear_last_exception(env_, &err); - napi_reject_deferred(env_, deferred_, err); + NAPI_CALL_RETURN_VOID(env_, napi_get_and_clear_last_exception(env_, &err)); + NAPI_CALL_RETURN_VOID(env_, napi_reject_deferred(env_, deferred_, err)); } + DeleteReference(); lock_->CleanUpLockRequestOnCompletion(this); } -void LockRequest::OnSatisfied(napi_env env) -{ - if (timeoutActive_) { - DisarmTimeoutTimer(env); - } -} - -void LockRequest::OnQueued(napi_env env, uint32_t timeoutMillis) -{ - if (timeoutMillis > 0) { - ArmTimeoutTimer(env, timeoutMillis); - } -} - bool LockRequest::AbortIfNeeded() { if (options_.signal == nullptr) { @@ -210,94 +223,24 @@ bool LockRequest::AbortIfNeeded() return true; } -void LockRequest::ArmTimeoutTimer(napi_env env, uint32_t timeoutMillis) -{ - timeoutActive_ = true; - uv_update_time(NapiHelper::GetLibUV(env)); - uv_timer_start(timeoutTimer_, TimeoutCallback, timeoutMillis, 0); - napi_value resourceName = nullptr; - NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, "stopTimerTsfn", NAPI_AUTO_LENGTH, &resourceName)); - NAPI_CALL_RETURN_VOID(env, napi_create_threadsafe_function(env, nullptr, nullptr, resourceName, 0, 1, nullptr, - nullptr, timeoutTimer_, StopTimer, &stopTimerTsfn_)); - // NOTE: handle the abortsignal functionality in the future - // NOTE: need to check call results for 0 -} - -void LockRequest::DisarmTimeoutTimer(napi_env env) -{ - std::unique_lock guard(lockRequestMutex_); - if (stopTimerTsfn_ == nullptr) { - return; - } - NAPI_CALL_RETURN_VOID(env, napi_call_threadsafe_function(stopTimerTsfn_, new WeakWrap(GetWeakPtr()), - napi_tsfn_blocking)); - timeoutActive_ = false; -} - -void LockRequest::StopTimer(napi_env env, napi_value jsCallback, void *context, void *data) +void LockRequest::HandleRequestTimeout() { - WeakWrap *weakRequest = static_cast *>(data); - if (weakRequest->GetWeakPtr().expired() || uv_is_closing(static_cast(context))) { - delete weakRequest; - return; - } - uv_timer_stop(static_cast(context)); - delete weakRequest; -} - -void LockRequest::TimeoutCallback(uv_timer_t *handle) -{ - RequestTimeoutData *data = static_cast(handle->data); - if (data == nullptr) { - // fail! something terribly bad happened! - HILOG_FATAL("Internal error: unable to handle the AsyncLock timeout"); - return; - } // Check deadlocks and form the rejector value with or w/o the warning. It is required to be done // first in order to obtain the actual data. - std::string error; - AsyncLockManager::DumpLocksInfoForThread(AsyncLockManager::GetCurrentTid(data->request->env_), error); - - // NOTE: both AsyncLock and LockRequest might be deleted here, but at this point we imply that - // AsyncLock exists, later on we we will handle the case when it does not - - // NOTE: - // We might have the race with the lock acquirer function here and the request will be - // already deleted if the race is won by the acquirer. So we should firstly make sure that - // the race is won by us and then call the request's methods - - bool success = data->lock->CleanUpLockRequestOnTimeout(data->request); - if (!success) { - return; - } - data->request->HandleRequestTimeout(std::move(error)); - AsyncLock *lock = data->lock; - napi_env env = data->request->env_; - napi_remove_env_cleanup_hook(env, EnvCleanUp, data->request); - // will delete 'data' too - delete data->request; - lock->ProcessPendingLockRequest(env); -} + std::string errorMessage; + AsyncLockManager::DumpLocksInfoForThread(AsyncLockManager::GetCurrentTid(env_), errorMessage); -void LockRequest::HandleRequestTimeout(std::string &&errorMessage) -{ HILOG_ERROR("AsyncLock lockAsync() timed out! Information: %s", errorMessage.c_str()); // here we imply that there are no races already and the timeout function should do its job // by rejecting the associated promise with an BusinessError instance. - napi_delete_reference(env_, callback_); - callback_ = nullptr; - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env_, &scope); - if (scope == nullptr) { - return; - } + napi_status status {napi_ok}; + Common::Helper::HandleScope scope(env_, status); + NAPI_CALL_RETURN_VOID(env_, status); HILOG_ERROR("AsyncLock lockAsync() timed out! Rejecting the promise."); napi_value error = ErrorHelper::NewError(env_, ErrorHelper::ERR_ASYNCLOCK_TIMEOUT, errorMessage.c_str()); napi_reject_deferred(env_, deferred_, error); - - napi_close_handle_scope(env_, scope); } std::string LockRequest::GetLockInfo() const @@ -311,4 +254,24 @@ std::string LockRequest::GetLockInfo() const return strTrace; } +napi_value LockRequest::FinallyCallback(napi_env env, napi_callback_info info) +{ + LockRequest *lockRequest = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, nullptr, reinterpret_cast(&lockRequest))); + HITRACE_HELPER_METER_NAME("AsyncLock FinallyCallback, " + lockRequest->GetLockInfo()); + + lockRequest->DeleteReference(); + lockRequest->lock_->CleanUpLockRequestOnCompletion(lockRequest); + + napi_value undefined; + NAPI_CALL(env, napi_get_undefined(env, &undefined)); + return undefined; +} + +void LockRequest::EnvCleanup(void *arg) +{ + LockRequest *lockRequest = static_cast(arg); + lockRequest->lock_->FindAndAbortRequest(lockRequest, LockRequestFinishReason::ENV_CLEANUP); +} + } // namespace Commonlibrary::Concurrent::LocksModule diff --git a/js_concurrent_module/utils/locks/lock_request.h b/js_concurrent_module/utils/locks/lock_request.h index 2ffa7dde7bef6e1ad951730d19f991ca6529c894..4bb40a8b3da0b7a14156602eb92072d6c0bd60a5 100644 --- a/js_concurrent_module/utils/locks/lock_request.h +++ b/js_concurrent_module/utils/locks/lock_request.h @@ -16,6 +16,7 @@ #ifndef JS_CONCURRENT_MODULE_UTILS_LOCKS_LOCK_REQUEST_H #define JS_CONCURRENT_MODULE_UTILS_LOCKS_LOCK_REQUEST_H +#include #include #include #include @@ -26,6 +27,9 @@ #include "helper/object_helper.h" namespace Commonlibrary::Concurrent::LocksModule { + +enum class LockRequestFinishReason : uint8_t { ASYNC_CALLBACK, CALLBACK, TIMEOUT, ENV_CLEANUP }; + enum LockMode { LOCK_MODE_UNLOCK, LOCK_MODE_SHARED, @@ -41,17 +45,12 @@ struct LockOptions { class AsyncLock; -class LockRequest : public std::enable_shared_from_this { +class LockRequest { public: LockRequest(AsyncLock* lock, tid_t tid, napi_env env, napi_ref cb, LockMode mode, const LockOptions &options, napi_deferred deferred); ~LockRequest(); - std::weak_ptr GetWeakPtr() - { - return weak_from_this(); - } - tid_t GetTid() const { return tid_; @@ -77,25 +76,31 @@ public: return env_; } - void CallCallbackAsync(); - void CallCallback(); - - void OnQueued(napi_env env, uint32_t timeoutMillis); - void OnSatisfied(napi_env env); + void Finish(LockRequestFinishReason reason); private: + void InitTimer(); + void StopTimer(); + void CloseTimer(); + + void InitAsyncHandle(); + void SendAsyncHandle(); + void CloseAsyncHandle(); + + void AddEnvCleanupHook(); + void RemoveEnvCleanupHook(); + + void CreateReference(); + void DeleteReference(); + + void CallCallback(); bool AbortIfNeeded(); - void ArmTimeoutTimer(napi_env env, uint32_t timeoutMillis); - void DisarmTimeoutTimer(napi_env env); - void HandleRequestTimeout(std::string &&errorMessage); + void HandleRequestTimeout(); + std::string GetLockInfo() const; - void CleanTimer(); - static void AsyncAfterWorkCallback(napi_env env, napi_status status, void *data); + static napi_value FinallyCallback(napi_env env, napi_callback_info info); - static void TimeoutCallback(uv_timer_t *handle); - static void DeallocateTimeoutTimerCallback(uv_handle_t* handle); - static void EnvCleanUp(void* arg); - static void StopTimer(napi_env env, napi_value jsCallback, void* context, void* data); + static void EnvCleanup(void *arg); AsyncLock* lock_; tid_t tid_; @@ -106,19 +111,10 @@ private: LockMode mode_; LockOptions options_; napi_deferred deferred_; - napi_async_work work_; - uv_timer_t *timeoutTimer_; - bool timeoutActive_; - napi_threadsafe_function stopTimerTsfn_{nullptr}; - std::mutex lockRequestMutex_; + uv_timer_t *timeoutTimer_ {nullptr}; + uv_async_t *asyncHandle_ {nullptr}; uint64_t engineId_; }; -struct RequestTimeoutData { - RequestTimeoutData(AsyncLock* l, LockRequest* r): lock(l), request(r) {} - AsyncLock* lock; - LockRequest* request; -}; - } // namespace Commonlibrary::Concurrent::LocksModule #endif // JS_CONCURRENT_MODULE_UTILS_LOCKS_LOCK_REQUEST_H diff --git a/js_concurrent_module/utils/test/test_locks.cpp b/js_concurrent_module/utils/test/test_locks.cpp index 51f0a282dfd3a4ff0202ec5d22b9d70cc5cea983..980cd3c91f368ec0ad8c8c0e0aac4fcd4c66b010 100644 --- a/js_concurrent_module/utils/test/test_locks.cpp +++ b/js_concurrent_module/utils/test/test_locks.cpp @@ -257,7 +257,6 @@ TEST_F(LocksTest, SharedLockSingle) LockOptions options; lock->LockAsync(env, callback_ref, LOCK_MODE_SHARED, options); - Loop(LOOP_ONCE); ASSERT_TRUE(isCalled); } @@ -324,7 +323,6 @@ TEST_F(LocksTest, SharedLockMulti) LockOptions options; barrier.arrive_and_wait(); lockPtr->LockAsync(env, callback_ref, LOCK_MODE_SHARED, options); - Loop(LOOP_ONCE); LocksTest::DestroyEngine(); }); napi_env env = GetEnv(); @@ -334,7 +332,6 @@ TEST_F(LocksTest, SharedLockMulti) LockOptions options; lock->LockAsync(env, callback_ref, LOCK_MODE_SHARED, options); - Loop(LOOP_ONCE); t.join(); ASSERT_FALSE(callbackData.fail); ASSERT_EQ(callbackData.callCount, 2U); @@ -539,12 +536,10 @@ TEST_F(LocksTest, SharedModeWithEnvDestroyed) bool isPromise {false}; ASSERT_CHECK_CALL(napi_is_promise(env, result, &isPromise)); ASSERT_TRUE(isPromise); - Loop(LOOP_ONCE); LocksTest::DestroyEngine(); }); - Loop(LOOP_ONCE); t.join(); ASSERT_EQ(callbackData.callCount, 2U); } @@ -615,7 +610,6 @@ TEST_F(LocksTest, TimeoutLockWithEnvDestroyedTest) napi_value result; ASSERT_CHECK_CALL(napi_call_function(env, lock, lockAsync, argc, args, &result)); - Loop(LOOP_ONCE); LocksTest::Sleep(); callbackData.end.arrive_and_wait(); LocksTest::DestroyEngine();