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