This is an archive of the discontinued LLVM Phabricator instance.

Add functionality to load dynamic libraries temporarily
ClosedPublic

Authored by Holman on Sep 27 2022, 2:12 PM.

Details

Summary

Previously, it was possible to load dynamic libraries which would be unloaded on llvm_shutdown(), but recently ManagedStatic removal changed this so that loaded libraries really can't ever be unloaded. This functionality was very useful, and so to add it back in a more explicit way, I've added new getLibrary() and closeLibrary() methods to allow callers to use the very convenient platform independent abstraction that LLVM has for dynamic libraries.

As a specific use case, the onnx-mlir project was using this functionality with an API that allows instancing LLVM so you can compile a shared library, and then load that library, and eventually close the instance (and library) and compile something else. This change to llvm_shutdown causes libraries to leak and also locks the libraries for the entire duration of the program which prevents reusing library names.

Diff Detail

Event Timeline

Holman created this revision.Sep 27 2022, 2:12 PM
Herald added a project: Restricted Project. · View Herald TranscriptSep 27 2022, 2:12 PM
Holman requested review of this revision.Sep 27 2022, 2:12 PM
lhames accepted this revision.Sep 28 2022, 12:45 PM

I think it makes sense to introduce a closeLibrary operation, and I'm ok with this as an initial implementation.

I'm a little worried about introducing the separate TemporaryHandles set since that will affect lookup order, but we never really promised a sensible lookup order before anyway.

Long term we should refactor sys::DynamicLibrary to (1) be the thinnest possible wrapper around the OS library load / close calls, (2) provide guarantees on lookup order if possible (should we match the order that libraries were opened in? or use system RTLD_GLOBAL or equivalent?). I don't think that kind of refactoring should block this patch though.

@nhaehnle -- There was no library unloading story in https://reviews.llvm.org/D129127 beyond "they'll all get unloaded when the process terminates", right? I think we need a bulk-unloading story. Would it make sense to add a destructor to the Globals struct so that if a library with sys::DynamicLibrary compiled in is closed then all libraries loaded through that interface are closed too?

llvm/include/llvm/Support/DynamicLibrary.h
98

Since you're touching these APIs anyway, could you add a note that they forward to the underlying OS library load/close operations, and that we make no guarantees about when those will actually close them library. (e.g. on Darwin, libraries containing Swift or ObjC will never be closed).

llvm/lib/Support/DynamicLibrary.cpp
49–50

&& binds tighter than || -- I think you'll want parens here.

This revision is now accepted and ready to land.Sep 28 2022, 12:45 PM
Holman updated this revision to Diff 463958.Sep 29 2022, 10:39 AM

Fix assert, add comments about unload semantics

Holman marked 2 inline comments as done.Sep 29 2022, 10:40 AM

I think it makes sense to introduce a closeLibrary operation, and I'm ok with this as an initial implementation.

I'm a little worried about introducing the separate TemporaryHandles set since that will affect lookup order, but we never really promised a sensible lookup order before anyway.

Long term we should refactor sys::DynamicLibrary to (1) be the thinnest possible wrapper around the OS library load / close calls, (2) provide guarantees on lookup order if possible (should we match the order that libraries were opened in? or use system RTLD_GLOBAL or equivalent?). I don't think that kind of refactoring should block this patch though.

I agree, I went this route because it was the least intrusive to the current API and I didn't fully understand the context of why getPermanentLibrary opens a handle and then closes the existing handle if one exists instead of something like the semantics I added, but I think I see now it was about lookup order.

@nhaehnle -- There was no library unloading story in https://reviews.llvm.org/D129127 beyond "they'll all get unloaded when the process terminates", right? I think we need a bulk-unloading story. Would it make sense to add a destructor to the Globals struct so that if a library with sys::DynamicLibrary compiled in is closed then all libraries loaded through that interface are closed too?

HandleSet has a destructor that I believe that should covers this case.

Also, I do not have commit access, so can you please help me get this merged if it looks ok?

This revision was automatically updated to reflect the committed changes.