diff --git a/drivers/gpu/nvgpu/include/nvgpu/posix/bug.h b/drivers/gpu/nvgpu/include/nvgpu/posix/bug.h index 995a9885e..b17447568 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/posix/bug.h +++ b/drivers/gpu/nvgpu/include/nvgpu/posix/bug.h @@ -24,6 +24,7 @@ #define __NVGPU_POSIX_BUG_H__ #include +#include /* * TODO: make these actually useful! @@ -54,4 +55,29 @@ void dump_stack(void); void __bug(const char *fmt, ...) __attribute__ ((noreturn)); bool __warn(bool cond, const char *fmt, ...); +/* Provide a simple API for BUG() handling */ +void bug_handler_register(jmp_buf *handler); +void bug_handler_cancel(void); + +/* + * Macro to indicate that a BUG() call is expected when executing + * the "code_to_run" block of code. The macro uses a statement expression + * and the setjmp API to set a long jump point that gets called by the BUG() + * function if enabled. This allows the macro to simply expand as true if + * BUG() was called, and false otherwise. + */ + +#define EXPECT_BUG(code_to_run) \ + ({ \ + jmp_buf handler; \ + bool bug_result = true; \ + if (!setjmp(handler)) { \ + bug_handler_register(&handler); \ + code_to_run; \ + bug_handler_cancel(); \ + bug_result = false; \ + } \ + bug_result; \ + }) + #endif diff --git a/drivers/gpu/nvgpu/libnvgpu-drv.export b/drivers/gpu/nvgpu/libnvgpu-drv.export index 122247493..96c57796e 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv.export @@ -10,6 +10,8 @@ __nvgpu_set_enabled bitmap_clear bitmap_find_next_zero_area_off bitmap_set +bug_handler_cancel +bug_handler_register clear_bit find_first_bit find_first_zero_bit diff --git a/drivers/gpu/nvgpu/os/posix/bug.c b/drivers/gpu/nvgpu/os/posix/bug.c index cf5b36bc1..62a9c25b5 100644 --- a/drivers/gpu/nvgpu/os/posix/bug.c +++ b/drivers/gpu/nvgpu/os/posix/bug.c @@ -24,6 +24,23 @@ #include #include #include +#include +#include + +static _Thread_local bool expect_bug; +static _Thread_local jmp_buf *jmp_handler; + +void bug_handler_register(jmp_buf *handler) +{ + expect_bug = true; + jmp_handler = handler; +} + +void bug_handler_cancel(void) +{ + expect_bug = false; + jmp_handler = NULL; +} static void __dump_stack(unsigned int skip_frames) { @@ -40,9 +57,14 @@ void dump_stack(void) */ void __bug(const char *fmt, ...) { + if (expect_bug) { + nvgpu_info(NULL, "Expected BUG detected!"); + expect_bug = false; + /* Perform a long jump to where "setjmp()" was called. */ + longjmp(*jmp_handler, 1); + } + /* If BUG is unexpected, raise a SIGSEGV signal and kill the thread */ nvgpu_err(NULL, "BUG detected!"); - - /* Raise a bad system call signal and kill the thread */ (void) raise(SIGSEGV); pthread_exit(NULL); }