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 }