cairo: Add mechanism to debug missing Dispose calls
Enabled by setting a new MONO_CAIRO_DEBUG_DISPOSE environment variable.
This commit is contained in:
parent
116d9fcc95
commit
5a78a5d177
7 changed files with 89 additions and 44 deletions
|
@ -40,6 +40,49 @@ using Cairo;
|
||||||
|
|
||||||
namespace Cairo {
|
namespace Cairo {
|
||||||
|
|
||||||
|
static class CairoDebug
|
||||||
|
{
|
||||||
|
static System.Collections.Generic.Dictionary<IntPtr,string> traces;
|
||||||
|
|
||||||
|
public static readonly bool Enabled;
|
||||||
|
|
||||||
|
static CairoDebug ()
|
||||||
|
{
|
||||||
|
var dbg = Environment.GetEnvironmentVariable ("MONO_CAIRO_DEBUG_DISPOSE");
|
||||||
|
if (dbg == null)
|
||||||
|
return;
|
||||||
|
Enabled = true;
|
||||||
|
traces = new System.Collections.Generic.Dictionary<IntPtr,string> ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnAllocated (IntPtr obj)
|
||||||
|
{
|
||||||
|
if (!Enabled)
|
||||||
|
throw new InvalidOperationException ();
|
||||||
|
|
||||||
|
traces.Add (obj, Environment.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnDisposed<T> (IntPtr obj, bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && !Enabled)
|
||||||
|
throw new InvalidOperationException ();
|
||||||
|
|
||||||
|
if (!disposing) {
|
||||||
|
Console.Error.WriteLine ("{0} is leaking, programmer is missing a call to Dispose", typeof(T).FullName);
|
||||||
|
if (Enabled) {
|
||||||
|
Console.Error.WriteLine ("Allocated from:");
|
||||||
|
Console.Error.WriteLine (traces[obj]);
|
||||||
|
} else {
|
||||||
|
Console.Error.WriteLine ("Set MONO_CAIRO_DEBUG_DISPOSE to track allocation traces");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Enabled)
|
||||||
|
traces.Remove (obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct Point
|
public struct Point
|
||||||
{
|
{
|
||||||
public Point (int x, int y)
|
public Point (int x, int y)
|
||||||
|
@ -204,12 +247,10 @@ namespace Cairo {
|
||||||
|
|
||||||
protected virtual void Dispose (bool disposing)
|
protected virtual void Dispose (bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposing){
|
if (!disposing || CairoDebug.Enabled)
|
||||||
Console.Error.WriteLine ("Cairo.Context: called from finalization thread, programmer is missing a call to Dispose");
|
CairoDebug.OnDisposed<Context> (state, disposing);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == IntPtr.Zero)
|
if (!disposing|| state == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Console.WriteLine ("Destroying");
|
//Console.WriteLine ("Destroying");
|
||||||
|
|
|
@ -61,13 +61,11 @@ namespace Cairo
|
||||||
|
|
||||||
protected virtual void Dispose (bool disposing)
|
protected virtual void Dispose (bool disposing)
|
||||||
{
|
{
|
||||||
if (handle == IntPtr.Zero)
|
if (!disposing || CairoDebug.Enabled)
|
||||||
return;
|
CairoDebug.OnDisposed<FontFace> (handle, disposing);
|
||||||
|
|
||||||
if (!disposing) {
|
if (!disposing|| handle == IntPtr.Zero)
|
||||||
Console.Error.WriteLine ("Cairo.FontFace: called from finalization thread, programmer is missing a call to Dispose");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
NativeMethods.cairo_font_face_destroy (handle);
|
NativeMethods.cairo_font_face_destroy (handle);
|
||||||
handle = IntPtr.Zero;
|
handle = IntPtr.Zero;
|
||||||
|
@ -77,6 +75,8 @@ namespace Cairo
|
||||||
public FontFace (IntPtr handle)
|
public FontFace (IntPtr handle)
|
||||||
{
|
{
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
if (CairoDebug.Enabled)
|
||||||
|
CairoDebug.OnAllocated (handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntPtr Handle {
|
public IntPtr Handle {
|
||||||
|
|
|
@ -47,6 +47,8 @@ namespace Cairo
|
||||||
internal FontOptions (IntPtr handle)
|
internal FontOptions (IntPtr handle)
|
||||||
{
|
{
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
if (CairoDebug.Enabled)
|
||||||
|
CairoDebug.OnAllocated (handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FontOptions Copy ()
|
public FontOptions Copy ()
|
||||||
|
@ -68,13 +70,11 @@ namespace Cairo
|
||||||
|
|
||||||
protected virtual void Dispose (bool disposing)
|
protected virtual void Dispose (bool disposing)
|
||||||
{
|
{
|
||||||
if (handle == IntPtr.Zero)
|
if (!disposing || CairoDebug.Enabled)
|
||||||
return;
|
CairoDebug.OnDisposed<FontOptions> (handle, disposing);
|
||||||
|
|
||||||
if (!disposing) {
|
if (!disposing|| handle == IntPtr.Zero)
|
||||||
Console.Error.WriteLine ("Cairo.FontOptions: called from finalization thread, programmer is missing a call to Dispose");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
NativeMethods.cairo_font_options_destroy (handle);
|
NativeMethods.cairo_font_options_destroy (handle);
|
||||||
handle = IntPtr.Zero;
|
handle = IntPtr.Zero;
|
||||||
|
|
|
@ -41,6 +41,8 @@ namespace Cairo {
|
||||||
internal Path (IntPtr handle)
|
internal Path (IntPtr handle)
|
||||||
{
|
{
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
if (CairoDebug.Enabled)
|
||||||
|
CairoDebug.OnAllocated (handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Path ()
|
~Path ()
|
||||||
|
@ -57,12 +59,10 @@ namespace Cairo {
|
||||||
|
|
||||||
protected virtual void Dispose (bool disposing)
|
protected virtual void Dispose (bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposing) {
|
if (!disposing || CairoDebug.Enabled)
|
||||||
Console.Error.WriteLine ("Cairo.Path: called from finalization thread, programmer is missing a call to Dispose");
|
CairoDebug.OnDisposed<Path> (handle, disposing);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handle == IntPtr.Zero)
|
if (!disposing|| handle == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
NativeMethods.cairo_path_destroy (handle);
|
NativeMethods.cairo_path_destroy (handle);
|
||||||
|
|
|
@ -66,12 +66,15 @@ namespace Cairo {
|
||||||
|
|
||||||
static Hashtable patterns = new Hashtable ();
|
static Hashtable patterns = new Hashtable ();
|
||||||
|
|
||||||
internal Pattern (IntPtr ptr)
|
internal Pattern (IntPtr handle)
|
||||||
{
|
{
|
||||||
lock (patterns){
|
lock (patterns){
|
||||||
patterns [ptr] = this;
|
patterns [handle] = this;
|
||||||
}
|
}
|
||||||
pattern = ptr;
|
|
||||||
|
Handle = handle;
|
||||||
|
if (CairoDebug.Enabled)
|
||||||
|
CairoDebug.OnAllocated (handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Pattern ()
|
~Pattern ()
|
||||||
|
@ -98,16 +101,14 @@ namespace Cairo {
|
||||||
|
|
||||||
protected virtual void Dispose (bool disposing)
|
protected virtual void Dispose (bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposing) {
|
if (!disposing || CairoDebug.Enabled)
|
||||||
Console.Error.WriteLine ("Cairo.Pattern: called from finalization thread, programmer is missing a call to Dispose");
|
CairoDebug.OnDisposed<Pattern> (Handle, disposing);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pattern == IntPtr.Zero)
|
if (!disposing|| Handle == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
NativeMethods.cairo_pattern_destroy (pattern);
|
NativeMethods.cairo_pattern_destroy (Handle);
|
||||||
pattern = IntPtr.Zero;
|
Handle = IntPtr.Zero;
|
||||||
lock (patterns){
|
lock (patterns){
|
||||||
patterns.Remove (this);
|
patterns.Remove (this);
|
||||||
}
|
}
|
||||||
|
@ -116,7 +117,7 @@ namespace Cairo {
|
||||||
[Obsolete ("Use Dispose()")]
|
[Obsolete ("Use Dispose()")]
|
||||||
public void Destroy ()
|
public void Destroy ()
|
||||||
{
|
{
|
||||||
Dispose ();
|
NativeMethods.cairo_pattern_destroy (pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Extend Extend {
|
public Extend Extend {
|
||||||
|
@ -143,6 +144,7 @@ namespace Cairo {
|
||||||
|
|
||||||
public IntPtr Handle {
|
public IntPtr Handle {
|
||||||
get { return pattern; }
|
get { return pattern; }
|
||||||
|
private set { pattern = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete ("Replaced by Handle property")]
|
[Obsolete ("Replaced by Handle property")]
|
||||||
|
|
|
@ -35,11 +35,13 @@ namespace Cairo {
|
||||||
internal ScaledFont (IntPtr handle)
|
internal ScaledFont (IntPtr handle)
|
||||||
{
|
{
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
if (CairoDebug.Enabled)
|
||||||
|
CairoDebug.OnAllocated (handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScaledFont (FontFace fontFace, Matrix matrix, Matrix ctm, FontOptions options)
|
public ScaledFont (FontFace fontFace, Matrix matrix, Matrix ctm, FontOptions options)
|
||||||
|
: this (NativeMethods.cairo_scaled_font_create (fontFace.Handle, matrix, ctm, options.Handle))
|
||||||
{
|
{
|
||||||
handle = NativeMethods.cairo_scaled_font_create (fontFace.Handle, matrix, ctm, options.Handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScaledFont ()
|
~ScaledFont ()
|
||||||
|
@ -99,13 +101,11 @@ namespace Cairo {
|
||||||
|
|
||||||
protected virtual void Dispose (bool disposing)
|
protected virtual void Dispose (bool disposing)
|
||||||
{
|
{
|
||||||
if (handle == IntPtr.Zero)
|
if (!disposing || CairoDebug.Enabled)
|
||||||
return;
|
CairoDebug.OnDisposed<ScaledFont> (handle, disposing);
|
||||||
|
|
||||||
if (!disposing) {
|
if (!disposing|| handle == IntPtr.Zero)
|
||||||
Console.Error.WriteLine ("Cairo.ScaledFont: called from finalization thread, programmer is missing a call to Dispose");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
NativeMethods.cairo_scaled_font_destroy (handle);
|
NativeMethods.cairo_scaled_font_destroy (handle);
|
||||||
handle = IntPtr.Zero;
|
handle = IntPtr.Zero;
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace Cairo {
|
||||||
protected static Hashtable surfaces = new Hashtable ();
|
protected static Hashtable surfaces = new Hashtable ();
|
||||||
internal IntPtr surface = IntPtr.Zero;
|
internal IntPtr surface = IntPtr.Zero;
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
protected Surface()
|
protected Surface()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -55,6 +56,8 @@ namespace Cairo {
|
||||||
}
|
}
|
||||||
if (!owns)
|
if (!owns)
|
||||||
NativeMethods.cairo_surface_reference (ptr);
|
NativeMethods.cairo_surface_reference (ptr);
|
||||||
|
if (CairoDebug.Enabled)
|
||||||
|
CairoDebug.OnAllocated (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static internal Surface LookupExternalSurface (IntPtr p)
|
static internal Surface LookupExternalSurface (IntPtr p)
|
||||||
|
@ -147,12 +150,11 @@ namespace Cairo {
|
||||||
|
|
||||||
protected virtual void Dispose (bool disposing)
|
protected virtual void Dispose (bool disposing)
|
||||||
{
|
{
|
||||||
if (surface == IntPtr.Zero)
|
if (!disposing || CairoDebug.Enabled)
|
||||||
|
CairoDebug.OnDisposed<Surface> (surface, disposing);
|
||||||
|
|
||||||
|
if (!disposing|| surface == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
if (!disposing) {
|
|
||||||
Console.Error.WriteLine ("Cairo.Surface: called from finalization thread, programmer is missing a call to Dispose");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (surfaces.SyncRoot)
|
lock (surfaces.SyncRoot)
|
||||||
surfaces.Remove (surface);
|
surfaces.Remove (surface);
|
||||||
|
|
Loading…
Reference in a new issue