- BKE_blender_version.h (only version defines & versionstr). - BKE_blender_copybuffer.h (currently only used for view3d copy/paste). - BKE_blender_undo.h (global undo functions). - BKE_blendfile.h (high level blend file read/write API).
		
			
				
	
	
		
			328 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			328 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * ***** 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_version.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 */ |