Skip to content

Commit b1df1be

Browse files
committed
Allocate on the heap and register that pointer
1 parent a8b201d commit b1df1be

File tree

3 files changed

+42
-17
lines changed

3 files changed

+42
-17
lines changed

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ internal static extern int git_diff_find_similar(
507507
[DllImport(libgit2)]
508508
internal static extern int git_filter_register(
509509
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string name,
510-
ref GitFilter gitFilter, int priority);
510+
IntPtr gitFilter, int priority);
511511

512512
[DllImport(libgit2)]
513513
internal static extern int git_filter_unregister(

LibGit2Sharp/Core/Proxy.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -741,18 +741,18 @@ public static GitDiffDelta git_diff_get_delta(DiffSafeHandle diff, int idx)
741741

742742
#region git_filter_
743743

744-
public static GitFilter git_filter_register(string name, ref GitFilter filter, int priority)
744+
public static void git_filter_register(string name, IntPtr filter, int priority)
745745
{
746746
using (ThreadAffinity())
747747
{
748-
int res = NativeMethods.git_filter_register(name, ref filter, priority);
748+
int res = NativeMethods.git_filter_register(name, filter, priority);
749749
if (res == (int)GitErrorCode.Exists)
750750
{
751751
var message = string.Format("A filter with the name '{0}' is already registered.", name);
752752
throw new InvalidOperationException(message);
753753
}
754754
Ensure.ZeroResult(res);
755-
return filter;
755+
// return filter;
756756
}
757757
}
758758

LibGit2Sharp/Filter.cs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Runtime.InteropServices;
23
using System.Text;
34
using LibGit2Sharp.Core;
45

@@ -9,45 +10,54 @@ namespace LibGit2Sharp
910
/// </summary>
1011
public sealed class Filter
1112
{
12-
private GitFilter filter;
13-
private readonly string name;
13+
private GitFilter managedFilter;
14+
private IntPtr nativeFilter;
15+
16+
private readonly string filterName;
1417
private readonly string attributes;
1518
private readonly int version;
1619

20+
1721
/// <summary>
1822
/// Initializes a new instance of the <see cref="Filter"/> class.
23+
/// And allocates the filter natively.
1924
/// </summary>
2025
public Filter(string name, string attributes, int version)
2126
{
2227
Ensure.ArgumentNotNullOrEmptyString(name, "name");
2328
Ensure.ArgumentNotNullOrEmptyString(attributes, "attributes");
2429
Ensure.ArgumentNotNull(version, "version");
2530

26-
this.name = name;
31+
this.filterName = name;
2732
this.attributes = attributes;
2833
this.version = version;
29-
filter = new GitFilter
34+
35+
managedFilter = new GitFilter
3036
{
3137
attributes = EncodingMarshaler.FromManaged(Encoding.UTF8, attributes),
32-
version = (uint)version
38+
version = (uint)version,
39+
shutdown = FilterCallbacks.ShutdownCallback,
3340
};
41+
42+
nativeFilter = Marshal.AllocHGlobal(Marshal.SizeOf(managedFilter));
43+
Marshal.StructureToPtr(managedFilter, nativeFilter, false);
3444
}
3545

3646
internal Filter(string name, IntPtr filterPtr)
3747
{
38-
var handle = filterPtr.MarshalAs<GitFilter>();
39-
this.name = name;
40-
this.version = (int)handle.version;
41-
this.attributes = LaxUtf8Marshaler.FromNative(handle.attributes);
48+
nativeFilter = filterPtr;
49+
managedFilter = nativeFilter.MarshalAs<GitFilter>();
50+
filterName = name;
51+
attributes = EncodingMarshaler.FromNative(Encoding.UTF8, this.managedFilter.attributes);
52+
version = (int) managedFilter.version;
4253
}
4354

44-
4555
/// <summary>
4656
/// The name that this filter was registered with
4757
/// </summary>
4858
public string Name
4959
{
50-
get { return name; }
60+
get { return filterName; }
5161
}
5262

5363
/// <summary>
@@ -71,15 +81,30 @@ public int Version
7181
/// </summary>
7282
public void Register()
7383
{
74-
filter = Proxy.git_filter_register(name, ref filter, 1);
84+
Proxy.git_filter_register(filterName, nativeFilter, 1);
7585
}
7686

7787
/// <summary>
78-
/// Remove the filter from the registry.
88+
/// Remove the filter from the registry, and frees the native heap allocation.
7989
/// </summary>
8090
public void Deregister()
8191
{
8292
Proxy.git_filter_unregister(Name);
93+
Marshal.FreeHGlobal(nativeFilter);
94+
}
95+
96+
private static class FilterCallbacks
97+
{
98+
// Because our GitFilter structure exists on the managed heap only for a short time (to be marshaled
99+
// to native memory with StructureToPtr), we need to bind to static delegates. If at construction time
100+
// we were to bind to the methods directly, that's the same as newing up a fresh delegate every time.
101+
// Those delegates won't be rooted in the object graph and can be collected as soon as StructureToPtr finishes.
102+
public static readonly GitFilter.git_filter_shutdown_fn ShutdownCallback = Shutdown;
103+
104+
private static void Shutdown(IntPtr gitFilter)
105+
{
106+
Console.WriteLine("Shut down mother fucker");
107+
}
83108
}
84109
}
85110

0 commit comments

Comments
 (0)