Browse Source

fix & update: 调整信号处理机制

修复在parser模块下发送信号ctrl-C捕捉失灵的bug

link #2
SongZihuan 4 years ago
parent
commit
f92edbeec6

+ 1 - 0
main.c

@@ -29,5 +29,6 @@ int main(int argc, char *argv[]) {
         runCodeStdin(inter, HelloString);  // 从stdin中运行代码
     freeInter(inter, true);
 
+    system("pause");  // 按任意键继续...
     return 0;
 }

+ 26 - 3
src/virtualmath.c

@@ -49,14 +49,37 @@ void runCodeStdin(Inter *inter, char *hello_string) {
     }
 }
 
+void safe_sleep(double ms) {
+    time_t start = clock();
+    time_t now;
+    double d_time;
+    do {
+        now = clock();
+        d_time = (double)(now - start) / CLOCKS_PER_SEC;
+        if (d_time >= ms)
+            break;
+    } while (true);
+}
+
+bool checkSignalPm() {  // 兜底检查
+    if (signal_tag.status == signal_appear) {
+        signal_tag.status = signal_reset;
+        return true;
+    }
+    return false;
+}
+
 bool runParser(char *code_file, Inter *inter, bool is_one, Statement **st) {
     ParserMessage *pm = makeParserMessageFile(code_file, is_one);
     *st = makeStatement(0, (code_file == NULL) ? "stdin" : code_file);
     parserCommandList(pm, inter, true, *st);
-    if (pm->status == int_error) {
-        fprintf(stderr, "KeyInterrupt\n");
+    safe_sleep(0.005);  // 等待 0.005s 捕捉信号 (若信号捕捉不到可能要适当调高此处的等待时间)
+    if (checkSignalPm()) {
+        fprintf(stdout, "Signal: KeyInterrupt\n");
+    } else if (pm->status == int_error) {
+        fprintf(stdout, "Singal Error: %s\n", pm->status_message);
     } else if (pm->status != success)
-        fprintf(stderr, "Syntax Error: %s\n", pm->status_message);
+        fprintf(stdout, "Syntax Error: %s\n", pm->status_message);
     else {
         freeParserMessage(pm, true);
         return true;

+ 8 - 8
vmcore/include/handler.h

@@ -1,17 +1,17 @@
 #ifndef VIRTUALMATH_HANDLER_H
 #define VIRTUALMATH_HANDLER_H
 
-enum SignalType{
-    signal_reset,  // 没有信号
-    signal_check,  // 信号已经被处理, 等待异步处理
-    signal_appear,  // 信号未被处理
+struct SignalTag{
+    volatile int signum;  // 信号
+    volatile enum SignalType{
+        signal_reset=0,  // 没有信号
+        signal_appear,  // 信号未被处理
+    } status;
 };
 
-typedef enum SignalType SignalType;
-extern volatile SignalType is_KeyInterrupt;
-extern volatile SignalType pm_KeyInterrupt;
+typedef struct SignalTag SignalTag;
+extern volatile SignalTag signal_tag;
 
 void signalStopInter(int signum);;
-void signalStopPm(int signum);
 
 #endif //VIRTUALMATH_HANDLER_H

+ 1 - 1
vmcore/include/lexical.h

@@ -15,7 +15,7 @@ struct LexFile{
         int enter;  // 若计数为0则不忽略enter
     } filter_data;
     fline line;
-    wchar_t *errsyntax;
+    wchar_t *errsyntax;  // 匹配器出错信息,如:字符串缺少结尾双引号
 };
 
 struct LexMather{

+ 5 - 15
vmcore/parser/grammar.c

@@ -48,19 +48,14 @@ void parserCommandList(P_FUNC, bool global, Statement *st) {
     int token_type;
     int save_enter = pm->tm->file->filter_data.enter;
     char *command_message = global ? "ERROR from command list(get parserCommand)" : NULL;
-    void *bak = NULL;
     fline line = 0;
     bool should_break = false;
     bool have_command = false;
 
-    pm_KeyInterrupt = signal_reset;
-    bak = signal(SIGINT, signalStopPm);
     pm->tm->file->filter_data.enter = 0;
-    bool is_one = pm->short_cm;
-
     while (!should_break){
         token_type = readBackToken(pm);
-        if (token_type == -3 || token_type == -2)
+        if (token_type == -3 || token_type == -2)  // 出现错误(syntax error或者检测到退出信号)
             break;
         else if (token_type == MATHER_EOF){
             delToken(pm);
@@ -68,7 +63,7 @@ void parserCommandList(P_FUNC, bool global, Statement *st) {
         }
         else if (token_type == MATHER_ENTER || token_type == MATHER_SEMICOLON){
             delToken(pm);
-            if (is_one && have_command)
+            if (pm->short_cm && have_command)
                 break;
         }
         else{
@@ -81,7 +76,7 @@ void parserCommandList(P_FUNC, bool global, Statement *st) {
             stop = readBackToken(pm);
             if (stop == MATHER_ENTER) {
                 delToken(pm);
-                if (is_one)
+                if (pm->short_cm)
                     should_break = true;
             } else if (stop == MATHER_SEMICOLON)
                 delToken(pm);
@@ -102,13 +97,8 @@ void parserCommandList(P_FUNC, bool global, Statement *st) {
             freeToken(command_token, false);
         }
     }
-    if (is_one)
-        clearLexFile(pm->tm->file);
-    signal(SIGINT, bak);
-    if (pm_KeyInterrupt != signal_reset) {
-        pm_KeyInterrupt = signal_reset;
-        syntaxError(pm, int_error, line, 1, "KeyInterrupt");
-    }
+    if (pm->short_cm)
+        clearLexFile(pm->tm->file);  // 清理输入的内容
     pm->tm->file->filter_data.enter = save_enter;
 }
 

+ 1 - 1
vmcore/parser/lexical.c

@@ -31,7 +31,7 @@ wint_t readChar(LexFile *file){
 void backChar(LexFile *file){
     file->back.is_back = true;
     if (file->back.p == L'\n')
-        file->line --;
+        file->line --;  // 函数减一行
 }
 
 void clearLexFile(LexFile *file) {

+ 3 - 3
vmcore/parser/syntax.c

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

+ 4 - 11
vmcore/signalhandler/handler.c

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

+ 1 - 1
vmcore/src/inter.c

@@ -172,7 +172,7 @@ void freeInter(Inter *inter, bool show_gc) {
 
 #if DEBUG
     wint_t ch;
-    if (show_gc && (printf("\nEnter '1' to show gc: "), (fgetwc(stdin)) == L'1')) {
+    if (show_gc && (printf("\nEnter '1' to show gc info: "), (fgetwc(stdin)) == L'1')) {
         printGC(inter);
         while ((ch = fgetwc(stdin)) != '\n' || ch == WEOF)
             PASS;

File diff suppressed because it is too large
+ 0 - 1174
vmcore/src/parameter.c


+ 4 - 21
vmcore/src/run.c

@@ -176,8 +176,8 @@ ResultType runStatementOpt(bool run_gc, FUNC) {  // 不运行gc机制
 }
 
 static bool checkSignal(fline line, char *file, FUNC_NT) {
-    if (is_KeyInterrupt == signal_appear){
-        is_KeyInterrupt = signal_reset;
+    if (signal_tag.status == signal_appear){
+        signal_tag.status = signal_reset;
         setResultError(E_KeyInterrupt, KEY_INTERRUPT, line, file, true, CNEXT_NT);
         return true;
     }
@@ -209,7 +209,6 @@ static bool gotoStatement(Statement **next, FUNC) {
 ResultType iterStatement(FUNC) {
     Statement *base;
     ResultType type;
-    void *bak = NULL;
 
     setResultCore(result);
     if (st == NULL){
@@ -217,15 +216,9 @@ ResultType iterStatement(FUNC) {
         return result->type;
     }
 
-    is_KeyInterrupt = signal_reset;
-    bak = signal(SIGINT, signalStopInter);
     gc_addTmpLink(&belong->gc_status);
     do {
         base = st;
-        if (checkSignal(base->line, base->code_file, CNEXT_NT)) {
-            type = result->type;
-            break;
-        }
         while (base != NULL) {
             freeResult(result);
             type = runStatement(CFUNC(base, var_list, result, belong));
@@ -251,7 +244,6 @@ ResultType iterStatement(FUNC) {
     result->node = base;
 
     gc_freeTmpLink(&belong->gc_status);
-    signal(SIGINT, bak);
     return result->type;
 }
 
@@ -265,26 +257,18 @@ ResultType globalIterStatement(Result *result, Inter *inter, Statement *st, bool
     VarList *var_list = NULL;
     Statement *base;
     LinkValue *belong = inter->base_belong;
-    void *bak = NULL;
-    clock_t start, stop;
+    clock_t start = clock();
+    clock_t stop;
 
     if (st == NULL){
         setResult(result, inter);
         return result->type;
     }
 
-    is_KeyInterrupt = signal_reset;
-    bak = signal(SIGINT, signalStopInter);
     gc_addTmpLink(&belong->gc_status);
-
-    start = clock();
     do {
         base = st;
         var_list = inter->var_list;
-        if (checkSignal(base->line, base->code_file, CNEXT_NT)) {
-            type = result->type;
-            break;
-        }
         while (base != NULL) {
             freeResult(result);
             type = runStatement(CFUNC(base, var_list, result, belong));
@@ -313,7 +297,6 @@ ResultType globalIterStatement(Result *result, Inter *inter, Statement *st, bool
     if (p_clock)
         printf("run times = %Lf sec\n", (double long)(stop - start) / CLOCKS_PER_SEC);
     gc_freeTmpLink(&belong->gc_status);
-    signal(SIGINT, bak);
     return result->type;
 }
 

+ 1 - 0
vmcore/src/virtualmath.c

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

Some files were not shown because too many files changed in this diff