www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Temporarily protect array from garbage collection

reply "Lars T. Kyllingstad" <public kyllingen.net> writes:
Is it possible to temporarily prevent the garbage collector from 
collecting a memory block even if there are no references to it?

The use case is as follows:  I want to call a C library function 
which expects to take ownership of a buffer.  It looks something 
like this:

     alias FreeFunc = extern(C) void function(void*, void*) 
nothrow;

     extern(C) void foo(void* buf, size_t len,
                        FreeFunc free, void* ctx) nothrow;

Here, 'buf' is a pointer to the buffer, 'len' is the length of 
the buffer, 'free' is a function to deallocate the buffer when 
the library is done with it, and 'ctx' is a user-supplied context 
pointer.  Upon deallocation, 'free' receives two parameters; the 
pointer to the buffer and the context pointer.  The latter can be 
anything, even null, as it is just passed to 'free' and not used 
for anything else.

Here is the problem:  I want to be able to use a 
garbage-collected dynamic array with this function, but I don't 
want to have to retain a reference to it in my program.  (I don't 
know when the C library will call the free function.)  In other 
words, I want something like this:

     extern(C) void myFree(void* ptr, void* ctx)
     {
         enableGCFor(ptr);
     }

     auto arr = new int[123];
     disableGCFor(arr);
     foo(arr.ptr, arr.length, &myFree, null);
     arr = null;

Is this at all possible?

Thanks,
Lars
Apr 24 2014
parent reply Justin Whear <justin economicmodeling.com> writes:
On Thu, 24 Apr 2014 19:55:37 +0000, Lars T. Kyllingstad wrote:

 Is it possible to temporarily prevent the garbage collector from
 collecting a memory block even if there are no references to it?
 
 The use case is as follows:  I want to call a C library function which
 expects to take ownership of a buffer.  It looks something like this:
 
      alias FreeFunc = extern(C) void function(void*, void*)
 nothrow;
 
      extern(C) void foo(void* buf, size_t len,
                         FreeFunc free, void* ctx) nothrow;
 
 Here, 'buf' is a pointer to the buffer, 'len' is the length of the
 buffer, 'free' is a function to deallocate the buffer when the library
 is done with it, and 'ctx' is a user-supplied context pointer.  Upon
 deallocation, 'free' receives two parameters; the pointer to the buffer
 and the context pointer.  The latter can be anything, even null, as it
 is just passed to 'free' and not used for anything else.
 
 Here is the problem:  I want to be able to use a garbage-collected
 dynamic array with this function, but I don't want to have to retain a
 reference to it in my program.  (I don't know when the C library will
 call the free function.)  In other words, I want something like this:
 
      extern(C) void myFree(void* ptr, void* ctx)
      {
          enableGCFor(ptr);
      }
 
      auto arr = new int[123];
      disableGCFor(arr);
      foo(arr.ptr, arr.length, &myFree, null);
      arr = null;
 
 Is this at all possible?
 
 Thanks,
 Lars
You can use GC.addRoot() from core.memory before passing the pointer to the C function, then use GC.removeRoot in your myFree function.
Apr 24 2014
parent "Lars T. Kyllingstad" <public kyllingen.net> writes:
On Thursday, 24 April 2014 at 20:09:38 UTC, Justin Whear wrote:
 You can use GC.addRoot() from core.memory before passing the 
 pointer to
 the C function, then use GC.removeRoot in your myFree function.
Perfect, thanks!
Apr 24 2014