Skip to content

Native loading: simplify git_libgit2_init / git_libgit2_shutdown #1438

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 4 commits into from
Jun 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

### Fixes

- The exception thrown when the native library cannot be loaded is now
able to be caught and will no longer crash the process.

## v0.24 - ([diff](https://github.com/libgit2/libgit2sharp/compare/v0.23..v0.24))

This is the last release before a moving to .NET Core compatible library.
Expand Down
87 changes: 30 additions & 57 deletions LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,62 +17,13 @@ internal static partial class NativeMethods
{
public const uint GIT_PATH_MAX = 4096;
private const string libgit2 = NativeDllName.Name;
// This is here to keep the pointer alive
#pragma warning disable 0414
private static readonly LibraryLifetimeObject lifetimeObject;
#pragma warning restore 0414
private static int handlesCount;

/// <summary>
/// Internal hack to ensure that the call to git_threads_shutdown is called after all handle finalizers
/// have run to completion ensuring that no dangling git-related finalizer runs after git_threads_shutdown.
/// There should never be more than one instance of this object per AppDomain.
/// </summary>
private sealed class LibraryLifetimeObject
#if DESKTOP
: CriticalFinalizerObject
#endif
{
// Ensure mono can JIT the .cctor and adjust the PATH before trying to load the native library.
// See https://github.com/libgit2/libgit2sharp/pull/190
[MethodImpl(MethodImplOptions.NoInlining)]
public LibraryLifetimeObject()
{
int res = git_libgit2_init();
Ensure.Int32Result(res);
if (res == 1)
{
// Ignore the error that this propagates. Call it in case openssl is being used.
git_openssl_set_locking();
}
AddHandle();
}

~LibraryLifetimeObject()
{
RemoveHandle();
}
}

#if DESKTOP
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
#endif
internal static void AddHandle()
{
Interlocked.Increment(ref handlesCount);
}

#if DESKTOP
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
#endif
internal static void RemoveHandle()
{
int count = Interlocked.Decrement(ref handlesCount);
if (count == 0)
{
git_libgit2_shutdown();
}
}
// An object tied to the lifecycle of the NativeMethods static class.
// This will handle initialization and shutdown of the underlying
// native library.
#pragma warning disable 0414
private static readonly NativeShutdownObject shutdownObject;
#pragma warning restore 0414

static NativeMethods()
{
Expand All @@ -87,8 +38,30 @@ static NativeMethods()
String.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", path, Path.PathSeparator, Environment.GetEnvironmentVariable(pathEnvVariable)));
}

// See LibraryLifetimeObject description.
lifetimeObject = new LibraryLifetimeObject();
LoadNativeLibrary();
shutdownObject = new NativeShutdownObject();
}

// Avoid inlining this method because otherwise mono's JITter may try
// to load the library _before_ we've configured the path.
[MethodImpl(MethodImplOptions.NoInlining)]
private static void LoadNativeLibrary()
{
// Configure the OpenSSL locking on the true initialization
// of the library.
if (git_libgit2_init() == 1)
{
git_openssl_set_locking();
}
}

// Shutdown the native library in a finalizer.
private sealed class NativeShutdownObject
{
~NativeShutdownObject()
{
git_libgit2_shutdown();
}
}

[DllImport(libgit2)]
Expand Down