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 {
|
||||
|
||||
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 Point (int x, int y)
|
||||
|
@ -204,12 +247,10 @@ namespace Cairo {
|
|||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (!disposing){
|
||||
Console.Error.WriteLine ("Cairo.Context: called from finalization thread, programmer is missing a call to Dispose");
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == IntPtr.Zero)
|
||||
if (!disposing || CairoDebug.Enabled)
|
||||
CairoDebug.OnDisposed<Context> (state, disposing);
|
||||
|
||||
if (!disposing|| state == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
//Console.WriteLine ("Destroying");
|
||||
|
|
|
@ -61,13 +61,11 @@ namespace Cairo
|
|||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (handle == IntPtr.Zero)
|
||||
return;
|
||||
if (!disposing || CairoDebug.Enabled)
|
||||
CairoDebug.OnDisposed<FontFace> (handle, disposing);
|
||||
|
||||
if (!disposing) {
|
||||
Console.Error.WriteLine ("Cairo.FontFace: called from finalization thread, programmer is missing a call to Dispose");
|
||||
if (!disposing|| handle == IntPtr.Zero)
|
||||
return;
|
||||
}
|
||||
|
||||
NativeMethods.cairo_font_face_destroy (handle);
|
||||
handle = IntPtr.Zero;
|
||||
|
@ -77,6 +75,8 @@ namespace Cairo
|
|||
public FontFace (IntPtr handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
if (CairoDebug.Enabled)
|
||||
CairoDebug.OnAllocated (handle);
|
||||
}
|
||||
|
||||
public IntPtr Handle {
|
||||
|
|
|
@ -47,6 +47,8 @@ namespace Cairo
|
|||
internal FontOptions (IntPtr handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
if (CairoDebug.Enabled)
|
||||
CairoDebug.OnAllocated (handle);
|
||||
}
|
||||
|
||||
public FontOptions Copy ()
|
||||
|
@ -68,13 +70,11 @@ namespace Cairo
|
|||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (handle == IntPtr.Zero)
|
||||
return;
|
||||
if (!disposing || CairoDebug.Enabled)
|
||||
CairoDebug.OnDisposed<FontOptions> (handle, disposing);
|
||||
|
||||
if (!disposing) {
|
||||
Console.Error.WriteLine ("Cairo.FontOptions: called from finalization thread, programmer is missing a call to Dispose");
|
||||
if (!disposing|| handle == IntPtr.Zero)
|
||||
return;
|
||||
}
|
||||
|
||||
NativeMethods.cairo_font_options_destroy (handle);
|
||||
handle = IntPtr.Zero;
|
||||
|
|
|
@ -41,6 +41,8 @@ namespace Cairo {
|
|||
internal Path (IntPtr handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
if (CairoDebug.Enabled)
|
||||
CairoDebug.OnAllocated (handle);
|
||||
}
|
||||
|
||||
~Path ()
|
||||
|
@ -57,12 +59,10 @@ namespace Cairo {
|
|||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (!disposing) {
|
||||
Console.Error.WriteLine ("Cairo.Path: called from finalization thread, programmer is missing a call to Dispose");
|
||||
return;
|
||||
}
|
||||
if (!disposing || CairoDebug.Enabled)
|
||||
CairoDebug.OnDisposed<Path> (handle, disposing);
|
||||
|
||||
if (handle == IntPtr.Zero)
|
||||
if (!disposing|| handle == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
NativeMethods.cairo_path_destroy (handle);
|
||||
|
|
|
@ -66,12 +66,15 @@ namespace Cairo {
|
|||
|
||||
static Hashtable patterns = new Hashtable ();
|
||||
|
||||
internal Pattern (IntPtr ptr)
|
||||
internal Pattern (IntPtr handle)
|
||||
{
|
||||
lock (patterns){
|
||||
patterns [ptr] = this;
|
||||
patterns [handle] = this;
|
||||
}
|
||||
pattern = ptr;
|
||||
|
||||
Handle = handle;
|
||||
if (CairoDebug.Enabled)
|
||||
CairoDebug.OnAllocated (handle);
|
||||
}
|
||||
|
||||
~Pattern ()
|
||||
|
@ -98,16 +101,14 @@ namespace Cairo {
|
|||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (!disposing) {
|
||||
Console.Error.WriteLine ("Cairo.Pattern: called from finalization thread, programmer is missing a call to Dispose");
|
||||
return;
|
||||
}
|
||||
if (!disposing || CairoDebug.Enabled)
|
||||
CairoDebug.OnDisposed<Pattern> (Handle, disposing);
|
||||
|
||||
if (pattern == IntPtr.Zero)
|
||||
if (!disposing|| Handle == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
NativeMethods.cairo_pattern_destroy (pattern);
|
||||
pattern = IntPtr.Zero;
|
||||
NativeMethods.cairo_pattern_destroy (Handle);
|
||||
Handle = IntPtr.Zero;
|
||||
lock (patterns){
|
||||
patterns.Remove (this);
|
||||
}
|
||||
|
@ -116,7 +117,7 @@ namespace Cairo {
|
|||
[Obsolete ("Use Dispose()")]
|
||||
public void Destroy ()
|
||||
{
|
||||
Dispose ();
|
||||
NativeMethods.cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
public Extend Extend {
|
||||
|
@ -143,6 +144,7 @@ namespace Cairo {
|
|||
|
||||
public IntPtr Handle {
|
||||
get { return pattern; }
|
||||
private set { pattern = value; }
|
||||
}
|
||||
|
||||
[Obsolete ("Replaced by Handle property")]
|
||||
|
|
|
@ -35,11 +35,13 @@ namespace Cairo {
|
|||
internal ScaledFont (IntPtr handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
if (CairoDebug.Enabled)
|
||||
CairoDebug.OnAllocated (handle);
|
||||
}
|
||||
|
||||
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 ()
|
||||
|
@ -99,13 +101,11 @@ namespace Cairo {
|
|||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (handle == IntPtr.Zero)
|
||||
return;
|
||||
if (!disposing || CairoDebug.Enabled)
|
||||
CairoDebug.OnDisposed<ScaledFont> (handle, disposing);
|
||||
|
||||
if (!disposing) {
|
||||
Console.Error.WriteLine ("Cairo.ScaledFont: called from finalization thread, programmer is missing a call to Dispose");
|
||||
if (!disposing|| handle == IntPtr.Zero)
|
||||
return;
|
||||
}
|
||||
|
||||
NativeMethods.cairo_scaled_font_destroy (handle);
|
||||
handle = IntPtr.Zero;
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace Cairo {
|
|||
protected static Hashtable surfaces = new Hashtable ();
|
||||
internal IntPtr surface = IntPtr.Zero;
|
||||
|
||||
[Obsolete]
|
||||
protected Surface()
|
||||
{
|
||||
}
|
||||
|
@ -55,6 +56,8 @@ namespace Cairo {
|
|||
}
|
||||
if (!owns)
|
||||
NativeMethods.cairo_surface_reference (ptr);
|
||||
if (CairoDebug.Enabled)
|
||||
CairoDebug.OnAllocated (ptr);
|
||||
}
|
||||
|
||||
static internal Surface LookupExternalSurface (IntPtr p)
|
||||
|
@ -147,13 +150,12 @@ namespace Cairo {
|
|||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (surface == IntPtr.Zero)
|
||||
return;
|
||||
if (!disposing) {
|
||||
Console.Error.WriteLine ("Cairo.Surface: called from finalization thread, programmer is missing a call to Dispose");
|
||||
return;
|
||||
}
|
||||
if (!disposing || CairoDebug.Enabled)
|
||||
CairoDebug.OnDisposed<Surface> (surface, disposing);
|
||||
|
||||
if (!disposing|| surface == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
lock (surfaces.SyncRoot)
|
||||
surfaces.Remove (surface);
|
||||
|
||||
|
|
Loading…
Reference in a new issue