This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Best way to do GC in Lisp/CFFI

4 posts · 3602 views

I have Lisp functions that wrap C wrappers for C++ functions that contain a new operator. The C wrappers have to stay the same I can't change those but I was advised to update my method of GC.

Here are the C wrappers:
Mat* cv_create_Mat() {
    return new Mat();
}
void cv_delete_Mat(void* ptr) {
    delete (~Mat*)ptr;
}
Here are the Lisp wrappers for them:
(defcfun ("cv_create_Mat" mat) (:pointer mat)
  "MAT constructor")


(defcfun ("cv_delete_Mat" del-mat) :void
  (ptr :pointer)) 
In a loop, as below, I would normally after calling a MAT function, delete it when I'm done with it manually with DEL-MAT, but I heard there was a better way by actually entering in the DEL-MAT function into Lisps natural GC methods so it would know when it comes across a function with a new it should call delete to get rid of it when it know i'm done with it.. The thing is I could use help to get started. Hopefully a concrete example of how to do this so I don't have to call DEL-MAT manually

(dotimes (n 1000)
(setf m (mat))
(del-mat m))

Re: Best way to do GC in Lisp/CFFI

Another way to do it (gc on the C++ side) is to link in the Bohem GC and stop worrying. http://www.hboehm.info/gc/

Cheers
--
MA
Marco Antoniotti

Re: Best way to do GC in Lisp/CFFI

You probably heard about "finalizers".
Here's a couple top links on the subject.

http://pinterface.livejournal.com/40614.html
https://github.com/Balooga/Simple-Finalizer

Finalizers involve some interesting tradeoffs.
C/C++ libraries are often written assuming strict, often lexically-scoped object lifecycles.
Finalizers hook into looser GC semantics.
The order of invocation is undefined for finalizers, and the GC may not even call them before program exit.
I'm undecided whether finalizers are a net win, but they definitely have some proponents.

Re: Best way to do GC in Lisp/CFFI

Thanks for your replies to my question, I was planning to go the trivial-garbage route and someone from CFFI-DEVEL kindly gave me this code to do GC automatically using my mat and del-mat functions
 (defstruct (cvmatrix (:constructor %make-cvmatrix))
  (sap (mat) :type sb-sys:system-area-pointer :read-only t))

 (defun make-cvmatrix ()
  (let* ((matrix (%make-cvmatrix))
          (sap (cvmatrix-sap matrix)))
    (tg:finalize matrix (lambda (x) (del-mat sap)))
    matrix))
When I run the make-cvmatrix function to create a matrix it outputs a struct instead of a pointer like i needed. I changed the last line of the make-cvmatrix function to be "sap" as below:
    (tg:finalize matrix (lambda (x) (del-mat sap)))
    sap))
...and it appears to run fine with only minor variations in my ram levels which i suppose is just a result of lisps GC in process.
Since I'm new to GC w/ trivial-garbage, I was hoping someone can verify first that the change to sap was an ok move.

I was hoping someone could edit my code so I have a good example of Lisp GC with TG to work from and if I write a defcfun for this C wrapper :
Mat* cv_create_Mat_typed(int rows, int cols, int type) {
    return new Mat(rows, cols, type);
}

eg:


(defcfun ("cv_create_Mat_typed" mat-typed)  (:pointer mat)
  "MAT constructor with a row, column and type parameter."
  (rows :int)
  (cols :int)
  (type :int))
show me where the rows cols type params get placed in an edited finalizer/constructor above..I would definately appreciate greatly:), concrete examples using the code I posted.