-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Introduce some clar helpers for child threads #4010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Introduce `git_thread_exit`, which will allow threads to terminate at an arbitrary time, returning a `void *`. On Windows, this means that we need to store the current `git_thread` in TLS, so that we can set its `return` value when terminating. We cannot simply use `ExitThread`, since Win32 returns `DWORD`s from threads; we return `void *`.
#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(); \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't the giterr_clear()
just above this get rid of the information we're trying to store?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same mechanism that cl_git_pass
uses. It's aimed to work as cl_git_pass(git_function...)
, so it clears any prior errors before executing git_function
.
Getting rid of this would be annoying when we fail for some reason that doesn't set the git error. For example, when a function returns GIT_ITEROVER
or something unexpectedly. It would be weird to report the last error message which probably has nothing to do with the failure.
It breaks down in this case, where we're cl_git_pass
ing after executing the thing that failed - sort of like we do here.
((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>"); \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_last->message
would get freed when the thread exits, no? Wouldn't we want to strdup()
it or git_buf_detach()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will, that's why we're stuffing it into the error_msg
to preserve that data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(This follows the same pattern as cl_git_pass
, FWIW.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I completely missed the fact that expr
is an expression rather than the result; it must be all of those backticks confusing me.
We want a predictable number of initializations in our multithreaded init test, but we also want to make sure that we have _actually_ initialized `git_libgit2_init` before calling `git_thread_create` (since it now has a sanity check that `git_libgit2_init` has been called). Since `git_thread_create` is internal-only, keep this sanity check. Flip the invocation so that we `git_libgit2_init` before our thread tests and `git_libgit2_shutdown` again after.
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.
861586c
to
6a05c7a
Compare
62d4225
to
6367c58
Compare
When running in a child thread, we cannot
clar_git_pass
(or anything that will cause clar tolongjmp
to its error handler):Instead, provide some helpers to set up an error context in the child thread that the clar execution thread can then restore and abort when safe. Use this for the
threads::refdb
test so that it errors gracefully, instead of crashing.Obviously this does not fix the underlying problem in the
threads::refdb
test, but it does make it easier to reason about.