1 /*
2 * Copyright (c) 2023 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 "napi/native_api.h"
17 #include <cerrno>
18 #include <csignal>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <ifaddrs.h>
23 #include <js_native_api_types.h>
24 #include <threads.h>
25 #include <unistd.h>
26
27 #define PARAM_0 0
28 #define PARAM_1 1
29 #define PARAM_2 2
30 #define PARAM_UNNORMAL (-1)
31 #define ERRON_0 0
32 #define SUCCESS 1
33 #define FAIL (-1)
34 #define TSS_SET_VALUE (void *)0xFF
35 #define hs (100.0)
36 #define ms (1000.0)
37 #define us (1000000)
38 #define ns (1000000000L)
39
40 static tss_t key;
41 static int g_count = PARAM_0;
42 volatile int t_status = PARAM_0;
43 static thrd_t thr;
44
exception_handler(int sig)45 void exception_handler(int sig) { exit(t_status); }
46
threadfun_create(void *arg)47 int threadfun_create(void *arg)
48 {
49 signal(SIGSEGV, exception_handler);
50 g_count++;
51 thrd_exit(thrd_success);
52 }
Thrd_create(napi_env env, napi_callback_info info)53 static napi_value Thrd_create(napi_env env, napi_callback_info info)
54 {
55 thrd_t id;
56 int result;
57 result = thrd_create(&id, threadfun_create, nullptr);
58 struct timespec;
59 thrd_join(id, nullptr);
60 g_count = PARAM_0;
61 napi_value results = nullptr;
62 napi_create_int32(env, result, &results);
63 return results;
64 }
threadfunc_current(void *arg)65 int threadfunc_current(void *arg)
66 {
67 g_count++;
68 thrd_current();
69 thrd_exit(thrd_success);
70 }
71
Thrd_current(napi_env env, napi_callback_info info)72 static napi_value Thrd_current(napi_env env, napi_callback_info info)
73 {
74 int result;
75 result = thrd_create(&thr, threadfunc_current, nullptr);
76 thrd_join(thr, nullptr);
77 g_count = PARAM_0;
78 napi_value napi_value = nullptr;
79 napi_create_int32(env, result, &napi_value);
80 return napi_value;
81 }
82
threadfunc_detach(void *arg)83 int threadfunc_detach(void *arg)
84 {
85 g_count++;
86 thrd_detach(thrd_current());
87 thrd_exit(thrd_success);
88 }
Thrd_detach(napi_env env, napi_callback_info info)89 static napi_value Thrd_detach(napi_env env, napi_callback_info info)
90 {
91 g_count = PARAM_0;
92 thrd_t id;
93 int result;
94 result = thrd_create(&id, threadfunc_detach, nullptr);
95 napi_value napi_value = nullptr;
96 napi_create_int32(env, result, &napi_value);
97 return napi_value;
98 }
99
threadfunc_equal(void *arg)100 int threadfunc_equal(void *arg)
101 {
102 g_count++;
103 thrd_t id = thrd_current();
104 if (!(thrd_equal(id, thr))) {
105 }
106 thrd_exit(thrd_success);
107 }
108
Thrd_equal(napi_env env, napi_callback_info info)109 static napi_value Thrd_equal(napi_env env, napi_callback_info info)
110 {
111 g_count = PARAM_0;
112 int result;
113 thrd_create(&thr, threadfunc_equal, nullptr);
114 result = thrd_join(thr, nullptr);
115 g_count = PARAM_0;
116 napi_value napi_value = nullptr;
117 napi_create_int32(env, result, &napi_value);
118 return napi_value;
119 }
threadfun_exit(void *arg)120 int threadfun_exit(void *arg)
121 {
122 signal(SIGSEGV, exception_handler);
123 g_count++;
124 thrd_exit(thrd_success);
125 }
Thrd_exit(napi_env env, napi_callback_info info)126 static napi_value Thrd_exit(napi_env env, napi_callback_info info)
127 {
128 thrd_t id;
129 int result;
130 result = thrd_create(&id, threadfun_exit, nullptr);
131 struct timespec;
132 thrd_join(id, nullptr);
133 g_count = PARAM_0;
134 napi_value results = nullptr;
135 napi_create_int32(env, result, &results);
136 return results;
137 }
threadfun_join(void *arg)138 int threadfun_join(void *arg)
139 {
140 g_count++;
141 return PARAM_0;
142 }
Thrd_join(napi_env env, napi_callback_info info)143 static napi_value Thrd_join(napi_env env, napi_callback_info info)
144 {
145 thrd_t id;
146 int result;
147 thrd_create(&id, threadfun_join, nullptr);
148 result = thrd_join(id, nullptr);
149 g_count = PARAM_0;
150 napi_value napi_value = nullptr;
151 napi_create_int32(env, result, &napi_value);
152 return napi_value;
153 }
threadfun_sleep(void *arg)154 int threadfun_sleep(void *arg)
155 {
156 g_count++;
157 struct timespec const *tl = (struct timespec const *)arg;
158 if (thrd_sleep(tl, nullptr) != PARAM_0) {
159 }
160 thrd_exit(thrd_success);
161 }
Thrd_sleep(napi_env env, napi_callback_info info)162 static napi_value Thrd_sleep(napi_env env, napi_callback_info info)
163 {
164 int result;
165 thrd_t id;
166 struct timespec ts = {.tv_sec = PARAM_1};
167 result = thrd_create(&id, threadfun_sleep, (void *)(&ts));
168 thrd_join(id, nullptr);
169 g_count = PARAM_0;
170 napi_value napi_value = nullptr;
171 napi_create_int32(env, result, &napi_value);
172 return napi_value;
173 }
174
ustimer(struct timespec tss, struct timespec tse)175 double ustimer(struct timespec tss, struct timespec tse)
176 {
177 double sd = difftime(tse.tv_sec, tss.tv_sec);
178 long nsd = tse.tv_nsec - tss.tv_nsec;
179 if (nsd < PARAM_0) {
180 return us * (sd - PARAM_1) + (ns + nsd) / ms;
181 } else {
182 return us * (sd) + nsd / ms;
183 }
184 }
185
Yieldfunc(void)186 void Yieldfunc(void)
187 {
188 struct timespec tss, tse;
189 timespec_get(&tss, TIME_UTC);
190 do {
191 thrd_yield();
192 timespec_get(&tse, TIME_UTC);
193 } while (ustimer(tss, tse) < hs);
194 }
195
Thrd_yield(napi_env env, napi_callback_info info)196 static napi_value Thrd_yield(napi_env env, napi_callback_info info)
197 {
198 g_count = PARAM_0;
199 int result = PARAM_0;
200 struct timespec tss, tse;
201 timespec_get(&tss, TIME_UTC);
202 Yieldfunc();
203 timespec_get(&tse, TIME_UTC);
204 ustimer(tss, tse);
205 napi_value napi_value = nullptr;
206 napi_create_int32(env, result, &napi_value);
207 return napi_value;
208 }
209
Tss_create(napi_env env, napi_callback_info info)210 static napi_value Tss_create(napi_env env, napi_callback_info info)
211 {
212 size_t argc = PARAM_1;
213 napi_value args[1] = {nullptr};
214 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
215 int isSuccessCase;
216 napi_get_value_int32(env, args[0], &isSuccessCase);
217
218 int toJsResult = FAIL;
219 int ret;
220
221 if (isSuccessCase == PARAM_1) {
222 ret = tss_create(&key, nullptr);
223 if (ret == thrd_success) {
224 toJsResult = SUCCESS;
225 }
226 }
227 tss_delete(key);
228
229 napi_value result = nullptr;
230 napi_create_int32(env, toJsResult, &result);
231 return result;
232 }
233
Tss_set(napi_env env, napi_callback_info info)234 static napi_value Tss_set(napi_env env, napi_callback_info info)
235 {
236 size_t argc = PARAM_1;
237 napi_value args[1] = {nullptr};
238 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
239 int isSuccessCase;
240 napi_get_value_int32(env, args[0], &isSuccessCase);
241
242 int toJsResult = PARAM_0;
243 int ret;
244
245 if (isSuccessCase == PARAM_1) {
246 ret = tss_create(&key, nullptr);
247 if (ret == thrd_success) {
248 ret = tss_set(key, TSS_SET_VALUE);
249 if (ret == thrd_success) {
250 toJsResult = SUCCESS;
251 }
252 }
253 }
254 tss_delete(key);
255
256 napi_value result = nullptr;
257 napi_create_int32(env, toJsResult, &result);
258 return result;
259 }
260
Tss_get(napi_env env, napi_callback_info info)261 static napi_value Tss_get(napi_env env, napi_callback_info info)
262 {
263 size_t argc = PARAM_1;
264 napi_value args[1] = {nullptr};
265 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
266 int isSuccessCase;
267 napi_get_value_int32(env, args[0], &isSuccessCase);
268
269 int toJsResult = FAIL;
270 int ret;
271
272 if (isSuccessCase == PARAM_1) {
273 tss_create(&key, nullptr);
274 ret = tss_set(key, TSS_SET_VALUE);
275 if (ret == thrd_success) {
276 void *value = tss_get(key);
277 if (value != PARAM_0 && value == TSS_SET_VALUE) {
278 toJsResult = SUCCESS;
279 }
280 }
281 }
282 tss_delete(key);
283
284 napi_value result = nullptr;
285 napi_create_int32(env, toJsResult, &result);
286 return result;
287 }
288
Tss_delete(napi_env env, napi_callback_info info)289 static napi_value Tss_delete(napi_env env, napi_callback_info info)
290 {
291 size_t argc = PARAM_1;
292 napi_value args[1] = {nullptr};
293 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
294 int isSuccessCase;
295 napi_get_value_int32(env, args[0], &isSuccessCase);
296
297 int toJsResult = FAIL;
298
299 if (isSuccessCase == PARAM_1) {
300 tss_create(&key, nullptr);
301 tss_set(key, TSS_SET_VALUE);
302 void *value = tss_get(key);
303 if (value != PARAM_0 && value == TSS_SET_VALUE) {
304 tss_delete(key);
305 value = tss_get(key);
306 if (value == PARAM_0) {
307 toJsResult = SUCCESS;
308 }
309 }
310 }
311
312 napi_value result = nullptr;
313 napi_create_int32(env, toJsResult, &result);
314 return result;
315 }
316
Cnd_wait(napi_env env, napi_callback_info info)317 static napi_value Cnd_wait(napi_env env, napi_callback_info info)
318 {
319 mtx_t mutex;
320 cnd_t cond;
321 cnd_init(&cond);
322 mtx_lock(&mutex);
323 int backParam = cnd_wait(&cond, &mutex);
324 mtx_unlock(&mutex);
325 cnd_destroy(&cond);
326 mtx_destroy(&mutex);
327 napi_value result = nullptr;
328 napi_create_int32(env, backParam, &result);
329 return result;
330 }
DoPlainTests(int (*fn1)(void *arg), void *arg1, int (*fn2)(void *arg), void *arg2)331 int DoPlainTests(int (*fn1)(void *arg), void *arg1, int (*fn2)(void *arg), void *arg2)
332 {
333 int ret = PARAM_0;
334 int pid = PARAM_0;
335 pid = fork();
336 if (pid == FAIL) {
337 return FAIL;
338 }
339 if (pid == PARAM_0) {
340 _exit(PARAM_0);
341 }
342 if (fn2) {
343 ret = fn2(arg2);
344 }
345 return ret;
346 }
Cndtimewaittest(void *testarg)347 int Cndtimewaittest(void *testarg)
348 {
349 const struct timespec time_point = {0};
350 mtx_t mutex;
351 cnd_t cond;
352 cnd_init(&cond);
353 mtx_lock(&mutex);
354 int backParam = cnd_timedwait(&cond, &mutex, &time_point);
355 mtx_unlock(&mutex);
356 cnd_destroy(&cond);
357 mtx_destroy(&mutex);
358 return backParam;
359 }
Cnd_timedWait(napi_env env, napi_callback_info info)360 static napi_value Cnd_timedWait(napi_env env, napi_callback_info info)
361 {
362 void *test = nullptr;
363 DoPlainTests(Cndtimewaittest, test, nullptr, nullptr);
364
365 napi_value result = nullptr;
366 napi_create_int32(env, SUCCESS, &result);
367 return result;
368 }
369
Cnd_broadcast(napi_env env, napi_callback_info info)370 static napi_value Cnd_broadcast(napi_env env, napi_callback_info info)
371 {
372 cnd_t cond;
373 cnd_init(&cond);
374 int backParam = cnd_broadcast(&cond);
375 napi_value result = nullptr;
376 napi_create_int32(env, backParam, &result);
377 return result;
378 }
379
Cnd_destroy(napi_env env, napi_callback_info info)380 static napi_value Cnd_destroy(napi_env env, napi_callback_info info)
381 {
382 cnd_t cond;
383 int backParam = cnd_init(&cond);
384 cnd_destroy(&cond);
385 napi_value result = nullptr;
386 napi_create_int32(env, backParam, &result);
387 return result;
388 }
389
Cnd_signal(napi_env env, napi_callback_info info)390 static napi_value Cnd_signal(napi_env env, napi_callback_info info)
391 {
392 cnd_t cond;
393 cnd_init(&cond);
394 int backParam = cnd_signal(&cond);
395 napi_value result = nullptr;
396 napi_create_int32(env, backParam, &result);
397 return result;
398 }
399
Cnd_init(napi_env env, napi_callback_info info)400 static napi_value Cnd_init(napi_env env, napi_callback_info info)
401 {
402 cnd_t cond;
403 int backParam = cnd_init(&cond);
404 napi_value result = nullptr;
405 napi_create_int32(env, backParam, &result);
406 return result;
407 }
408
DoOnce(void)409 void DoOnce(void)
410 {
411 static char list[100];
412 static char buf[12] = "called once";
413 FILE *fp = fopen("/data/storage/el2/base/files/Fzl.txt", "a+");
414 fwrite(buf, sizeof(char), strlen(buf), fp);
415 fclose(fp);
416 FILE *fpSecond = fopen("/data/storage/el2/base/files/Fzl.txt", "r");
417 fread(list, sizeof(list), PARAM_1, fpSecond);
418 fclose(fpSecond);
419 }
420 static once_flag flag = ONCE_FLAG_INIT;
421
Func(void *data)422 void Func(void *data) { call_once(&flag, DoOnce); }
423
CallOnce(napi_env env, napi_callback_info info)424 static napi_value CallOnce(napi_env env, napi_callback_info info)
425 {
426 napi_value result = nullptr;
427 int returnValue = FAIL;
428 thrd_t firstParam, secondParam, thirdParam, fourthParam;
429 thrd_create(&firstParam, (thrd_start_t)Func, nullptr);
430 thrd_create(&secondParam, (thrd_start_t)Func, nullptr);
431 thrd_create(&thirdParam, (thrd_start_t)Func, nullptr);
432 thrd_create(&fourthParam, (thrd_start_t)Func, nullptr);
433 thrd_join(firstParam, nullptr);
434 thrd_join(secondParam, nullptr);
435 thrd_join(thirdParam, nullptr);
436 thrd_join(fourthParam, nullptr);
437 remove("/data/storage/el2/base/files/Fzl.txt");
438 if (errno == PARAM_0) {
439 returnValue = SUCCESS;
440 }
441 napi_create_int32(env, returnValue, &result);
442 return result;
443 }
MtxDestroy(napi_env env, napi_callback_info info)444 static napi_value MtxDestroy(napi_env env, napi_callback_info info)
445 {
446 errno = ERRON_0;
447 mtx_t mtx;
448 mtx_init(&mtx, mtx_plain);
449 mtx_destroy(&mtx);
450 napi_value result;
451 if (errno != PARAM_0) {
452 napi_create_int32(env, PARAM_UNNORMAL, &result);
453 } else {
454 napi_create_int32(env, PARAM_0, &result);
455 }
456 return result;
457 }
458
MtxInit(napi_env env, napi_callback_info info)459 static napi_value MtxInit(napi_env env, napi_callback_info info)
460 {
461 errno = ERRON_0;
462 mtx_t mtx;
463 int ret = mtx_init(&mtx, mtx_plain);
464 mtx_destroy(&mtx);
465 napi_value result;
466 napi_create_int32(env, ret, &result);
467 return result;
468 }
469
MtxLock(napi_env env, napi_callback_info info)470 static napi_value MtxLock(napi_env env, napi_callback_info info)
471 {
472 errno = ERRON_0;
473 mtx_t mtx;
474 mtx_init(&mtx, mtx_plain);
475 int ret = mtx_lock(&mtx);
476 mtx_trylock(&mtx);
477 mtx_unlock(&mtx);
478 mtx_destroy(&mtx);
479 napi_value result;
480 napi_create_int32(env, ret, &result);
481 return result;
482 }
483
MtxTimedLock(napi_env env, napi_callback_info info)484 static napi_value MtxTimedLock(napi_env env, napi_callback_info info)
485 {
486 errno = ERRON_0;
487 mtx_t mtx;
488 struct timespec restrict;
489 memset(&restrict, PARAM_0, sizeof(restrict));
490 mtx_init(&mtx, mtx_plain);
491 int ret = mtx_timedlock(&mtx, &restrict);
492 mtx_trylock(&mtx);
493 mtx_unlock(&mtx);
494 mtx_destroy(&mtx);
495 napi_value result;
496 napi_create_int32(env, ret, &result);
497 return result;
498 }
499
MtxTryLock(napi_env env, napi_callback_info info)500 static napi_value MtxTryLock(napi_env env, napi_callback_info info)
501 {
502 errno = ERRON_0;
503 mtx_t mtx;
504 struct timespec restrict;
505 memset(&restrict, PARAM_0, sizeof(restrict));
506 mtx_init(&mtx, mtx_plain);
507 mtx_timedlock(&mtx, &restrict);
508 int ret = mtx_trylock(&mtx);
509 mtx_unlock(&mtx);
510 mtx_destroy(&mtx);
511 napi_value result;
512 napi_create_int32(env, ret, &result);
513 return result;
514 }
515
MtxUnLock(napi_env env, napi_callback_info info)516 static napi_value MtxUnLock(napi_env env, napi_callback_info info)
517 {
518 errno = ERRON_0;
519 mtx_t mtx;
520 struct timespec restrict;
521 memset(&restrict, PARAM_0, sizeof(restrict));
522 mtx_init(&mtx, mtx_plain);
523 mtx_timedlock(&mtx, &restrict);
524 mtx_trylock(&mtx);
525 int ret = mtx_unlock(&mtx);
526 mtx_destroy(&mtx);
527 napi_value result;
528 napi_create_int32(env, ret, &result);
529 return result;
530 }
531
532 EXTERN_C_START
Init(napi_env env, napi_value exports)533 static napi_value Init(napi_env env, napi_value exports)
534 {
535 napi_property_descriptor desc[] = {
536 {"thrd_create", nullptr, Thrd_create, nullptr, nullptr, nullptr, napi_default, nullptr},
537 {"thrd_current", nullptr, Thrd_current, nullptr, nullptr, nullptr, napi_default, nullptr},
538 {"thrd_detach", nullptr, Thrd_detach, nullptr, nullptr, nullptr, napi_default, nullptr},
539 {"thrd_equal", nullptr, Thrd_equal, nullptr, nullptr, nullptr, napi_default, nullptr},
540 {"thrd_exit", nullptr, Thrd_exit, nullptr, nullptr, nullptr, napi_default, nullptr},
541 {"thrd_join", nullptr, Thrd_join, nullptr, nullptr, nullptr, napi_default, nullptr},
542 {"thrd_sleep", nullptr, Thrd_sleep, nullptr, nullptr, nullptr, napi_default, nullptr},
543 {"thrd_yield", nullptr, Thrd_yield, nullptr, nullptr, nullptr, napi_default, nullptr},
544 {"tss_create", nullptr, Tss_create, nullptr, nullptr, nullptr, napi_default, nullptr},
545 {"tss_set", nullptr, Tss_set, nullptr, nullptr, nullptr, napi_default, nullptr},
546 {"tss_get", nullptr, Tss_get, nullptr, nullptr, nullptr, napi_default, nullptr},
547 {"tss_delete", nullptr, Tss_delete, nullptr, nullptr, nullptr, napi_default, nullptr},
548 {"cnd_init", nullptr, Cnd_init, nullptr, nullptr, nullptr, napi_default, nullptr},
549 {"cnd_signal", nullptr, Cnd_signal, nullptr, nullptr, nullptr, napi_default, nullptr},
550 {"cnd_destroy", nullptr, Cnd_destroy, nullptr, nullptr, nullptr, napi_default, nullptr},
551 {"cnd_wait", nullptr, Cnd_wait, nullptr, nullptr, nullptr, napi_default, nullptr},
552 {"cnd_timedwait", nullptr, Cnd_timedWait, nullptr, nullptr, nullptr, napi_default, nullptr},
553 {"cnd_broadcast", nullptr, Cnd_broadcast, nullptr, nullptr, nullptr, napi_default, nullptr},
554 {"callOnce", nullptr, CallOnce, nullptr, nullptr, nullptr, napi_default, nullptr},
555 {"mtxDestroy", nullptr, MtxDestroy, nullptr, nullptr, nullptr, napi_default, nullptr},
556 {"mtxInit", nullptr, MtxInit, nullptr, nullptr, nullptr, napi_default, nullptr},
557 {"mtxLock", nullptr, MtxLock, nullptr, nullptr, nullptr, napi_default, nullptr},
558 {"mtxTimedLock", nullptr, MtxTimedLock, nullptr, nullptr, nullptr, napi_default, nullptr},
559 {"mtxTryLock", nullptr, MtxTryLock, nullptr, nullptr, nullptr, napi_default, nullptr},
560 {"mtxUnLock", nullptr, MtxUnLock, nullptr, nullptr, nullptr, napi_default, nullptr},
561 };
562 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
563 return exports;
564 }
565 EXTERN_C_END
566
567 static napi_module demoModule = {
568 .nm_version = 1,
569 .nm_flags = 0,
570 .nm_filename = nullptr,
571 .nm_register_func = Init,
572 .nm_modname = "threads",
573 .nm_priv = ((void *)0),
574 .reserved = {0},
575 };
576
RegisterModule(void)577 extern "C" __attribute__((constructor)) void RegisterModule(void) { napi_module_register(&demoModule); }
578