Skip to content
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

Is it possible to hot reload unmanaged DLLs? #118

Closed
KatoStoelen opened this issue Jan 3, 2020 · 3 comments · Fixed by #119
Closed

Is it possible to hot reload unmanaged DLLs? #118

KatoStoelen opened this issue Jan 3, 2020 · 3 comments · Fixed by #119
Assignees
Labels
enhancement New feature or request help wanted Extra attention is needed question Further information is requested
Milestone

Comments

@KatoStoelen
Copy link
Contributor

Posting this issue as a question. It's related to #93 but for unmanaged DLLs.

Scenario - Plugin Accessing a SQL Server Database

You add the Microsoft.Data.SqlClient NuGet package to the plugin project, which (on Windows atleast) has a dependency on sni.dll. The host runs fine when you start it. However, if you want to make a change to the plugin and deploy a new version without restarting the host, the deployment might failt due to sni.dll being locked by the host process.

You might be able to just ignore the fact that you cannot change or delete the unmanaged DLLs, but would it be possible to achieve hot reloading of plugins dependent on unmanaged DLLs?

@KatoStoelen KatoStoelen added the question Further information is requested label Jan 3, 2020
@natemcmaster natemcmaster added the help wanted Extra attention is needed label Jan 4, 2020
@natemcmaster
Copy link
Owner

Is loading multiple versions of an unmanaged .dll even supported by AssemblyLoadContext? Unlike managed assemblies, unmanaged .dll's don't have a version (from the perspective of coreclr), so I'm not sure what the DllImport resolver does when asked for an unmanaged dll that has already been loaded.

If ALC does allow multiple versions of an unmanaged library, then we can consider supporting this. AssemblyLoadContext has an API which allows loading managed .dll's from a stream, which is how hot reload avoids file-locking.

public Assembly LoadAssemblyFromFilePath(string path)
{
if (!_loadInMemory)
{
return LoadFromAssemblyPath(path);
}
using var file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
return LoadFromStream(file);
}
I don't see an equivalent for unmanaged .dll's on https://docs.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext. The only alternative I can think of is to implement "shadow copy". Copy the unmanaged .dll to a path in /tmp (or Windows equivalent) and load that instead, and make sure to delete the tmp file once the context is unloaded/disposed. That change would need to be attempting in
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
.

@KatoStoelen
Copy link
Contributor Author

I thought about shadow copying, but as observed in #93 the DLL is still locked by the host process even after the context is disposed. Which would mean that the shadow copy of the DLLs would be locked until the host process is stopped. One could select a different, unique target directory for the shadow copy on each reload. ALC might be smart enough to know when an unmanaged DLL is already loaded? This approach does seem a little hackish, though. When the plugin no longer requires a specific unmanaged DLL, one would have to restart the host process to free up memory (if my observation is correct).

It would have been nice to load the unmanaged DLLs into memory, but it might be that the limitations of this approach is the reason for why ALC does not provide such an option?

@natemcmaster
Copy link
Owner

I think a unique target directory for each reload is necessary. In the absence of a better solution, shadow copy is worth prototyping to validate this guess.

By the way, I've marked this issue as 'help wanted' as I don't have time to take this on right now, but I'm willing to accept a pull request to resolve this.

natemcmaster pushed a commit that referenced this issue Jan 10, 2020
When hot reloading is enabled, unmanaged DLLs will be shadow copied to a
unique temp directory per PluginLoader to allow replacing the original file. 
The temp directory is deleted when the AssemblyLoadContext is unloaded.

Fixes #118
@natemcmaster natemcmaster added this to the 1.1.0 milestone Jan 10, 2020
@natemcmaster natemcmaster added the enhancement New feature or request label Jan 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants