2007-11-16 Mike Kestner <mkestner@novell.com>

* glib/Object.cs: use toggle refs for all objects.
	de-obsolete Data hash.  Add internal Signals hash.
	* glib/Signal.cs: switch to weak gchandles.
	* glib/WeakObject.cs: kill.

svn path=/trunk/gtk-sharp/; revision=89776
This commit is contained in:
Mike Kestner 2007-11-16 18:35:38 +00:00
parent 9897c07f21
commit 70018d857d
5 changed files with 81 additions and 190 deletions

View File

@ -1,3 +1,10 @@
2007-11-16 Mike Kestner <mkestner@novell.com>
* glib/Object.cs: use toggle refs for all objects.
de-obsolete Data hash. Add internal Signals hash.
* glib/Signal.cs: switch to weak gchandles.
* glib/WeakObject.cs: kill.
2007-11-16 Eskil Bylund <eskil@letterboxes.org> 2007-11-16 Eskil Bylund <eskil@letterboxes.org>
* gtk/ListStore.custom: * gtk/ListStore.custom:

View File

@ -67,8 +67,7 @@ sources = \
TypeInitializerAttribute.cs \ TypeInitializerAttribute.cs \
UnwrappedObject.cs \ UnwrappedObject.cs \
ValueArray.cs \ ValueArray.cs \
Value.cs \ Value.cs
WeakObject.cs
build_sources = $(addprefix $(srcdir)/, $(sources)) AssemblyInfo.cs build_sources = $(addprefix $(srcdir)/, $(sources)) AssemblyInfo.cs
dist_sources = $(sources) dist_sources = $(sources)

View File

