• 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 "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