diff options
author | Edward Thomson <ethomson@github.com> | 2016-11-18 07:34:20 -0500 |
---|---|---|
committer | Edward Thomson <ethomson@github.com> | 2016-11-18 16:52:28 +0000 |
commit | bbf22f8229718571059cd579945b134772f9a73d (patch) | |
tree | a33f4bd59ae257b6ad3c5ab72c5a77a5c51ac00b | |
parent | 99479062dbb738ebc5892e163b701680cea91980 (diff) | |
download | libgit2-bbf22f8229718571059cd579945b134772f9a73d.tar.gz |
clar: Introduce assertion helpers for threads
Don't `cl_git_pass` in a child thread. When the assertion fails, clar
will `longjmp` to its error handler, but:
> The effect of a call to longjmp() where initialization of the jmp_buf
> structure was not performed in the calling thread is undefined.
Instead, set up an error context that threads can populate, and the
caller can check.
-rw-r--r-- | tests/clar_libgit2.h | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/tests/clar_libgit2.h b/tests/clar_libgit2.h index d7e635302..1d8d4a50b 100644 --- a/tests/clar_libgit2.h +++ b/tests/clar_libgit2.h @@ -41,6 +41,47 @@ } \ } while(0) +/** + * Thread safe assertions; you cannot use `cl_git_report_failure` from a + * child thread since it will try to `longjmp` to abort and "the effect of + * a call to longjmp() where initialization of the jmp_buf structure was + * not performed in the calling thread is undefined." + * + * Instead, callers can provide a clar thread error context to a thread, + * which will populate and return it on failure. Callers can check the + * status with `cl_git_thread_check`. + */ +typedef struct { + int error; + const char *file; + int line; + const char *expr; + char error_msg[4096]; +} cl_git_thread_err; + +#define cl_git_thread_pass(threaderr, expr) cl_git_thread_pass_(threaderr, (expr), __FILE__, __LINE__) + +#define cl_git_thread_pass_(__threaderr, __expr, __file, __line) do { \ + giterr_clear(); \ + if ((((cl_git_thread_err *)__threaderr)->error = (__expr)) != 0) { \ + const git_error *_last = giterr_last(); \ + ((cl_git_thread_err *)__threaderr)->file = __file; \ + ((cl_git_thread_err *)__threaderr)->line = __line; \ + ((cl_git_thread_err *)__threaderr)->expr = "Function call failed: " #__expr; \ + p_snprintf(((cl_git_thread_err *)__threaderr)->error_msg, 4096, "thread 0x%" PRIxZ " - error %d - %s", \ + git_thread_currentid(), ((cl_git_thread_err *)__threaderr)->error, \ + _last ? _last->message : "<no message>"); \ + git_thread_exit(__threaderr); \ + } \ + } while (0) + +static void cl_git_thread_check(void *data) +{ + cl_git_thread_err *threaderr = (cl_git_thread_err *)data; + if (threaderr->error != 0) + clar__assert(0, threaderr->file, threaderr->line, threaderr->expr, threaderr->error_msg, 1); +} + void cl_git_report_failure(int, const char *, int, const char *); #define cl_assert_at_line(expr,file,line) \ |