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 <csetjmp>
19 #include <js_native_api.h>
20 #include <node_api.h>
21 #include <pthread.h>
22 
23 #define PARAM_0 0
24 #define PARAM_1 1
25 #define PARAM_2 2
26 #define PARAM_UNNORMAL (-1)
27 #define ERRON_0 0
28 #define ONEVAL 1
29 #define MINUSONE (-1)
30 #define NO_ERR 0
31 
subroutine(jmp_buf jumper)32 void subroutine(jmp_buf jumper) { longjmp(jumper, PARAM_1); }
33 void subroutine(jmp_buf);
Longjmp(napi_env env, napi_callback_info info)34 static napi_value Longjmp(napi_env env, napi_callback_info info)
35 {
36     napi_value result = nullptr;
37     int value = PARAM_0;
38     jmp_buf jumper;
39     errno = ERRON_0;
40     value = setjmp(jumper);
41     if (value != PARAM_0) {
42         napi_create_int32(env, PARAM_0, &result);
43     } else {
44         napi_create_int32(env, PARAM_UNNORMAL, &result);
45         subroutine(jumper);
46     }
47     return result;
48 }
49 
_Longjmp(napi_env env, napi_callback_info info)50 static napi_value _Longjmp(napi_env env, napi_callback_info info)
51 {
52     int returnValue = PARAM_0;
53     errno = ERRON_0;
54     sigjmp_buf bufJmp;
55     _setjmp(bufJmp);
56     _longjmp(bufJmp, PARAM_0);
57     if (errno == PARAM_0) {
58         returnValue = ONEVAL;
59     }
60     napi_value result = nullptr;
61     napi_create_int32(env, returnValue, &result);
62     return result;
63 }
64 
_Setjmp(napi_env env, napi_callback_info info)65 static napi_value _Setjmp(napi_env env, napi_callback_info info)
66 {
67     napi_value result = nullptr;
68     int valueFirst = PARAM_0;
69     int valueSecond = PARAM_0;
70     jmp_buf jmp;
71     if (valueFirst == PARAM_0) {
72         int setValue = _setjmp(jmp);
73         napi_create_int32(env, setValue, &result);
74         return result;
75     } else {
76         int setValue = _setjmp(jmp);
77         if (setValue == PARAM_0) {
78             _longjmp(jmp, valueSecond);
79         }
80         napi_create_int32(env, setValue, &result);
81         return result;
82     }
83 }
84 
sigThread(void *args)85 void *sigThread(void *args)
86 {
87     sigjmp_buf jmpbuf;
88     sigsetjmp(jmpbuf, PARAM_1);
89     siglongjmp(jmpbuf, PARAM_1);
90     return nullptr;
91 }
92 
SigLongJmp(napi_env env, napi_callback_info info)93 static napi_value SigLongJmp(napi_env env, napi_callback_info info)
94 {
95     pthread_t tid = PARAM_0;
96     pthread_create(&tid, nullptr, sigThread, nullptr);
97     pthread_detach(tid);
98     napi_value result = nullptr;
99     napi_create_int32(env, NO_ERR, &result);
100     return result;
101 }
102 
SetJmp(napi_env env, napi_callback_info info)103 static napi_value SetJmp(napi_env env, napi_callback_info info)
104 {
105     napi_value result = nullptr;
106     jmp_buf jb;
107     int ret = setjmp(jb);
108     napi_create_int32(env, ret, &result);
109     return result;
110 }
111 
SigSetJmp(napi_env env, napi_callback_info info)112 static napi_value SigSetJmp(napi_env env, napi_callback_info info)
113 {
114     napi_value result = nullptr;
115     sigjmp_buf sjb;
116     int ret = sigsetjmp(sjb, PARAM_1);
117     napi_create_int32(env, ret, &result);
118     return result;
119 }
120 
121 EXTERN_C_START
Init(napi_env env, napi_value exports)122 static napi_value Init(napi_env env, napi_value exports)
123 {
124     napi_property_descriptor desc[] = {
125         {"longjmp", nullptr, Longjmp, nullptr, nullptr, nullptr, napi_default, nullptr},
126         {"_longjmp", nullptr, _Longjmp, nullptr, nullptr, nullptr, napi_default, nullptr},
127         {"_setjmp", nullptr, _Setjmp, nullptr, nullptr, nullptr, napi_default, nullptr},
128         {"setJmp", nullptr, SetJmp, nullptr, nullptr, nullptr, napi_default, nullptr},
129         {"sigLongJmp", nullptr, SigLongJmp, nullptr, nullptr, nullptr, napi_default, nullptr},
130         {"sigSetJmp", nullptr, SigSetJmp, nullptr, nullptr, nullptr, napi_default, nullptr},
131     };
132     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
133     return exports;
134 }
135 EXTERN_C_END
136 
137 static napi_module demoModule = {
138     .nm_version = 1,
139     .nm_flags = 0,
140     .nm_filename = nullptr,
141     .nm_register_func = Init,
142     .nm_modname = "setjmp",
143     .nm_priv = ((void *)0),
144     .reserved = {0},
145 };
146 
RegisterEntryModule(void)147 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
148