-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Rework dlsym()
, dlopen()
, jl_dlsym()
and jl_load_dynamic_library()
APIs
#28888
Conversation
Libdl.dlsym()
and jl_dlsym()
.Libdl.dlsym()
, Libdl.dlopen()
, jl_dlsym()
and jl_load_dynamic_library()
APIs
Libdl.dlsym()
, Libdl.dlopen()
, jl_dlsym()
and jl_load_dynamic_library()
APIsdlsym()
, dlopen()
, jl_dlsym()
and jl_load_dynamic_library()
APIs
src/dlload.c
Outdated
/* Next, check for errors. On Windows, a NULL pointer means the symbol | ||
* was not found. On everything else, we can have NULL symbols, so we check | ||
* for non-NULL returns from dlerror(). */ | ||
const char * err = jl_dlerror(); |
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.
Not a big deal, but we don't really need to do this work on windows unless we know there's a failure.
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 originally had it split out but it was enough extra code that I liked it better this way. Optimizing for the programmer, not the program, I suppose.
src/dlload.c
Outdated
{ | ||
#ifdef _OS_WINDOWS_ | ||
CHAR reason[256]; | ||
static CHAR reason[256]; |
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 makes this no longer thread safe, which is probably fine if we only do it in the error case, but if we do it in the success case as well, I'm worried the error message will get overwritten by the success of a different thread.
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.
I've fixed this by slapping __thread
in front of it.
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.
Unfortunately, we can't assume that that's universally available.
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.
I was taking my inspiration from support/dirname.c
. Can I do:
# if !defined(_COMPILER_MICROSOFT_)
static __thread char reason[256];
# else
static __declspec(thread) char reason[256];
# endif
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.
If you really need to, you can use our own tls... There're already platform dependent members in there so it shouldn't be a huge problem even though it won't look as nice and will certainly needs cross references in the comments.
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.
Because there seems to be some disagreement within the Julia codebase, I have taken the liberty of adding #define JL_THREAD_LOCAL
to julia.h
which emulates what is held within src/support/dirname.c
. If this shouldn't be done (and we should instead use the more complex TLS implementation in src/threading.c
), it's probably best to transition both jl_dlerror()
and dirname()
to use that new stuff instead.
Do you want to separate out the |
src/ccall.cpp
Outdated
@@ -1490,13 +1491,11 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) | |||
}; | |||
#define is_libjulia_func(name) _is_libjulia_func((uintptr_t)&(name), #name) | |||
|
|||
static auto ptls_getter = &jl_get_ptls_states; |
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.
Why the change? This completely defeated the purpose of the old code, which is clearly stated in the comment..............
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's because I have been dealing with the dynamic (runtime) linker too much, so when it said "can cause linker issues" I naively thought that meant at runtime when the symbol actually gets used. I didn't realize this caused issues at compile-time link. :P
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.
You are welcome to change the comment in whichever way you want so that anyone that have read that comment won't change this code without testing the compiler configure combination again.....
With regards to splitting out the That's okay though; because BP doesn't strictly need this; the |
d517d3a
to
cac021c
Compare
^^ Due to a missing semicolon. Impressive. |
119d60d
to
29398e6
Compare
Huzzah! We are passing all tests. If I could get a thumbs up or thumbs down on the API exposed here, then we can make the final decision. I have purposefully not put in deprecation warnings for the |
Ok by me. @yuyichao ? |
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.
LGTM. The ccall ptls getter lookup is correct but is just very confusing though....
// directly accessing the address of an ifunc can cause compile-time linker issues | ||
// on some configurations (e.g. AArch64 + -Bsymbolic-functions), so we guard the | ||
// `&jl_get_ptls_states` within this `#ifdef` guard, and use a more roundabout | ||
// method involving `jl_dlsym()` on Linux platforms instead. | ||
#ifdef _OS_LINUX_ |
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 actually makes the static
useless. The performance isn't super critical here so if you want to just get rid of the static
that's fine. Otherwise you can write it as.
static auto ptls_getter = [] {
#ifdef _OS_LINUX_
jl_ptls_t (*p)(void);
jl_dlsym(....);
return p;
#else
return jl_get_ptls_states;
#endif
}();
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.
Wow, that's available even all the way back to GCC 4.8.5
. I'm amazed. And yes, you're right this completely defeats static
, but I like this fancy lambda initialization. I'm gonna go with that since compiler support is good enough.
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 standard C++11 feature and we require C++11 so that shouldn't be very surprising......
{ | ||
#ifdef _OS_WINDOWS_ | ||
CHAR reason[256]; | ||
static JL_THREAD_LOCAL CHAR reason[256]; |
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.
No change needed but note that the "more complex" tls implementation we have should actually be simpler and faster.
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.
Simpler than just writing JL_THREAD_LOCAL
? How would I use it?
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.
Simpler in the code generated that is.
* Remove `jl_dlsym_e()` to instead be rolled into `jl_dlsym()` with a `throw_err` parameter, similar to `jl_load_dynamic_library()`. * Fix #28881 by having `Libdl.dlsym()` return `nothing` on missing symbol, rather than `C_NULL`.
This changes `dlopen()` to mimic `dlsym()` so that a negative result returns `nothing`. While not necessary in the same way as in the `dlsym()` case (there are no valid `NULL` `dlopen()` results) the consistency is worth it.
When this goes green, I'm going to merge. Thanks for the shepherding, Keno and Yichao! |
I'm not sure that I like the new API any better than the old, but I suppose that's not very helpful feedback. |
Feel free to suggest a better API in a new PR. I’m going to sit with his one for now. |
The behavioral change of returning |
Seems like the correct place to me. |
Remove
jl_dlsym_e()
to instead be rolled intojl_dlsym()
with athrow_err
parameter, similar tojl_load_dynamic_library_()
.Fix
jl_dlsym
incorrectly assumes a NULL return is an error #28881 by havingLibdl.dlsym()
returnnothing
on missing symbol, rather thanC_NULL
.Change
dlopen()
to mimicdlsym()
so that a negative result returnsnothing
. While not necessary in the same way as in thedlsym()
case (there are no validNULL
dlopen()
results) the consistency is worth it.