On Mon, 09 May 2011 16:46:20 +0200, nitralime said:
On 05/09/2011 01:49 PM, Martin Simmons wrote:
> On Sun, 08 May 2011 14:39:41 +0200, Nitralime said:
Using a finalizer seems to be a possible way to go. But I'm not sure how this can be done by just using the finalizer parameters "object" and "function" where "function" can't reliablely access "object" (cf. documentation of finalizer in "trivial-garbage" package)!!
Any help and feedback is very much appreciated!
IMHO, attempting to transparently wrap a foreign object with a CLOS object is not a good design.
Using a finalizer is dangerous because it is difficult to guarantee that the Lisp wrapper object is retained for the correct lifetime.
For example, consider
(defstruct table foreign-pointer)
(defun allocate-table () (make-table :foreign-pointer (foreign-allocate-table)))
(defun allocate-and-munge-table () (let ((table (allocate-table))) (foreign-munge-table (table-foreign-pointer table))))
The compiler might not keep the variable "table" alive during the call to the foreign function foreign-munge-table. As a result, the Lisp table object might be gc'ed in another thread while the foreign code is accessing it.
Consider the following sample (pseudo-)code:
(defclass table () ((table-pointer :initarg :handle :accessor handle-of)))
(defmethod initialize-instance :after ((self table) &key) (let ((table-pointer (handle-of self))) (tg:finalize self (lambda () (foreign-destroy-table table-pointer)))))
(defmethod get-row ((t table) index) (transform-to-lisp-vector (foreign-get-row (hadle-of t) index)))
(defmethod move-to ((t table) index) (foreign-move-to (handle-of t) index)) .....
Now consider a function which creates a table instance and puts it into a result plist (and has probabely some side effects):
(defun call-a-foreign-function (.....) (let (....) .... <call a foreign function which allocates a table object and returns a-foreign-table-pointer> .... (let ((result-table (make-instance 'table :handle a-foreign-table-pointer)) (...)) ... ... '(:id ... :tab result-table :msg ... ...))))
The question is now what will happen if you do just
(call-a-foreign-function ...)
or something like this
(getf (call-a-foreign-function ...) :id)
I assume that the unreachable object 'result-table' will be garbage collected, and the finalization will free the corresponding C table object!
Do you see any misconception (resp. potential danger) here?
Your examples will be safe, but
(get-row (getf (call-a-foreign-function ...) :tab) 0)
might crash.