1 module tagion.GlobalSignals; 2 3 import core.stdc.signal; 4 import core.stdc.stdio; 5 import core.stdc.stdlib : exit, system; 6 import core.stdc.string : strlen; 7 import core.sync.event; 8 import tagion.basic.Version; 9 import tagion.logger.Logger; 10 11 //import core.internal.execinfo; 12 // The declaration of the backtrace function in the execinfo.d is not declared @nogc 13 // so they are declared here with @nogc because signal needs a @nogc function 14 static if (ver.Posix && not_unittest) { 15 extern (C) { 16 nothrow @nogc { 17 int backtrace(void** buffer, int size); 18 char** backtrace_symbols(const(void*)* buffer, int size); 19 void backtrace_symbols_fd(const(void*)* buffer, int size, int fd); 20 } 21 } 22 } 23 24 __gshared Event stopsignal; 25 static shared bool abort = false; 26 27 private shared bool fault; 28 // static if (ver.Posix && not_unittest) { 29 // private static extern (C) void shutdown(int sig) @nogc nothrow { 30 // if (!fault) { 31 // if (sig is SIGINT) { 32 // printf("SIGINT=%d SIGTERM=%d\n", SIGINT, SIGTERM); 33 // printf("Shutdown sig %d about=%d\n", sig, abort); 34 // if (abort) { 35 // exit(0); 36 // } 37 // printf("Program will now abort\n"); 38 // abort = true; 39 // } 40 // else { 41 // printf("Ignored sig %d about=%d\n", sig, abort); 42 // } 43 // } 44 // } 45 // } 46 47 //shared char[] call_stack_file; 48 enum CALL_STACK_FILE_SIZE = 0x100; 49 version (ONETOOL) { 50 import tagion.tools.OneMain : main_name; 51 52 } 53 else { 54 private shared static string main_name; 55 shared static this() { 56 import std.file : thisExePath; 57 58 main_name = thisExePath.idup; 59 60 } 61 } 62 alias CallStackFile = char[CALL_STACK_FILE_SIZE + 1]; 63 private const(CallStackFile) call_stack_file() nothrow @nogc { 64 CallStackFile filename; 65 filename[] = '\0'; 66 size_t pos; //=main_name.length; 67 filename[0 .. main_name.length] = main_name; 68 pos += main_name.length; 69 filename[pos] = '.'; 70 pos++; 71 filename[pos .. pos + backtrace_ext.length] = backtrace_ext; 72 return filename; 73 } 74 75 static if (ver.Posix && not_unittest) { 76 import core.sys.posix.signal; 77 import core.sys.posix.unistd : STDERR_FILENO; 78 79 enum BACKTRACE_SIZE = 0x80; /// Just big enough to hold the call stack 80 static extern (C) void segment_fault(int sig, siginfo_t* ctx, void* ptr) @nogc nothrow { 81 if (fault) { 82 return; 83 } 84 abort = true; 85 fault = true; 86 log.silent = true; 87 88 fprintf(stderr, "Fatal error\n"); 89 void*[BACKTRACE_SIZE] callstack; 90 int size; 91 92 fprintf(stderr, "Got signal %d, faulty address is %p, from pid %d\n", 93 sig, ctx.si_addr, ctx.si_pid); 94 95 size = backtrace(callstack.ptr, BACKTRACE_SIZE); 96 backtrace_symbols_fd(callstack.ptr, size, STDERR_FILENO); 97 98 scope char** messages; 99 messages = backtrace_symbols(callstack.ptr, size); 100 const filename = call_stack_file; 101 printf("filename %s\n", &filename[0]); 102 { 103 auto fp = fopen(&filename[0], "w"); 104 scope (exit) { 105 fclose(fp); 106 } 107 foreach (i, msg; messages[0 .. size]) { 108 fprintf(fp, "%s\n", msg); 109 } 110 } 111 fprintf(stderr, "\nSEGMENT FAULT\n"); 112 fprintf(stderr, "Backtrack file has been written to %.*s\n", 113 cast(int) call_stack_file.length, call_stack_file.ptr); 114 fprintf(stderr, "Use the callstack to list the backtrace\n"); 115 exit(-1); 116 } 117 } 118 119 import core.stdc.signal; 120 121 enum SIGPIPE = 13; // SIGPIPE is not defined in the module core.stdc.signal 122 static extern (C) void ignore(int sig) @nogc nothrow { 123 printf("Ignore sig %d\n", sig); 124 } 125 126 enum backtrace_ext = "callstack"; 127 static if (not_unittest) { 128 shared static this() { 129 import std.path; 130 131 stopsignal.initialize(true, false); 132 133 //call_stack_file = setExtension(thisExePath, backtrace_ext) ~ '\0'; 134 135 signal(SIGPIPE, &ignore); 136 version (Posix) { 137 import core.sys.posix.signal; 138 139 // import core.runtime; 140 141 sigaction_t sa = void; 142 (cast(byte*)&sa)[0 .. sa.sizeof] = 0; 143 /// sigfillset( &action.sa_mask ); // block other signals 144 145 sa.sa_sigaction = &segment_fault; 146 sigemptyset(&sa.sa_mask); 147 sa.sa_flags = SA_RESTART; 148 sigaction(SIGSEGV, &sa, null); 149 } 150 151 // signal(SIGINT, &shutdown); 152 // signal(SIGTERM, &shutdown); 153 } 154 }