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 "condition_manager.h"
17 #include "condition_variable.h"
18 #include "helper/error_helper.h"
19
20 namespace Commonlibrary::Concurrent::Condition {
21
22 static thread_local napi_ref conditionClassRef = nullptr;
23
Init(napi_env env,napi_value exports)24 napi_value ConditionManager::Init(napi_env env, napi_value exports)
25 {
26 napi_value locks;
27 bool hasLocks {false};
28 napi_has_named_property(env, exports, "locks", &hasLocks);
29 if (hasLocks) {
30 napi_get_named_property(env, exports, "locks", &locks);
31 } else {
32 napi_create_object(env, &locks);
33 napi_set_named_property(env, exports, "locks", locks);
34 }
35
36 napi_property_descriptor props[] = {
37 DECLARE_NAPI_INSTANCE_OBJECT_PROPERTY("wait"), DECLARE_NAPI_INSTANCE_OBJECT_PROPERTY("waitFor"),
38 DECLARE_NAPI_INSTANCE_OBJECT_PROPERTY("notifyAll"), DECLARE_NAPI_INSTANCE_OBJECT_PROPERTY("notifyOne"),
39 DECLARE_NAPI_STATIC_FUNCTION("request", Request),
40 };
41 napi_value ConditionVariableClass;
42 napi_define_sendable_class(env, "ConditionVariable", NAPI_AUTO_LENGTH, Constructor, nullptr,
43 sizeof(props) / sizeof(props[0]), props, nullptr, &ConditionVariableClass);
44 napi_create_reference(env, ConditionVariableClass, 1, &conditionClassRef);
45 napi_set_named_property(env, locks, "ConditionVariable", ConditionVariableClass);
46
47 return exports;
48 }
49
Wait(napi_env env,napi_callback_info cbinfo)50 napi_value ConditionManager::Wait(napi_env env, napi_callback_info cbinfo)
51 {
52 napi_value thisVar;
53 napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
54
55 ConditionVariable *cond;
56 napi_unwrap_sendable(env, thisVar, reinterpret_cast<void **>(&cond));
57 napi_deferred deferred;
58 napi_value promise;
59 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
60
61 cond->AddTask(env, deferred);
62
63 return promise;
64 }
65
WaitFor(napi_env env,napi_callback_info cbinfo)66 napi_value ConditionManager::WaitFor(napi_env env, napi_callback_info cbinfo)
67 {
68 size_t argc = 1;
69 napi_value args;
70 napi_value thisVar;
71 napi_get_cb_info(env, cbinfo, &argc, &args, &thisVar, nullptr);
72
73 if (argc != 1) {
74 Common::Helper::ErrorHelper::ThrowError(env, Common::Helper::ErrorHelper::TYPE_ERROR,
75 "Invalid number of arguments");
76 return nullptr;
77 }
78
79 int32_t timeout {0};
80 napi_status status = napi_get_value_int32(env, args, &timeout);
81 if (status != napi_ok) {
82 Common::Helper::ErrorHelper::ThrowError(env, Common::Helper::ErrorHelper::TYPE_ERROR,
83 "Invalid argument type. Expected number");
84 return nullptr;
85 }
86
87 ConditionVariable *cond;
88 napi_unwrap_sendable(env, thisVar, reinterpret_cast<void **>(&cond));
89 napi_deferred deferred;
90 napi_value promise;
91 NAPI_CALL(env, napi_create_promise(env, &deferred, &promise));
92
93 if (timeout < 0) {
94 timeout = 0;
95 }
96 cond->AddTask(env, deferred, timeout);
97
98 return promise;
99 }
100
NotifyAll(napi_env env,napi_callback_info cbinfo)101 napi_value ConditionManager::NotifyAll(napi_env env, napi_callback_info cbinfo)
102 {
103 napi_value thisVar;
104 napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
105
106 ConditionVariable *cond;
107 napi_unwrap_sendable(env, thisVar, reinterpret_cast<void **>(&cond));
108
109 cond->FinishTask(true);
110 return nullptr;
111 }
112
NotifyOne(napi_env env,napi_callback_info cbinfo)113 napi_value ConditionManager::NotifyOne(napi_env env, napi_callback_info cbinfo)
114 {
115 napi_value thisVar;
116 napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
117
118 ConditionVariable *cond;
119 napi_unwrap_sendable(env, thisVar, reinterpret_cast<void **>(&cond));
120
121 cond->FinishTask();
122 return nullptr;
123 }
124
Constructor(napi_env env,napi_callback_info cbinfo)125 napi_value ConditionManager::Constructor(napi_env env, napi_callback_info cbinfo)
126 {
127 size_t argc = Common::Helper::NapiHelper::GetCallbackInfoArgc(env, cbinfo);
128 NAPI_ASSERT(env, argc == 0 || argc == 1, "AsyncLock::Constructor: the number of params must be zero or one");
129 auto args = std::make_unique<napi_value[]>(argc);
130 napi_value thisVar;
131 napi_get_cb_info(env, cbinfo, &argc, args.get(), &thisVar, nullptr);
132
133 ConditionVariable *cond = nullptr;
134 if (argc == 1) {
135 napi_valuetype type;
136 NAPI_CALL(env, napi_typeof(env, args[0], &type));
137 if (type != napi_string) {
138 Common::Helper::ErrorHelper::ThrowError(env, Common::Helper::ErrorHelper::TYPE_ERROR,
139 "Request:: param must be string");
140 return nullptr;
141 }
142
143 std::string condName = Common::Helper::NapiHelper::GetString(env, args[0]);
144 cond = ConditionVariable::FindOrCreateCondition(condName);
145 } else {
146 cond = new ConditionVariable();
147 }
148
149 napi_property_descriptor properties[] = {
150 DECLARE_NAPI_FUNCTION_WITH_DATA("wait", Wait, thisVar),
151 DECLARE_NAPI_FUNCTION_WITH_DATA("waitFor", WaitFor, thisVar),
152 DECLARE_NAPI_FUNCTION_WITH_DATA("notifyAll", NotifyAll, thisVar),
153 DECLARE_NAPI_FUNCTION_WITH_DATA("notifyOne", NotifyOne, thisVar),
154 };
155
156 NAPI_CALL(env, napi_define_properties(env, thisVar, sizeof(properties) / sizeof(properties[0]), properties));
157 napi_wrap_sendable(env, thisVar, reinterpret_cast<void *>(cond), ConditionManager::Destructor, nullptr);
158 return thisVar;
159 }
160
Request(napi_env env,napi_callback_info cbinfo)161 napi_value ConditionManager::Request(napi_env env, napi_callback_info cbinfo)
162 {
163 size_t argc = Common::Helper::NapiHelper::GetCallbackInfoArgc(env, cbinfo);
164 NAPI_ASSERT(env, argc == 1, "Request:: the number of params must be one");
165 auto args = std::make_unique<napi_value[]>(argc);
166 NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, args.get(), nullptr, nullptr));
167 napi_value conditionClass;
168 NAPI_CALL(env, napi_get_reference_value(env, conditionClassRef, &conditionClass));
169 napi_value instance;
170 NAPI_CALL(env, napi_new_instance(env, conditionClass, argc, args.get(), &instance));
171
172 return instance;
173 }
174
Destructor(napi_env env,void * nativeObject,void * finalizeHint)175 void ConditionManager::Destructor(napi_env env, void *nativeObject, void *finalizeHint)
176 {
177 auto cond = reinterpret_cast<ConditionVariable *>(nativeObject);
178 cond->TryRemoveCondition();
179 }
180
181 } // namespace Commonlibrary::Concurrent::Condition
182