[vlc-devel] commit: Simpler and safer event callbacks handling ( Rémi Denis-Courmont )

git version control git at videolan.org
Mon Feb 23 20:13:39 CET 2009


vlc | branch: master | Rémi Denis-Courmont <rdenis at simphalempin.com> | Mon Feb 23 20:00:52 2009 +0200| [d14f8d432c2dfaea7365e728a61ec37c3cdcf837] | committer: Rémi Denis-Courmont 

Simpler and safer event callbacks handling

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=d14f8d432c2dfaea7365e728a61ec37c3cdcf837
---

 bindings/cil/src/marshal.cs |   50 ++++++++++++-------------------------------
 1 files changed, 14 insertions(+), 36 deletions(-)

diff --git a/bindings/cil/src/marshal.cs b/bindings/cil/src/marshal.cs
index 166b90d..3a427f8 100644
--- a/bindings/cil/src/marshal.cs
+++ b/bindings/cil/src/marshal.cs
@@ -139,30 +139,12 @@ namespace VideoLAN.LibVLC
      */
     public abstract class EventingObject : BaseObject
     {
-        /**
-         * @brief Managed to unmanaged event handler mapping
-         * @ingroup Internals
-         *
-         * The CLR cannot do reference counting for unmanaged callbacks.
-         * We keep track of handled events here instead.
-         */
-        private class Event
-        {
-            public EventCallback managed;
-            public IntPtr        unmanaged;
-
-            public Event (EventCallback managed, IntPtr unmanaged)
-            {
-                this.managed = managed;
-                this.unmanaged = unmanaged;
-            }
-        };
-        private Dictionary<EventType, Event> events;
+        private Dictionary<Delegate, IntPtr> events;
         /**< references to our unmanaged function pointers */
 
         internal EventingObject () : base ()
         {
-            events = new Dictionary<EventType, Event> ();
+            events = new Dictionary<Delegate, IntPtr> ();
         }
 
         /**
@@ -187,19 +169,20 @@ namespace VideoLAN.LibVLC
          * @param callback callback to invoke when the event occurs
          *
          * @note
-         * For simplicity, we only allow one handler per type.
-         * Multicasting can be implemented higher up with managed code.
+         * For simplicity, we require distinct callbacks for each event type.
+         * This is hardly an issue since most events have different formats.
          */
-        internal void Attach (EventType type, EventCallback callback)
+        internal void Attach (EventType type, Delegate callback)
         {
             EventManagerHandle manager;
             IntPtr cb = Marshal.GetFunctionPointerForDelegate (callback);
-            Event ev = new Event (callback, cb);
             bool unref = false;
 
-            if (events.ContainsKey (type))
-                throw new ArgumentException ("Duplicate event");
-
+            /* If things go wrong, we will leak the callback thunk... until
+             * this object is destroyed anyway. If we added the thunk _after_
+             * the critical section, the native code could try to jump to a
+             * non-existent address, which is much worse. */
+            events.Add (callback, cb);
             try
             {
                 handle.DangerousAddRef (ref unref);
@@ -212,19 +195,19 @@ namespace VideoLAN.LibVLC
                     handle.DangerousRelease ();
             }
             Raise ();
-            events.Add (type, ev);
         }
 
-        private void Detach (EventType type, IntPtr callback)
+        internal void Detach (EventType type, Delegate callback)
         {
             EventManagerHandle manager;
+            IntPtr cb = events[callback];
             bool unref = false;
 
             try
             {
                 handle.DangerousAddRef (ref unref);
                 manager = GetManager ();
-                LibVLC.EventDetach (manager, type, callback, IntPtr.Zero, ex);
+                LibVLC.EventDetach (manager, type, cb, IntPtr.Zero, ex);
             }
             finally
             {
@@ -232,12 +215,7 @@ namespace VideoLAN.LibVLC
                     handle.DangerousRelease ();
             }
             Raise ();
-            events.Remove (type);
-        }
-
-        internal void Detach (EventType type)
-        {
-            Detach(type, events[type].unmanaged);
+            events.Remove (callback);
         }
     };
 };




More information about the vlc-devel mailing list