Fix T67459: Dope Editor, muting channels with shortcut doesn't work
[blender.git] / source / creator / creator_signals.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup creator
19  */
20
21 #ifndef WITH_PYTHON_MODULE
22
23 #  if defined(__linux__) && defined(__GNUC__)
24 #    define _GNU_SOURCE
25 #    include <fenv.h>
26 #  endif
27
28 #  if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
29 #    define OSX_SSE_FPE
30 #    include <xmmintrin.h>
31 #  endif
32
33 #  ifdef WIN32
34 #    if defined(_MSC_VER) && defined(_M_X64)
35 #      include <math.h> /* needed for _set_FMA3_enable */
36 #    endif
37 #    include <windows.h>
38 #    include <float.h>
39 #  endif
40
41 #  include <stdlib.h>
42 #  include <string.h>
43 #  include <errno.h>
44
45 #  include "BLI_sys_types.h"
46
47 #  ifdef WIN32
48 #    include "BLI_winstuff.h"
49 #  endif
50 #  include "BLI_utildefines.h"
51 #  include "BLI_string.h"
52 #  include "BLI_path_util.h"
53 #  include "BLI_fileops.h"
54 #  include "BLI_system.h"
55 #  include BLI_SYSTEM_PID_H
56
57 #  include "BKE_appdir.h" /* BKE_tempdir_base */
58 #  include "BKE_blender_version.h"
59 #  include "BKE_global.h"
60 #  include "BKE_main.h"
61 #  include "BKE_report.h"
62
63 #  include <signal.h>
64
65 #  include "creator_intern.h" /* own include */
66
67 // #define USE_WRITE_CRASH_BLEND
68 #  ifdef USE_WRITE_CRASH_BLEND
69 #    include "BKE_undo_system.h"
70 #    include "BLO_undofile.h"
71 #  endif
72
73 /* set breakpoints here when running in debug mode, useful to catch floating point errors */
74 #  if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
75 static void sig_handle_fpe(int UNUSED(sig))
76 {
77   fprintf(stderr, "debug: SIGFPE trapped\n");
78 }
79 #  endif
80
81 /* handling ctrl-c event in console */
82 #  if !defined(WITH_HEADLESS)
83 static void sig_handle_blender_esc(int sig)
84 {
85   static int count = 0;
86
87   G.is_break = true; /* forces render loop to read queue, not sure if its needed */
88
89   if (sig == 2) {
90     if (count) {
91       printf("\nBlender killed\n");
92       exit(2);
93     }
94     printf("\nSent an internal break event. Press ^C again to kill Blender\n");
95     count++;
96   }
97 }
98 #  endif
99
100 static void sig_handle_crash_backtrace(FILE *fp)
101 {
102   fputs("\n# backtrace\n", fp);
103   BLI_system_backtrace(fp);
104 }
105
106 static void sig_handle_crash(int signum)
107 {
108   wmWindowManager *wm = G_MAIN->wm.first;
109
110 #  ifdef USE_WRITE_CRASH_BLEND
111   if (wm->undo_stack) {
112     struct MemFile *memfile = BKE_undosys_stack_memfile_get_active(wm->undo_stack);
113     if (memfile) {
114       char fname[FILE_MAX];
115
116       if (!G_MAIN->name[0]) {
117         BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
118       }
119       else {
120         BLI_strncpy(fname, G_MAIN->name, sizeof(fname));
121         BLI_path_extension_replace(fname, sizeof(fname), ".crash.blend");
122       }
123
124       printf("Writing: %s\n", fname);
125       fflush(stdout);
126
127       BLO_memfile_write_file(memfile, fname);
128     }
129   }
130 #  endif
131
132   FILE *fp;
133   char header[512];
134
135   char fname[FILE_MAX];
136
137   if (!G_MAIN->name[0]) {
138     BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
139   }
140   else {
141     BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G_MAIN->name));
142     BLI_path_extension_replace(fname, sizeof(fname), ".crash.txt");
143   }
144
145   printf("Writing: %s\n", fname);
146   fflush(stdout);
147
148 #  ifndef BUILD_DATE
149   BLI_snprintf(
150       header, sizeof(header), "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG);
151 #  else
152   BLI_snprintf(header,
153                sizeof(header),
154                "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n",
155                BLEND_VERSION_ARG,
156                build_commit_date,
157                build_commit_time,
158                build_hash);
159 #  endif
160
161   /* open the crash log */
162   errno = 0;
163   fp = BLI_fopen(fname, "wb");
164   if (fp == NULL) {
165     fprintf(stderr,
166             "Unable to save '%s': %s\n",
167             fname,
168             errno ? strerror(errno) : "Unknown error opening file");
169   }
170   else {
171     if (wm) {
172       BKE_report_write_file_fp(fp, &wm->reports, header);
173     }
174
175     sig_handle_crash_backtrace(fp);
176
177     fclose(fp);
178   }
179
180   /* Delete content of temp dir! */
181   BKE_tempdir_session_purge();
182
183   /* really crash */
184   signal(signum, SIG_DFL);
185 #  ifndef WIN32
186   kill(getpid(), signum);
187 #  else
188   TerminateProcess(GetCurrentProcess(), signum);
189 #  endif
190 }
191
192 #  ifdef WIN32
193 LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
194 {
195   switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
196     case EXCEPTION_ACCESS_VIOLATION:
197       fputs("Error   : EXCEPTION_ACCESS_VIOLATION\n", stderr);
198       break;
199     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
200       fputs("Error   : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
201       break;
202     case EXCEPTION_BREAKPOINT:
203       fputs("Error   : EXCEPTION_BREAKPOINT\n", stderr);
204       break;
205     case EXCEPTION_DATATYPE_MISALIGNMENT:
206       fputs("Error   : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
207       break;
208     case EXCEPTION_FLT_DENORMAL_OPERAND:
209       fputs("Error   : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
210       break;
211     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
212       fputs("Error   : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
213       break;
214     case EXCEPTION_FLT_INEXACT_RESULT:
215       fputs("Error   : EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
216       break;
217     case EXCEPTION_FLT_INVALID_OPERATION:
218       fputs("Error   : EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
219       break;
220     case EXCEPTION_FLT_OVERFLOW:
221       fputs("Error   : EXCEPTION_FLT_OVERFLOW\n", stderr);
222       break;
223     case EXCEPTION_FLT_STACK_CHECK:
224       fputs("Error   : EXCEPTION_FLT_STACK_CHECK\n", stderr);
225       break;
226     case EXCEPTION_FLT_UNDERFLOW:
227       fputs("Error   : EXCEPTION_FLT_UNDERFLOW\n", stderr);
228       break;
229     case EXCEPTION_ILLEGAL_INSTRUCTION:
230       fputs("Error   : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
231       break;
232     case EXCEPTION_IN_PAGE_ERROR:
233       fputs("Error   : EXCEPTION_IN_PAGE_ERROR\n", stderr);
234       break;
235     case EXCEPTION_INT_DIVIDE_BY_ZERO:
236       fputs("Error   : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
237       break;
238     case EXCEPTION_INT_OVERFLOW:
239       fputs("Error   : EXCEPTION_INT_OVERFLOW\n", stderr);
240       break;
241     case EXCEPTION_INVALID_DISPOSITION:
242       fputs("Error   : EXCEPTION_INVALID_DISPOSITION\n", stderr);
243       break;
244     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
245       fputs("Error   : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
246       break;
247     case EXCEPTION_PRIV_INSTRUCTION:
248       fputs("Error   : EXCEPTION_PRIV_INSTRUCTION\n", stderr);
249       break;
250     case EXCEPTION_SINGLE_STEP:
251       fputs("Error   : EXCEPTION_SINGLE_STEP\n", stderr);
252       break;
253     case EXCEPTION_STACK_OVERFLOW:
254       fputs("Error   : EXCEPTION_STACK_OVERFLOW\n", stderr);
255       break;
256     default:
257       fputs("Error   : Unrecognized Exception\n", stderr);
258       break;
259   }
260
261   fflush(stderr);
262
263   /* If this is a stack overflow then we can't walk the stack, so just show
264    * where the error happened */
265   if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
266     HMODULE mod;
267     CHAR modulename[MAX_PATH];
268     LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress;
269
270     fprintf(stderr, "Address : 0x%p\n", address);
271     if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) {
272       if (GetModuleFileName(mod, modulename, MAX_PATH)) {
273         fprintf(stderr, "Module  : %s\n", modulename);
274       }
275     }
276
277     fflush(stderr);
278
279 #    ifdef NDEBUG
280     TerminateProcess(GetCurrentProcess(), SIGSEGV);
281 #    else
282     sig_handle_crash(SIGSEGV);
283 #    endif
284   }
285
286   return EXCEPTION_EXECUTE_HANDLER;
287 }
288 #  endif
289
290 static void sig_handle_abort(int UNUSED(signum))
291 {
292   /* Delete content of temp dir! */
293   BKE_tempdir_session_purge();
294 }
295
296 void main_signal_setup(void)
297 {
298   if (app_state.signal.use_crash_handler) {
299 #  ifdef WIN32
300     SetUnhandledExceptionFilter(windows_exception_handler);
301 #  else
302     /* after parsing args */
303     signal(SIGSEGV, sig_handle_crash);
304 #  endif
305   }
306
307   if (app_state.signal.use_abort_handler) {
308     signal(SIGABRT, sig_handle_abort);
309   }
310 }
311
312 void main_signal_setup_background(void)
313 {
314   /* for all platforms, even windos has it! */
315   BLI_assert(G.background);
316
317 #  if !defined(WITH_HEADLESS)
318   signal(SIGINT, sig_handle_blender_esc); /* ctrl c out bg render */
319 #  endif
320 }
321
322 void main_signal_setup_fpe(void)
323 {
324 #  if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
325   /* zealous but makes float issues a heck of a lot easier to find!
326    * set breakpoints on sig_handle_fpe */
327   signal(SIGFPE, sig_handle_fpe);
328
329 #    if defined(__linux__) && defined(__GNUC__)
330   feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
331 #    endif /* defined(__linux__) && defined(__GNUC__) */
332 #    if defined(OSX_SSE_FPE)
333   /* OSX uses SSE for floating point by default, so here
334    * use SSE instructions to throw floating point exceptions */
335   _MM_SET_EXCEPTION_MASK(_MM_MASK_MASK &
336                          ~(_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
337 #    endif /* OSX_SSE_FPE */
338 #    if defined(_WIN32) && defined(_MSC_VER)
339   /* enables all fp exceptions */
340   _controlfp_s(NULL, 0, _MCW_EM);
341   /* hide the ones we don't care about */
342   _controlfp_s(NULL, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM);
343 #    endif /* _WIN32 && _MSC_VER */
344 #  endif
345 }
346
347 #endif /* WITH_PYTHON_MODULE */