Garbage Collector and Delegate

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Daniel Brown

    Garbage Collector and Delegate

    I am registering a managed delegate to an unmanaged DLL for asynchronous
    callback. I understand the garbage collector will free the managed resource
    if they go out of scope but with the information I have read, it is unclear
    to me if the garbage collector will move the delegate (e.g.
    cableInterruptC allbackEventHan dler) if it is still referenced thereby
    invalidating the callback performed by the unmanaged code. I would greatly
    appreciate some information regarding this topic. I have included some code
    that will illustrate what I am doing. In my actual code I am implementing
    the Dispose Pattern. Sorry, it is a bit lengthy.

    [btapi.h] (partial)
    #ifdef __cplusplus
    #define BT_EXTERN extern "C"
    #else
    #define BT_EXTERN extern
    #endif

    #if !defined(BT973) && !defined(WINVER ) && !defined(BT1590 1) \
    && !defined(BT1599 1) && !defined(BT1790 3) && !defined(BT1390 8)
    #define BT_METHOD
    #else
    /* Windows requires __stdcall between the return type and the function
    name- so we can't just hide it in BT_EXTERN. */
    #define BT_METHOD __stdcall
    #endif

    BT_EXTERN bt_error_t
    BT_METHOD bt_icbr_install (
    bt_desc_t btd_p,
    bt_irq_t irq_type,
    bt_icbr_t *icbr_p,
    void *param_p,
    bt_data32_t vector);

    BT_EXTERN bt_error_t
    BT_METHOD bt_icbr_remove(
    bt_desc_t btd_p,
    bt_irq_t irq_type,
    bt_icbr_t *icbr_p);


    [C#]
    using System;
    using System.Runtime. InteropServices ;

    namespace SbsTechnologies .BusAdapter
    {
    public enum ErrorStatus : int
    {
    Success,
    IOError,
    DeviceDoesNotEx ist,
    OutOfMemory,
    }

    public enum InterruptType : int
    {
    Overflow,
    Error,
    Programmed,
    Cable,
    }

    public enum InterruptCallba ckType : int
    {
    Error = InterruptType.E rror,
    Programmed = InterruptType.P rogrammed,
    Cable = InterruptType.C able,
    }

    public class MirrorApiEventA rgs : EventArgs
    {
    private InterruptType interruptType;
    private uint vector;

    public MirrorApiEventA rgs(InterruptTy pe interruptType, uint vector) : base()
    {
    this.interruptT ype = interruptType;
    this.vector = vector;
    }

    public InterruptType InterruptType
    {
    get
    {
    return this.interruptT ype;
    }
    }

    public uint Vector
    {
    get
    {
    return this.vector;
    }
    }
    }

    internal delegate void InterruptCallba ckEventHandler( IntPtr parameter,
    InterruptType interruptType, uint vector);

    public delegate void MirrorApiEventH andler(object sender,
    MirrorApiEventA rgs e);

    internal sealed class MirrorApiIntero p
    {
    private sealed class UnsafeNativeMet hods
    {

    [DllImport(@"bit 3_984.dll", EntryPoint = "bt_icbr_instal l")]
    public static extern ErrorStatus bt_icbr_install (
    IntPtr btd_p,
    InterruptCallba ckType irq_type,
    InterruptCallba ckEventHandler icbr_p,
    IntPtr param_p,
    uint vector
    );

    [DllImport(@"bit 3_984.dll", EntryPoint = "bt_icbr_remove ")]
    public static extern ErrorStatus bt_icbr_remove(
    IntPtr btd_p,
    InterruptCallba ckType irq_type,
    InterruptCallba ckEventHandler icbr_p
    );
    }

    internal static void InstallInterrup tCallbackRoutin e(IntPtr handle,
    InterruptCallba ckType interruptCallba ckType, InterruptCallba ckEventHandler
    interruptCallba ckEventHandler, IntPtr param, uint vector)
    {
    UnsafeNativeMet hods.bt_icbr_in stall(handle, interruptCallba ckType,
    interruptCallba ckEventHandler, param, vector);
    }

    internal static void RemoveInterrupt CallbackRoutine (IntPtr handle,
    InterruptCallba ckType interruptCallba ckType, InterruptCallba ckEventHandler
    interruptCallba ckEventHandler)
    {
    UnsafeNativeMet hods.bt_icbr_re move(handle, interruptCallba ckType,
    interruptCallba ckEventHandler) ;
    }
    }

    public class MirrorApiInterr upt
    {
    private IntPtr handle;
    private uint vector;

    private InterruptCallba ckEventHandler cableInterruptC allbackEventHan dler;
    private InterruptCallba ckEventHandler errorInterruptC allbackEventHan dler;
    private InterruptCallba ckEventHandler
    programmedInter ruptCallbackEve ntHandler;

    public event MirrorApiEventH andler Cable;
    public event MirrorApiEventH andler Error;
    public event MirrorApiEventH andler Programmed;

    public MirrorApiInterr upt(IntPtr handle, uint vector)
    {
    this.handle = handle;
    this.vector = vector;

    cableInterruptC allbackEventHan dler = new
    InterruptCallba ckEventHandler( this.CableInter ruptCallback);
    errorInterruptC allbackEventHan dler = new
    InterruptCallba ckEventHandler( this.ErrorInter ruptCallback);
    programmedInter ruptCallbackEve ntHandler = new
    InterruptCallba ckEventHandler( this.Programmed InterruptCallba ck);

    MirrorApiIntero p.InstallInterr uptCallbackRout ine(this.handle ,
    InterruptCallba ckType.Cable, cableInterruptC allbackEventHan dler, IntPtr.Zero,
    this.vector);
    MirrorApiIntero p.InstallInterr uptCallbackRout ine(this.handle ,
    InterruptCallba ckType.Error, errorInterruptC allbackEventHan dler, IntPtr.Zero,
    this.vector);
    MirrorApiIntero p.InstallInterr uptCallbackRout ine(this.handle ,
    InterruptCallba ckType.Programm ed, programmedInter ruptCallbackEve ntHandler,
    IntPtr.Zero, this.vector);
    }

    ~MirrorApiInter rupt()
    {
    MirrorApiIntero p.RemoveInterru ptCallbackRouti ne(this.handle,
    InterruptCallba ckType.Cable, cableInterruptC allbackEventHan dler);
    }

    private void CableInterruptC allback(IntPtr parameter, InterruptType
    interruptType, uint vector)
    {
    this.OnCable(ne w MirrorApiEventA rgs(interruptTy pe, vector));
    }

    private void ErrorInterruptC allback(IntPtr parameter, InterruptType
    interruptType, uint vector)
    {
    this.OnError(ne w MirrorApiEventA rgs(interruptTy pe, vector));
    }

    private void ProgrammedInter ruptCallback(In tPtr parameter, InterruptType
    interruptType, uint vector)
    {
    this.OnProgramm ed(new MirrorApiEventA rgs(interruptTy pe, vector));
    }

    protected virtual void OnCable(MirrorA piEventArgs e)
    {
    if (this.Cable != null)
    {
    this.Cable(this , e);
    }
    }

    protected virtual void OnError(MirrorA piEventArgs e)
    {
    if (this.Error != null)
    {
    this.Error(this , e);
    }
    }

    protected virtual void OnProgrammed(Mi rrorApiEventArg s e)
    {
    if (this.Programme d != null)
    {
    this.Programmed (this, e);
    }
    }
    }
    }

  • Mattias Sjögren

    #2
    Re: Garbage Collector and Delegate

    Daniel,
    [color=blue]
    >I understand the garbage collector will free the managed resource
    >if they go out of scope but with the information I have read, it is unclear
    >to me if the garbage collector will move the delegate (e.g.
    >cableInterrupt CallbackEventHa ndler) if it is still referenced thereby
    >invalidating the callback performed by the unmanaged code. I would greatly
    >appreciate some information regarding this topic.[/color]

    The delegate may move, but the native function pointer that gets
    passed to the function you're calling will remain valid as long as the
    delegate is referenced.

    [color=blue]
    >In my actual code I am implementing the Dispose Pattern.[/color]

    Great, because when your ~MirrorApiInter rupt finalizer runs the
    delegate may already have been garbage collected, so you can't safely
    call RemoveInterrupt CallbackRoutine from there.



    Mattias

    --
    Mattias Sjögren [MVP] mattias @ mvps.org
    http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
    Please reply only to the newsgroup.

    Comment

    • Daniel Brown

      #3
      Re: Garbage Collector and Delegate

      Thanks for the help. Your time is appreciated.

      "Mattias Sjögren" wrote:
      [color=blue]
      > Daniel,
      >[color=green]
      > >I understand the garbage collector will free the managed resource
      > >if they go out of scope but with the information I have read, it is unclear
      > >to me if the garbage collector will move the delegate (e.g.
      > >cableInterrupt CallbackEventHa ndler) if it is still referenced thereby
      > >invalidating the callback performed by the unmanaged code. I would greatly
      > >appreciate some information regarding this topic.[/color]
      >
      > The delegate may move, but the native function pointer that gets
      > passed to the function you're calling will remain valid as long as the
      > delegate is referenced.
      >
      >[color=green]
      > >In my actual code I am implementing the Dispose Pattern.[/color]
      >
      > Great, because when your ~MirrorApiInter rupt finalizer runs the
      > delegate may already have been garbage collected, so you can't safely
      > call RemoveInterrupt CallbackRoutine from there.
      >
      >
      >
      > Mattias
      >
      > --
      > Mattias Sjögren [MVP] mattias @ mvps.org
      > http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
      > Please reply only to the newsgroup.
      >[/color]

      Comment

      Working...