Skip to content
This repository was archived by the owner on Oct 1, 2024. It is now read-only.

Commit e48ac63

Browse files
committed
generator: Dispose ownable method parameters in VM callback (bxc#237)
Some virtual methods are passed a native object that is wrapped in an IDisposable managed object, which is then passed on to the managed overrides. We need to dispose those objects as soon as possible, otherwise their native counterpart will not be freed until the next garbage collection. Requiring the overrides to dispose them would be cumbersome and error-prone. Those parameters will now be disposed in a finally {...} block, after the virtual method has returned. This means that overrides should not keep a reference to such a parameter outside of the scope of the method, as it will be diposed when the method returns. This change only affects Cairo.Context parameter for now, but it was particularly needed for them, as they could happily hold on to tens of MBs of memory until the next garbage collection.
1 parent 2967482 commit e48ac63

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

generator/ManagedCallString.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace GtkSharp.Generation {
2828
public class ManagedCallString {
2929

3030
IDictionary<Parameter, bool> parms = new Dictionary<Parameter, bool> ();
31+
IList<Parameter> dispose_params = new List<Parameter> ();
3132
string error_param = null;
3233
string user_data_param = null;
3334
string destroy_param = null;
@@ -57,6 +58,10 @@ public ManagedCallString (Parameters parms)
5758
special = true;
5859

5960
this.parms.Add (p, special);
61+
62+
if (p.IsOwnable) {
63+
dispose_params.Add (p);
64+
}
6065
}
6166
}
6267

@@ -70,10 +75,18 @@ public bool HasOutParam {
7075
}
7176
}
7277

78+
public bool HasDisposeParam {
79+
get { return dispose_params.Count > 0; }
80+
}
81+
7382
public string Unconditional (string indent) {
7483
string ret = "";
7584
if (error_param != null)
7685
ret = indent + error_param + " = IntPtr.Zero;\n";
86+
87+
foreach (Parameter p in dispose_params) {
88+
ret += indent + p.CSType + " my" + p.Name + " = null;\n";
89+
}
7790
return ret;
7891
}
7992

@@ -103,6 +116,10 @@ public string Setup (string indent)
103116
}
104117
}
105118

119+
foreach (Parameter p in dispose_params) {
120+
ret += indent + "my" + p.Name + " = " + p.FromNative (p.Name) + ";\n";
121+
}
122+
106123
return ret;
107124
}
108125

@@ -119,7 +136,12 @@ public override string ToString ()
119136
if (p.Generatable is CallbackGen) {
120137
result [i] += p.Name + "_invoker.Handler";
121138
} else {
122-
result [i] += (parms [p]) ? "my" + p.Name : p.FromNative (p.Name);
139+
if (parms [p] || dispose_params.Contains(p)) {
140+
// Parameter was declared and marshalled earlier
141+
result [i] += "my" + p.Name;
142+
} else {
143+
result [i] += p.FromNative (p.Name);
144+
}
123145
}
124146
i++;
125147
}
@@ -150,6 +172,22 @@ public string Finish (string indent)
150172

151173
return ret;
152174
}
175+
176+
public string DisposeParams (string indent)
177+
{
178+
string ret = "";
179+
180+
foreach (Parameter p in dispose_params) {
181+
string name = "my" + p.Name;
182+
string disp_name = "disposable_" + p.Name;
183+
184+
ret += indent + "var " + disp_name + " = " + name + " as IDisposable;\n";
185+
ret += indent + "if (" + disp_name + " != null)\n";
186+
ret += indent + "\t" + disp_name + ".Dispose ();\n";
187+
}
188+
189+
return ret;
190+
}
153191
}
154192
}
155193

generator/Parameter.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,12 @@ public string Name {
186186
}
187187
}
188188

189+
public bool IsOwnable {
190+
get {
191+
return this.Generatable is OwnableGen;
192+
}
193+
}
194+
189195
public bool Owned {
190196
get {
191197
return elem.GetAttribute ("owned") == "true";

generator/VirtualMethod.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,17 @@ public void GenerateCallback (StreamWriter sw, ClassBase implementor)
9898
sw.WriteLine ("\t\t\t\t{0} __obj = GLib.Object.GetObject (inst, false) as {0};", type);
9999
}
100100

101-
sw.Write (call.Setup ("\t\t\t\t"));
102-
sw.Write ("\t\t\t\t");
101+
string indent = "\t\t\t\t";
103102
if (!retval.IsVoid)
104-
sw.Write (retval.CSType + " __result = ");
103+
sw.WriteLine (indent + retval.CSType + " __result;");
104+
sw.Write (call.Setup (indent));
105+
sw.Write (indent);
106+
if (!retval.IsVoid)
107+
sw.Write ("__result = ");
105108
if (!this.IsStatic)
106109
sw.Write ("__obj.");
107110
sw.WriteLine (this.CallString + ";");
108-
sw.Write (call.Finish ("\t\t\t\t"));
111+
sw.Write (call.Finish (indent));
109112
if (!retval.IsVoid)
110113
sw.WriteLine ("\t\t\t\treturn " + retval.ToNative ("__result") + ";");
111114

@@ -116,6 +119,11 @@ public void GenerateCallback (StreamWriter sw, ClassBase implementor)
116119
sw.WriteLine ("\t\t\t\t// NOTREACHED: above call does not return.");
117120
sw.WriteLine ("\t\t\t\tthrow e;");
118121
}
122+
123+
if (call.HasDisposeParam) {
124+
sw.WriteLine ("\t\t\t} finally {");
125+
sw.Write (call.DisposeParams (indent));
126+
}
119127
sw.WriteLine ("\t\t\t}");
120128
sw.WriteLine ("\t\t}");
121129
sw.WriteLine ();

0 commit comments

Comments
 (0)