فهرست منبع

feat: 新增信号绑定函数

可以绑定指定信号
取消绑定指定信号
按默认模式处理指定信号
忽略信号

link #2
SongZihuan 4 سال پیش
والد
کامیت
12ce94aebe

+ 2 - 2
src/virtualmath.c

@@ -61,8 +61,8 @@ void safe_sleep(double ms) {
     } while (true);
 }
 
-bool checkSignalPm() {  // 兜底检查
-    if (signal_tag.status == signal_appear) {
+bool checkSignalPm() {  // 检查信号
+    if (signal_tag.status == signal_appear && PARSER_STOP_SIGNAL(signal_tag.signum)) {
         signal_tag.status = signal_reset;
         return true;
     }

+ 3 - 0
vmcore/include/__macro.h

@@ -6,6 +6,8 @@
 // PASS语句的定义
 #define PASS
 
+#define PARSER_STOP_SIGNAL(sig) ((sig) == SIGINT)
+
 #define RUN_TYPE(type) (type == R_not || type == R_opt)
 #define CHECK_RESULT(result) (result->type == R_not || result->type == R_opt)
 
@@ -49,6 +51,7 @@
 #define MD5_STR_LEN (MD5_SIZE * 2)
 #define MD5_STRING (MD5_STR_LEN + 1)
 
+typedef int vsignal;
 typedef long long vint;
 typedef long double vdou;
 typedef unsigned long long vhashn;

+ 2 - 2
vmcore/include/handler.h

@@ -2,7 +2,7 @@
 #define VIRTUALMATH_HANDLER_H
 
 struct SignalTag{
-    volatile int signum;  // 信号
+    volatile vsignal signum;  // 信号
     volatile enum SignalType{
         signal_reset=0,  // 没有信号
         signal_appear,  // 信号未被处理
@@ -12,6 +12,6 @@ struct SignalTag{
 typedef struct SignalTag SignalTag;
 extern volatile SignalTag signal_tag;
 
-void signalStopInter(int signum);;
+void vmSignalHandler(int signum);;
 
 #endif //VIRTUALMATH_HANDLER_H

+ 1 - 0
vmcore/include/inter.h

@@ -105,6 +105,7 @@ struct Inter{
     struct Var *base_var;
     struct LinkValue *base_belong;
     struct Package *package;
+    struct SignalList *sig_list;
     struct ClibInfo *clib_info;
     struct VarList *var_list;
     struct InterData{

+ 13 - 0
vmcore/include/value.h

@@ -36,6 +36,7 @@ typedef struct Result Result;
 typedef struct Error Error;
 typedef struct Inherit Inherit;
 typedef struct Package Package;
+typedef struct SignalList SignalList;
 
 typedef enum ResultType (*OfficialFunction)(O_FUNC);
 typedef void (*Registered)(R_FUNC);
@@ -233,6 +234,12 @@ struct Package {
     struct Package *next;
 };
 
+struct SignalList {
+    vsignal sig_num;  // 信号
+    LinkValue *value;  // 处理函数
+    struct SignalList *next;
+};
+
 enum BaseErrorType{
     E_BaseException = 0,
     E_Exception,
@@ -292,6 +299,12 @@ Package *makePackage(Value *value, char *md5, char *name, Package *base);
 void freePackage(Package *base);
 Value *checkPackage(Package *base, char *md5, char *name);
 
+SignalList *makeSignalList(vsignal sig_num, LinkValue *value);
+LinkValue *exchangeSignalFunc(SignalList *sig_list, LinkValue *new);
+SignalList *freeSignalList(SignalList *sig_list);
+SignalList *checkSignalList(vsignal sig_num, SignalList *sig_list);
+LinkValue *delSignalList(vsignal sig_num, SignalList **sig_list);
+
 Error *makeError(wchar_t *type, wchar_t *message, fline line, char *file);
 void freeError(Result *base);
 Error *connectError(Error *new, Error *base);

+ 89 - 0
vmcore/ofunc/src/vmobj/sys.c

@@ -215,6 +215,91 @@ static ResultType vm_raise(O_FUNC){
     return result->type;
 }
 
+static ResultType vm_signal(O_FUNC){
+    ArgumentParser ap[] = {{.type=name_value, .name=L"signal", .must=1, .long_arg=false},
+                           {.type=name_value, .name=L"func", .must=1, .long_arg=false},
+                           {.must=-1}};
+    SignalList *sl = inter->sig_list;
+    SignalList *tmp;
+    vsignal sig;
+    setResultCore(result);
+    {
+        parserArgumentUnion(ap, arg, CNEXT_NT);
+        if (!CHECK_RESULT(result))
+            return result->type;
+        freeResult(result);
+    }
+
+    if (ap[0].value->value->type != V_int) {
+        setResultError(E_TypeException, ONLY_ACC(signal, int), LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    sig = ap[0].value->value->data.int_.num;
+    if ((tmp = checkSignalList(sig, inter->sig_list)) == NULL) {
+        inter->sig_list = makeSignalList(ap[0].value->value->data.int_.num, ap[1].value);  // 添加新的节点
+        inter->sig_list->next = sl;  // 重新拼接
+        setResult(result, inter);  // 返回值为null
+    } else {
+        LinkValue *old = exchangeSignalFunc(tmp, ap[1].value);  // 此处会为 old 添加 tmp_link
+        setResultOperation(result, old);  // 更换函数, 旧函数作为返回值 (此处也会为 old 添加 tmp_link)
+        gc_freeTmpLink(&old->gc_status);  // 释放掉 exchangeSignalFunc 为 old 添加到 tmp_link
+    }
+    signal(sig, vmSignalHandler);  // 绑定函数
+    return result->type;
+}
+
+static ResultType vm_signal_core(O_FUNC, int status){
+    ArgumentParser ap[] = {{.type=name_value, .name=L"signal", .must=1, .long_arg=false},
+                           {.must=-1}};
+    vsignal sig;
+    LinkValue *old;
+    setResultCore(result);
+    {
+        parserArgumentUnion(ap, arg, CNEXT_NT);
+        if (!CHECK_RESULT(result))
+            return result->type;
+        freeResult(result);
+    }
+
+    if (ap[0].value->value->type != V_int) {
+        setResultError(E_TypeException, ONLY_ACC(signal, int), LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    sig = ap[0].value->value->data.int_.num;
+    if ((old = delSignalList(sig, &(inter->sig_list))) != NULL) {
+        setResultOperation(result, old);
+        gc_freeTmpLink(&old->gc_status);  // 释放 delSignalList 中设置 old 的 tmp_link
+    } else
+        setResult(result, inter);  // 默认返回none
+    switch (status) {
+        default:
+        case 1:
+            signal(sig, SIG_IGN);  // vm 不捕捉该信号
+            break;
+        case 2:
+            signal(sig, vmSignalHandler);  // 用 vm 的默认方式处理信号
+            break;
+        case 3:
+            signal(sig, SIG_ERR);  // 按错误处理
+            break;
+    }
+    return result->type;
+}
+
+static ResultType vm_signal_ignore(O_FUNC) {
+    return vm_signal_core(CO_FUNC(arg, var_list, result, belong), 1);
+}
+
+static ResultType vm_signal_default(O_FUNC) {
+    return vm_signal_core(CO_FUNC(arg, var_list, result, belong), 2);
+}
+
+static ResultType vm_signal_err(O_FUNC) {
+    return vm_signal_core(CO_FUNC(arg, var_list, result, belong), 3);
+}
+
 void registeredSysFunction(R_FUNC){
     NameFunc tmp[] = {{L"super",                  vm_super,          fp_no_, .var=nfv_notpush},
                       {L"static_method",          vm_no_,            fp_no_, .var=nfv_notpush},
@@ -243,6 +328,10 @@ void registeredSysFunction(R_FUNC){
 
                       {L"quit",                   vm_quit,           fp_no_, .var=nfv_notpush},
                       {L"raise",                  vm_raise,          fp_no_, .var=nfv_notpush},
+                      {L"signal",                 vm_signal,         fp_no_, .var=nfv_notpush},
+                      {L"signal_ignore",          vm_signal_ignore,  fp_no_, .var=nfv_notpush},
+                      {L"signal_default",         vm_signal_default, fp_no_, .var=nfv_notpush},
+                      {L"signal_err",             vm_signal_err,     fp_no_, .var=nfv_notpush},
                       {NULL, NULL}};
     iterBaseNameFunc(tmp, belong, CFUNC_CORE(var_list));
 }

+ 1 - 1
vmcore/parser/syntax.c

@@ -320,7 +320,7 @@ int getMatherStatus(LexFile *file, LexMathers *mathers) {
     setupMathers(mathers);
     while (status == -1){
         p = readChar(file);
-        if (signal_tag.status == signal_appear) {
+        if (signal_tag.status == signal_appear && PARSER_STOP_SIGNAL(signal_tag.signum)) {
             signal_tag.status = signal_reset;
             file->errsyntax = L"Signal KeyInterrupt";
             return -3;

+ 2 - 2
vmcore/signalhandler/handler.c

@@ -1,8 +1,8 @@
 #include "__virtualmath.h"
 volatile SignalTag signal_tag = {.signum=0, .status=signal_reset};
 
-void signalStopInter(int signum) {
+void vmSignalHandler(int signum) {
     signal_tag.status = signal_appear;
     signal_tag.signum = signum;
-    signal(signum, signalStopInter);  // signalStopInter 触发后,会和信号解除绑定,因此必须再次绑定
+    signal(signum, vmSignalHandler);  // vmSignalHandler 触发后,会和信号解除绑定,因此必须再次绑定
 }

+ 14 - 5
vmcore/src/inter.c

@@ -6,6 +6,7 @@ Inter *makeInter(char *out, char *error_, char *in, char *env, LinkValue *belong
     tmp->link_base = NULL;
     tmp->hash_base = NULL;
     tmp->base_var = NULL;
+    tmp->sig_list = NULL;
     tmp->package = NULL;
     tmp->data.env = NULL;
     changeInterEnv(env, false, tmp);
@@ -170,6 +171,10 @@ void freeInter(Inter *inter, bool show_gc) {
     freePackage(inter->package);
     freeVarList(inter->var_list);
 
+    for (SignalList *sl = inter->sig_list; sl != NULL; PASS)
+        sl = freeSignalList(sl);
+    inter->sig_list = NULL;
+
 #if DEBUG
     wint_t ch;
     if (show_gc && (printf("\nEnter '1' to show gc info: "), (fgetwc(stdin)) == L'1')) {
@@ -196,11 +201,10 @@ void freeInter(Inter *inter, bool show_gc) {
         freeHashTable(&inter->hash_base);
     freeClibInfoFromInter(inter);
     memFree(inter);
-    return_:
-    return;
+    return_: return;
 }
 
-void mergeInter(Inter *new, Inter *base){
+void mergeInter(Inter *new, Inter *base){  // 合并inter (sig_list内容不合并)
     Value **base_value = NULL;
     LinkValue **base_linkValue = NULL;
     HashTable **base_hash = NULL;
@@ -227,12 +231,17 @@ void mergeInter(Inter *new, Inter *base){
     *base_hash = new->hash_base;
     *base_var = new->base_var;
     *info = new->clib_info;
-    if (base->package == NULL)
+    if (base->package == NULL)  // 合并 package
         base->package = new->package;
+
+    for (SignalList *sl = new->sig_list; sl != NULL; PASS)  // 释放sl的内容
+        sl = freeSignalList(sl);
+    new->sig_list = NULL;
+
     memFree(new);
 }
 
-Inter *deriveInter(char *env, LinkValue *belong, Inter *inter) {
+Inter *deriveInter(char *env, LinkValue *belong, Inter *inter) {  // 派生一个inter
     Inter *import_inter = makeInter(NULL, NULL, NULL, env, belong);
     import_inter->data.inter_stdout = inter->data.inter_stdout;
     import_inter->data.inter_stderr = inter->data.inter_stderr;

+ 46 - 14
vmcore/src/run.c

@@ -175,13 +175,43 @@ ResultType runStatementOpt(bool run_gc, FUNC) {  // 不运行gc机制
     return type;
 }
 
-static bool checkSignal(fline line, char *file, FUNC_NT) {
-    if (signal_tag.status == signal_appear){
-        signal_tag.status = signal_reset;
-        setResultError(E_KeyInterrupt, KEY_INTERRUPT, line, file, true, CNEXT_NT);
-        return true;
+void signalDefault(vsignal sig_num, fline line, char *file, FUNC_NT) {
+    switch (sig_num) {  // 信号的默认处理 (使用switch-case分支)
+        case SIGINT:
+            setResultError(E_KeyInterrupt, KEY_INTERRUPT, line, file, true, CNEXT_NT);
+            break;
+        default:
+            break;
     }
-    return false;
+}
+
+static bool checkSignal(fline line, char *file, FUNC_NT) {  // 检查信号
+    if (signal_tag.status == signal_appear){  // 出现信号
+        SignalList *sig_list;
+        vsignal sig_num = signal_tag.signum;
+        Result bak = *result;  // 备份result
+        setResultCore(result);  // 重置result
+        signal_tag.status = signal_reset;  // 复位
+        if ((sig_list = checkSignalList(sig_num, inter->sig_list)) == NULL)
+            signalDefault(sig_num, line, file, CNEXT_NT);
+        else {
+            Argument *arg;
+            makeIntValue(sig_num, LINEFILE, CNEXT_NT);
+            arg = makeValueArgument(result->value);
+            freeResult(result);
+            callBackCore(sig_list->value, arg, line, file, 0, CNEXT_NT);  // 运行指定函数
+            freeArgument(arg, true);
+        }
+        if (CHECK_RESULT(result)) {
+            freeResult(result);
+            *result = bak;  // 恢复result
+            return false;
+        } else {
+            freeResult(&bak);  // 释放原有result
+            return true;
+        }
+    }
+    return false;  // 返回false表示未遇到error
 }
 
 static bool gotoStatement(Statement **next, FUNC) {
@@ -206,6 +236,12 @@ static bool gotoStatement(Statement **next, FUNC) {
  * @param var_list
  * @return
  */
+
+#define RUN_CHECK_SIGNAL if (checkSignal(base->line, base->code_file, CNEXT_NT)) { \
+type = result->type; \
+break; \
+}
+
 ResultType iterStatement(FUNC) {
     Statement *base;
     ResultType type;
@@ -222,10 +258,7 @@ ResultType iterStatement(FUNC) {
         while (base != NULL) {
             freeResult(result);
             type = runStatement(CFUNC(base, var_list, result, belong));
-            if (checkSignal(base->line, base->code_file, CNEXT_NT)) {
-                type = result->type;
-                break;
-            }
+            RUN_CHECK_SIGNAL;
             if (type == R_goto && result->times == 0){
                 if (!gotoStatement(&base, CNEXT)) {
                     type = result->type;
@@ -272,10 +305,7 @@ ResultType globalIterStatement(Result *result, Inter *inter, Statement *st, bool
         while (base != NULL) {
             freeResult(result);
             type = runStatement(CFUNC(base, var_list, result, belong));
-            if (checkSignal(base->line, base->code_file, CNEXT_NT)) {
-                type = result->type;
-                break;
-            }
+            RUN_CHECK_SIGNAL;
             if (type == R_goto){
                 if (!gotoStatement(&base, CNEXT)) {
                     type = result->type;
@@ -300,6 +330,8 @@ ResultType globalIterStatement(Result *result, Inter *inter, Statement *st, bool
     return result->type;
 }
 
+#undef RUN_CHECK_SIGNAL
+
 // 若需要中断执行, 则返回true
 bool operationSafeInterStatement(FUNC){
     ResultType type;

+ 45 - 0
vmcore/src/value.c

@@ -614,6 +614,51 @@ Value *checkPackage(Package *base, char *md5, char *name) {
     return NULL;
 }
 
+SignalList *makeSignalList(vsignal sig_num, LinkValue *value) {
+    SignalList *tmp;
+    gc_addStatementLink(&value->gc_status);
+    tmp = memCalloc(1, sizeof(SignalList));
+    tmp->sig_num = sig_num;
+    tmp->value = value;
+    tmp->next = NULL;
+    return tmp;
+}
+
+LinkValue *exchangeSignalFunc(SignalList *sig_list, LinkValue *new) {
+    LinkValue *old = sig_list->value;
+    gc_addTmpLink(&old->gc_status);
+    gc_freeStatementLink(&old->gc_status);
+    gc_addStatementLink(&new->gc_status);
+    sig_list->value = new;
+    return old;
+}
+
+SignalList *freeSignalList(SignalList *sig_list) {
+    SignalList *next = sig_list->next;
+    gc_freeStatementLink(&sig_list->value->gc_status);
+    memFree(sig_list);
+    return next;
+}
+
+SignalList *checkSignalList(vsignal sig_num, SignalList *sig_list) {  // 找到sig_num指定的sig_list
+    for (PASS; sig_list != NULL && sig_list->sig_num != sig_num; sig_list = sig_list->next)
+        PASS;
+    return sig_list;
+}
+
+LinkValue *delSignalList(vsignal sig_num, SignalList **sig_list) {  // 找到sig_num指定的sig_list, 并且删除
+    LinkValue *re = NULL;
+    for (SignalList **sl = sig_list; *sl != NULL; sl = &((*sl)->next)) {
+        if ((*sl)->sig_num == sig_num) {
+            re = (*sl)->value;
+            gc_addTmpLink(&re->gc_status);
+            *sl = freeSignalList(*sl);
+            break;
+        }
+    }
+    return re;
+}
+
 bool needDel(Value *object_value, Inter *inter) {
     LinkValue *_del_ = checkStrVar(inter->data.mag_func[M_DEL], false, CFUNC_CORE(object_value->object.var));
     enum FunctionPtType type;

+ 1 - 1
vmcore/src/virtualmath.c

@@ -2,6 +2,6 @@
 
 bool initVirtualMath(char const *local) {
     setlocale(LC_ALL, local);
-    signal(SIGINT, signalStopInter);  // 注册信号处理程序
+    signal(SIGINT, vmSignalHandler);  // 注册信号处理程序
     return true;
 }