Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

Merged
merged 5 commits into from
Nov 18, 2016
Merged

Conversation

ethomson
Copy link
Member

When running in a child thread, we cannot clar_git_pass (or anything that will cause clar to longjmp to its error handler):

The effect of a call to longjmp() where initialization of the jmp_buf structure was not performed in the calling thread is undefined.

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 thethreads::refdb test, but it does make it easier to reason about.

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(); \
Copy link
Member

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?

Copy link
Member Author

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_passing 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>"); \
Copy link
Member

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()?

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

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.

Edward Thomson added 3 commits November 18, 2016 16:52
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.
@ethomson ethomson force-pushed the ethomson/clar_threads branch from 861586c to 6a05c7a Compare November 18, 2016 16:52
@ethomson ethomson force-pushed the ethomson/clar_threads branch from 62d4225 to 6367c58 Compare November 18, 2016 19:00
@carlosmn carlosmn merged commit ae5838f into master Nov 18, 2016
@ethomson ethomson deleted the ethomson/clar_threads branch January 13, 2017 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants