diff options
Diffstat (limited to 'source/creator/creator_signals.c')
-rw-r--r-- | source/creator/creator_signals.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c new file mode 100644 index 00000000000..b25d7c56f6e --- /dev/null +++ b/source/creator/creator_signals.c @@ -0,0 +1,328 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file creator/creator_signals.c + * \ingroup creator + */ + +#ifndef WITH_PYTHON_MODULE + +#if defined(__linux__) && defined(__GNUC__) +# define _GNU_SOURCE +# include <fenv.h> +#endif + +#if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))) +# define OSX_SSE_FPE +# include <xmmintrin.h> +#endif + +#ifdef WIN32 +# if defined(_MSC_VER) && defined(_M_X64) +# include <math.h> /* needed for _set_FMA3_enable */ +# endif +# include <windows.h> +# include <float.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "BLI_sys_types.h" + +#ifdef WIN32 +# include "BLI_winstuff.h" +#endif +#include "BLI_utildefines.h" +#include "BLI_string.h" +#include "BLI_path_util.h" +#include "BLI_fileops.h" +#include "BLI_system.h" +#include BLI_SYSTEM_PID_H + +#include "BKE_appdir.h" /* BKE_tempdir_base */ +#include "BKE_blender.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_report.h" + +/* for passing information between creator and gameengine */ +#ifdef WITH_GAMEENGINE +# include "BL_System.h" +#else /* dummy */ +# define SYS_SystemHandle int +#endif + +#include <signal.h> + +#include "creator_intern.h" /* own include */ + +/* set breakpoints here when running in debug mode, useful to catch floating point errors */ +#if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE) +static void sig_handle_fpe(int UNUSED(sig)) +{ + fprintf(stderr, "debug: SIGFPE trapped\n"); +} +#endif + +/* handling ctrl-c event in console */ +#if !defined(WITH_HEADLESS) +static void sig_handle_blender_esc(int sig) +{ + static int count = 0; + + G.is_break = true; /* forces render loop to read queue, not sure if its needed */ + + if (sig == 2) { + if (count) { + printf("\nBlender killed\n"); + exit(2); + } + printf("\nSent an internal break event. Press ^C again to kill Blender\n"); + count++; + } +} +#endif + +static void sig_handle_crash_backtrace(FILE *fp) +{ + fputs("\n# backtrace\n", fp); + BLI_system_backtrace(fp); +} + +static void sig_handle_crash(int signum) +{ + +#if 0 + { + char fname[FILE_MAX]; + + if (!G.main->name[0]) { + BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend"); + } + else { + BLI_strncpy(fname, G.main->name, sizeof(fname)); + BLI_replace_extension(fname, sizeof(fname), ".crash.blend"); + } + + printf("Writing: %s\n", fname); + fflush(stdout); + + BKE_undo_save_file(fname); + } +#endif + + FILE *fp; + char header[512]; + wmWindowManager *wm = G.main->wm.first; + + char fname[FILE_MAX]; + + if (!G.main->name[0]) { + BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt"); + } + else { + BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G.main->name)); + BLI_replace_extension(fname, sizeof(fname), ".crash.txt"); + } + + printf("Writing: %s\n", fname); + fflush(stdout); + +#ifndef BUILD_DATE + BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG); +#else + BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n", + BLEND_VERSION_ARG, build_commit_date, build_commit_time, build_hash); +#endif + + /* open the crash log */ + errno = 0; + fp = BLI_fopen(fname, "wb"); + if (fp == NULL) { + fprintf(stderr, "Unable to save '%s': %s\n", + fname, errno ? strerror(errno) : "Unknown error opening file"); + } + else { + if (wm) { + BKE_report_write_file_fp(fp, &wm->reports, header); + } + + sig_handle_crash_backtrace(fp); + + fclose(fp); + } + + /* Delete content of temp dir! */ + BKE_tempdir_session_purge(); + + /* really crash */ + signal(signum, SIG_DFL); +#ifndef WIN32 + kill(getpid(), signum); +#else + TerminateProcess(GetCurrentProcess(), signum); +#endif +} + +#ifdef WIN32 +LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr); + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr); + break; + case EXCEPTION_BREAKPOINT: + fputs("Error: EXCEPTION_BREAKPOINT\n", stderr); + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr); + break; + case EXCEPTION_FLT_DENORMAL_OPERAND: + fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr); + break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr); + break; + case EXCEPTION_FLT_INEXACT_RESULT: + fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr); + break; + case EXCEPTION_FLT_INVALID_OPERATION: + fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr); + break; + case EXCEPTION_FLT_OVERFLOW: + fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr); + break; + case EXCEPTION_FLT_STACK_CHECK: + fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr); + break; + case EXCEPTION_FLT_UNDERFLOW: + fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr); + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr); + break; + case EXCEPTION_IN_PAGE_ERROR: + fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr); + break; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr); + break; + case EXCEPTION_INT_OVERFLOW: + fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr); + break; + case EXCEPTION_INVALID_DISPOSITION: + fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr); + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr); + break; + case EXCEPTION_PRIV_INSTRUCTION: + fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr); + break; + case EXCEPTION_SINGLE_STEP: + fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr); + break; + case EXCEPTION_STACK_OVERFLOW: + fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr); + break; + default: + fputs("Error: Unrecognized Exception\n", stderr); + break; + } + + fflush(stderr); + + /* If this is a stack overflow then we can't walk the stack, so just show + * where the error happened */ + if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) { +#ifdef NDEBUG + TerminateProcess(GetCurrentProcess(), SIGSEGV); +#else + sig_handle_crash(SIGSEGV); +#endif + } + + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +static void sig_handle_abort(int UNUSED(signum)) +{ + /* Delete content of temp dir! */ + BKE_tempdir_session_purge(); +} + + +void main_signal_setup(void) +{ + if (app_state.signal.use_crash_handler) { +#ifdef WIN32 + SetUnhandledExceptionFilter(windows_exception_handler); +#else + /* after parsing args */ + signal(SIGSEGV, sig_handle_crash); +#endif + } + + if (app_state.signal.use_abort_handler) { + signal(SIGABRT, sig_handle_abort); + } +} + +void main_signal_setup_background(void) +{ + /* for all platforms, even windos has it! */ + BLI_assert(G.background); + +#if !defined(WITH_HEADLESS) + signal(SIGINT, sig_handle_blender_esc); /* ctrl c out bg render */ +#endif +} + + +void main_signal_setup_fpe(void) +{ +#if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE) + /* zealous but makes float issues a heck of a lot easier to find! + * set breakpoints on sig_handle_fpe */ + signal(SIGFPE, sig_handle_fpe); + +# if defined(__linux__) && defined(__GNUC__) + feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +# endif /* defined(__linux__) && defined(__GNUC__) */ +# if defined(OSX_SSE_FPE) + /* OSX uses SSE for floating point by default, so here + * use SSE instructions to throw floating point exceptions */ + _MM_SET_EXCEPTION_MASK(_MM_MASK_MASK & ~ + (_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO)); +# endif /* OSX_SSE_FPE */ +# if defined(_WIN32) && defined(_MSC_VER) + _controlfp_s(NULL, 0, _MCW_EM); /* enables all fp exceptions */ + _controlfp_s(NULL, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM); /* hide the ones we don't care about */ +# endif /* _WIN32 && _MSC_VER */ +#endif +} + +#endif /* WITH_PYTHON_MODULE */
\ No newline at end of file |