Sherwood Wang
Sherwood Wang

Reputation: 715

Store a pointer to lisp object in system area memory

I want to use Common Lisp to process something for a C program. But for some reasons I need use SBCL.

I wonder how to correctly store a pointer to lisp object in system area memory which is allocated by a C function. For example,

struct c_struct {
    ...
    lispobj *obj;
    ...
};

With sb-kernel:get-lisp-obj-address, I can get the pointer to a lisp object. But it makes no sence to store it in foreign memory. The main problem is that GC moves objects. sb-sys:with-pinned-object only pins objects during the extent of the body and it's obviously a bad idea to pin a object for a long time. So I need some methods to tell GC to update the pointer when the pointed object is moved.

Upvotes: 2

Views: 1226

Answers (1)

BRPocock
BRPocock

Reputation: 13914

While I don't believe (although I'm eager to be corrected) that SBCL allows one to "pin" the pointer-address of an object for a very long time, nor is the garbage collector easily extensible to updating “foreign copies” of pointers to objects, you can obtain a persistent pointer to a Lisp callback function; i.e. a pointer which a C program can funcall which is actually a Lisp function, using defcallback.

One (untested) theory might be to wrap your C language calls in such a way:

  • C function allocates c_struct with a NULL pointer slot
  • You provide a (defcallback …) function pointer to your C program; let's call it void with_locked_access ((void*) interior_function(struct c_struct *), struct c_struct *struct_to_use)
  • when C function(s) want to access this pointer, they call interior_function with their own function-pointer interior_function and the pointer to the c_struct that interests them
  • interior_function is actually (defcallback call-c-with-pinned-object…); it, in turn, calls sb-sys:with-pinned-object and obtains the system-area pointer for the object, and stores it into c_struct before calling interior_function with the (now-populated) structure as its parameter.
  • interior_function does whatever it is that it wants the pinned Lisp object for; it returns, and call-c-with-pinned-object closes out the with-pinned-object form and returns, itself.

Naturally, this depends entirely upon what it is you want to do in your C code, and whether it's going to be running in parallel with Lisp code that might be negatively impacted by the pinning, &c &c.

Alternatively, in the special (but common) case that the object in question happens to be a byte vector (e.g. perhaps a buffer of some kind), you might be able to take advantage of cffi-sys:make-shareable-byte-vector and cffi-sys:with-pointer-to-vector-data, q.v.

Upvotes: 1

Related Questions