@ -31,7 +31,7 @@ namespace GLib {
public class Object : IWrapper, IDisposable { public class Object : IWrapper, IDisposable {
IntPtr _obj; IntPtr handle;
bool disposed = false; bool disposed = false;
Hashtable data; Hashtable data;
static Hashtable Objects = new Hashtable(); static Hashtable Objects = new Hashtable();
@ -40,13 +40,15 @@ namespace GLib {
~Object () ~Object ()
{ {
lock (PendingDestroys){ lock (PendingDestroys) {
PendingDestroys.Add (this); lock (Objects) {
lock (typeof (Object)){ if (Objects[Handle] is ToggleRef)
if (!idle_queued){ PendingDestroys.Add (Objects [Handle]);
Timeout.Add (50, new TimeoutHandler (PerformQueuedUnrefs)); Objects.Remove (Handle);
idle_queued = true; }
} if (!idle_queued){
Timeout.Add (50, new TimeoutHandler (PerformQueuedUnrefs));
idle_queued = true;
} }
} }
} }
@ -56,22 +58,18 @@ namespace GLib {
static bool PerformQueuedUnrefs () static bool PerformQueuedUnrefs ()
{ {
Object [] objects; object [] references;
lock (PendingDestroys){ lock (PendingDestroys){
objects = new Object [PendingDestroys.Count]; references = new object [PendingDestroys.Count];
PendingDestroys.CopyTo (objects, 0); PendingDestroys.CopyTo (references, 0);
PendingDestroys.Clear (); PendingDestroys.Clear ();
}
lock (typeof (Object))
idle_queued = false; idle_queued = false;
foreach (Object o in objects){
if (o._obj == IntPtr.Zero)
continue;
o.Dispose ();
} }
foreach (ToggleRef r in references)
r.Free ();
return false; return false;
} }
@ -82,17 +80,15 @@ namespace GLib {
disposed = true; disposed = true;
try { try {
ToggleRef toggle_ref = Objects [_obj] as ToggleRef; ToggleRef toggle_ref = Objects [Handle] as ToggleRef;
if (toggle_ref == null) if (toggle_ref != null)
g_object_unref (_obj);
else
toggle_ref.Free (); toggle_ref.Free ();
} catch (Exception e) { } catch (Exception e) {
Console.WriteLine ("Exception while disposing a " + this + " in Gtk#"); Console.WriteLine ("Exception while disposing a " + this + " in Gtk#");
throw e; throw e;
} }
Objects.Remove (_obj); Objects.Remove (Handle);
_obj = IntPtr.Zero; handle = IntPtr.Zero;
GC.SuppressFinalize (this); GC.SuppressFinalize (this);
} }
@ -105,34 +101,28 @@ namespace GLib {
return null; return null;
Object obj = null; Object obj = null;
object reference = Objects[o];
if (reference is WeakReference) { if (Objects.Contains (o)) {
WeakReference weak_ref = reference as WeakReference; ToggleRef toggle_ref = Objects [o] as ToggleRef;
if (weak_ref.IsAlive) if (toggle_ref != null && toggle_ref.IsAlive)
obj = weak_ref.Target as Object;
} else if (reference is ToggleRef) {
ToggleRef toggle_ref = reference as ToggleRef;
if (toggle_ref.IsAlive)
obj = toggle_ref.Target; obj = toggle_ref.Target;
} }
if (obj != null && obj._obj == o) { if (obj != null && obj.Handle == o) {
lock (PendingDestroys)
PendingDestroys.Remove (obj);
if (owned_ref) if (owned_ref)
g_object_unref (obj._obj); g_object_unref (obj.Handle);
obj.disposed = false;
return obj; return obj;
} }
obj = GLib.ObjectManager.CreateObject(o);
if (obj == null)
return null;
if (!owned_ref) if (!owned_ref)
g_object_ref (obj.Handle); g_object_ref (obj.Handle);
Objects [o] = new WeakReference (obj);
obj = GLib.ObjectManager.CreateObject(o);
if (obj == null) {
g_object_unref (o);
return null;
}
return obj; return obj;
} }
@ -292,22 +282,27 @@ namespace GLib {
for (int i = 0; i < names.Length; i++) for (int i = 0; i < names.Length; i++)
native_names [i] = GLib.Marshaller.StringToPtrGStrdup (names [i]); native_names [i] = GLib.Marshaller.StringToPtrGStrdup (names [i]);
Raw = gtksharp_object_newv (LookupGType ().Val, names.Length, native_names, vals); Raw = gtksharp_object_newv (LookupGType ().Val, names.Length, native_names, vals);
Objects [_obj] = new ToggleRef (this);
foreach (IntPtr p in native_names) foreach (IntPtr p in native_names)
GLib.Marshaller.Free (p); GLib.Marshaller.Free (p);
} }
protected virtual IntPtr Raw { protected virtual IntPtr Raw {
get { get {
return _obj; return handle;
} }
set { set {
if (_obj != IntPtr.Zero) if (handle == value)
Objects.Remove (_obj);
_obj = value;
if (value == IntPtr.Zero)
return; return;
Objects [value] = new WeakReference (this);
if (handle != IntPtr.Zero) {
ToggleRef tref = Objects [handle] as ToggleRef;
if (tref != null)
tref.Free ();
Objects.Remove (handle);
}
handle = value;
if (value != IntPtr.Zero)
Objects [value] = new ToggleRef (this);
} }
} }
@ -334,7 +329,16 @@ namespace GLib {
public IntPtr Handle { public IntPtr Handle {
get { get {
return _obj; return handle;
}
}
Hashtable signals;
internal Hashtable Signals {
get {
if (signals == null)
signals = new Hashtable ();
return signals;
} }
} }
@ -436,7 +440,6 @@ namespace GLib {
return Handle.GetHashCode (); return Handle.GetHashCode ();
} }
[Obsolete("Can cause instability due to garbage collection of GLib.Objects.")]
public Hashtable Data { public Hashtable Data {
get { get {
if (data == null) if (data == null)
@ -446,9 +449,13 @@ namespace GLib {
} }
} }
Hashtable persistent_data;
protected Hashtable PersistentData { protected Hashtable PersistentData {
get { get {
return WeakObject.Lookup (Handle).Data; if (persistent_data == null)
persistent_data = new Hashtable ();
return persistent_data;
} }
} }

View File

@ -45,7 +45,7 @@ namespace GLib {
public class Signal { public class Signal {
GCHandle gc_handle; GCHandle gc_handle;
IntPtr handle; Object obj;
string name; string name;
uint before_id = UInt32.MaxValue; uint before_id = UInt32.MaxValue;
uint after_id = UInt32.MaxValue; uint after_id = UInt32.MaxValue;
@ -53,14 +53,11 @@ namespace GLib {
private Signal (GLib.Object obj, string signal_name, Delegate marshaler) private Signal (GLib.Object obj, string signal_name, Delegate marshaler)
{ {
handle = obj.Handle; this.obj = obj;
name = signal_name; name = signal_name;
this.marshaler = marshaler; this.marshaler = marshaler;
gc_handle = GCHandle.Alloc (this); gc_handle = GCHandle.Alloc (this, GCHandleType.Weak);
IntPtr native_key = GLib.Marshaller.StringToPtrGStrdup (name + "_signal_marshaler"); obj.Signals [name] = this;
if (handle != IntPtr.Zero)
g_object_set_data_full (handle, native_key, (IntPtr) gc_handle, DestroyHelper.NotifyHandler);
GLib.Marshaller.Free (native_key);
} }
public static Signal Lookup (GLib.Object obj, string name) public static Signal Lookup (GLib.Object obj, string name)
@ -70,18 +67,10 @@ namespace GLib {
public static Signal Lookup (GLib.Object obj, string name, Delegate marshaler) public static Signal Lookup (GLib.Object obj, string name, Delegate marshaler)
{ {
IntPtr native_key = GLib.Marshaller.StringToPtrGStrdup (name + "_signal_marshaler"); Signal result = obj.Signals [name] as Signal;
IntPtr data; if (result == null)
if (obj.Handle == IntPtr.Zero) result = new Signal (obj, name, marshaler);
data = IntPtr.Zero; return result as Signal;
else
data = g_object_get_data (obj.Handle, native_key);
GLib.Marshaller.Free (native_key);
if (data == IntPtr.Zero)
return new Signal (obj, name, marshaler);
GCHandle gch = (GCHandle) data;
return gch.Target as Signal;
} }
Delegate before_handler; Delegate before_handler;
@ -89,7 +78,7 @@ namespace GLib {
public Delegate Handler { public Delegate Handler {
get { get {
InvocationHint hint = (InvocationHint) Marshal.PtrToStructure (g_signal_get_invocation_hint (handle), typeof (InvocationHint)); InvocationHint hint = (InvocationHint) Marshal.PtrToStructure (g_signal_get_invocation_hint (obj.Handle), typeof (InvocationHint));
if (hint.run_type == SignalFlags.RunFirst) if (hint.run_type == SignalFlags.RunFirst)
return before_handler; return before_handler;
else else
@ -100,7 +89,7 @@ namespace GLib {
uint Connect (int flags) uint Connect (int flags)
{ {
IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name); IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name);
uint id = g_signal_connect_data (handle, native_name, marshaler, (IntPtr) gc_handle, IntPtr.Zero, flags); uint id = g_signal_connect_data (obj.Handle, native_name, marshaler, (IntPtr) gc_handle, IntPtr.Zero, flags);
GLib.Marshaller.Free (native_name); GLib.Marshaller.Free (native_name);
return id; return id;
} }
@ -139,21 +128,13 @@ namespace GLib {
} }
if (after_id == UInt32.MaxValue && before_id == UInt32.MaxValue) if (after_id == UInt32.MaxValue && before_id == UInt32.MaxValue)
DisconnectObject (); obj.Signals.Remove (name);
}
void DisconnectObject ()
{
IntPtr native_key = GLib.Marshaller.StringToPtrGStrdup (name + "_signal_marshaler");
if (handle != IntPtr.Zero)
g_object_set_data (handle, native_key, IntPtr.Zero);
GLib.Marshaller.Free (native_key);
} }
void DisconnectHandler (uint handler_id) void DisconnectHandler (uint handler_id)
{ {
if (handler_id != UInt32.MaxValue && g_signal_handler_is_connected (handle, handler_id)) if (handler_id != UInt32.MaxValue && g_signal_handler_is_connected (obj.Handle, handler_id))
g_signal_handler_disconnect (handle, handler_id); g_signal_handler_disconnect (obj.Handle, handler_id);
} }
[CDeclCallback] [CDeclCallback]
@ -186,15 +167,6 @@ namespace GLib {
} }
} }
[DllImport("libgobject-2.0-0.dll")]
static extern IntPtr g_object_get_data (IntPtr instance, IntPtr key);
[DllImport("libgobject-2.0-0.dll")]
static extern void g_object_set_data (IntPtr instance, IntPtr key, IntPtr data);
[DllImport("libgobject-2.0-0.dll")]
static extern void g_object_set_data_full (IntPtr instance, IntPtr key, IntPtr data, DestroyNotify notify);
[DllImport("libgobject-2.0-0.dll")] [DllImport("libgobject-2.0-0.dll")]
static extern uint g_signal_connect_data(IntPtr obj, IntPtr name, Delegate cb, IntPtr gc_handle, IntPtr dummy, int flags); static extern uint g_signal_connect_data(IntPtr obj, IntPtr name, Delegate cb, IntPtr gc_handle, IntPtr dummy, int flags);

View File

@ -1,94 +0,0 @@
// WeakObject.cs - Object to hold managed references via native weakref.
//
// Authors: Mike Kestner <mkestner@novell.com>
//
// Copyright (c) 2005 Novell, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the Lesser GNU General
// Public License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
namespace GLib {
using System;
using System.Collections;
using System.Runtime.InteropServices;
internal class WeakObject {
GCHandle gc_handle;
static DestroyNotify notify = new DestroyNotify (OnNativeDestroy);
[CDeclCallback]
delegate void DestroyNotify (IntPtr data);
static void OnNativeDestroy (IntPtr data)
{
try {
GCHandle gch = (GCHandle) data;
WeakObject obj = gch.Target as WeakObject;
obj.Dispose ();
gch.Free ();
} catch (Exception e) {
ExceptionManager.RaiseUnhandledException (e, false);
}
}
void Dispose ()
{
signals = null;
data = null;
}
WeakObject (IntPtr obj)
{
gc_handle = GCHandle.Alloc (this);
g_object_set_data_full (obj, "gtk_sharp_weak_object", (IntPtr) gc_handle, notify);
}
Hashtable data;
public Hashtable Data {
get {
if (data == null)
data = new Hashtable ();
return data;
}
}
Hashtable signals;
public Hashtable Signals {
get {
if (signals == null)
signals = new Hashtable ();
return signals;
}
}
public static WeakObject Lookup (IntPtr obj)
{
IntPtr data = g_object_get_data (obj, "gtk_sharp_weak_object");
if (data == IntPtr.Zero)
return new WeakObject (obj);
GCHandle gch = (GCHandle) data;
return gch.Target as WeakObject;
}
[DllImport("libgobject-2.0-0.dll")]
static extern IntPtr g_object_get_data (IntPtr instance, string key);
[DllImport("libgobject-2.0-0.dll")]
static extern void g_object_set_data_full (IntPtr instance, string key, IntPtr data, DestroyNotify notify);
}
}