I've experimented in the past with making a macro that would generate the appropriate ffi code to create and manage c structs/unions/types. The challenge was to handle references obtained from accessors to fields containing other structs/union/types within them in such a way that - no copying was necessary, and - the original structure wouldn't be released as long as derived references existed.
For example, to handle events in SDL you create a SDL_Event union that you pass to functions to query for events. When the data for a particular event is populated, you query the type with evt.type and then access the fields of the specific type by accessing evt.key, a "view" on the same structure of type SDL_KeyboardEvent. There is no point in copying the structure when you do this. Also, you don't want the SDL_Event to be released while you're using (holding a reference to) the SDL_KeyboardEvent. While in this case it's not hard to manually keep the parent object alive, in the general case it feels more schemey to let the garbage collector take care of that.
What I came up with at that time was not legible and I'm not proud of it. While it seemed to work in my x64 machine, I got a segmentation fault when running the tests in a x86 installation:
https://github.com/euccastro/gambit-SDL2/blob/master/ffi-macro.scm (find struct-or-union-type)
Usage examples: https://github.com/euccastro/gambit-SDL2/blob/master/test-ffi.scm https://github.com/euccastro/gambit-SDL2/blob/master/sdl.scm (see SDL_Event. |voidstar| is how we tell the macro that we want it to manage this as described above)
The most straightforward way to do it would be to create, in addition to the macro, a library that maintains a table of weak keys --referring to derived ("child") structs-- to strong values --referring to the original ("parent") structs. In the module above I did just that, but I resorted to dubious tricks to avoid creating that library. In a new shot at this I'd just have the library.
I'm also factoring that more nicely so the parts are easier to read and test separately.
Another plausible approach would be to allocate a zero-size reference-counted object (with ___alloc_rc(0)), have its data point to the parent, and make a will with the child's foreign object as testator and with an action that kills the reference-counted object. I have tested that wills still execute after they themselves become unreachable, but I don't know whether that's behavior I should rely on. If that is not the case, then the reference-counted object's data could be a (cons parent-foreign will), so the will itself will be kept alive until it's executed.
While I had lots of fun looking at the sources and coming up with this, I suspect the more straightforward table approach involves less overhead.
If anyone else is interested in doing and/or using something like this, I'm happy to bounce ideas and take suggestions. I'm working on this mostly on weekends, but I'll try and be responsive during the week too.
Thanks for reading and have some happy scheming!
Afficher les réponses par date
On Sun, Dec 22, 2013 at 05:00:48PM +0100, Estevo wrote:
I've experimented in the past with making a macro that would generate the appropriate ffi code to create and manage c structs/unions/types. The challenge was to handle references obtained from accessors to fields containing other structs/union/types within them in such a way that
- no copying was necessary, and
- the original structure wouldn't be released as long as derived references
existed
Anyone know what guile does? If anything?
-- hendrik
I've experimented in the past with making a macro that would generate the appropriate ffi code to create and manage c structs/unions/types. The challenge was to handle references obtained from accessors to fields containing other structs/union/types within them in such a way that
- no copying was necessary, and
- the original structure wouldn't be released as long as derived
references
existed
Anyone know what guile does? If anything?
-- hendrik
Well, I was interested in how to make it work in Gambit as is. If we consider modifications to Gambit, there is an easy solution: give foreign objects a 'data' field that holds a user-settable strong reference to a Scheme object. Then, whenever you need to make sure that object A is not reclaimed while foreign object B is reachable, you just say (foreign-data-set! B A).
Indeed, after having tried hard, my current impression is that the above can't be done in a way that is robust and seamless to the user without modifying Gambit. I'd be very happy to be proven wrong in this!
I have made a pull request proposing that change:
https://github.com/feeley/gambit/pull/59
but I don't know whether the cost of one extra pointer per foreign object is a showstopper here.
If I'm not wrong you can take a similar approach to the one I took in my OpenAL wrapper on the Dumping Grounds page of the Gambit Wiki (http://dynamo.iro.umontreal.ca/wiki/images/2/2c/OpenAL.tar.gz). When I allocate a foreign struct, I attach a will to the object and in the will free the underlying C pointer when the foreign object is garbage collected. The implementation is at the bottom of the file labelled 'foreign-macros.scm' in that tarball.
On Tue, Dec 24, 2013 at 2:06 PM, Estevo euccastro@gmail.com wrote:
I've experimented in the past with making a macro that would generate the appropriate ffi code to create and manage c structs/unions/types. The challenge was to handle references obtained from accessors to fields containing other structs/union/types within them in such a way that
- no copying was necessary, and
- the original structure wouldn't be released as long as derived
references existed
Anyone know what guile does? If anything?
-- hendrik
Well, I was interested in how to make it work in Gambit as is. If we consider modifications to Gambit, there is an easy solution: give foreign objects a 'data' field that holds a user-settable strong reference to a Scheme object. Then, whenever you need to make sure that object A is not reclaimed while foreign object B is reachable, you just say (foreign-data-set! B A).
Indeed, after having tried hard, my current impression is that the above can't be done in a way that is robust and seamless to the user without modifying Gambit. I'd be very happy to be proven wrong in this!
I have made a pull request proposing that change:
https://github.com/feeley/gambit/pull/59
but I don't know whether the cost of one extra pointer per foreign object is a showstopper here.
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Hi Frederick,
If I'm not wrong you can take a similar approach to the one I took in
my OpenAL wrapper on the Dumping Grounds page of the Gambit Wiki (http://dynamo.iro.umontreal.ca/wiki/images/2/2c/OpenAL.tar.gz). When I allocate a foreign struct, I attach a will to the object and in the will free the underlying C pointer when the foreign object is garbage collected. The implementation is at the bottom of the file labelled 'foreign-macros.scm' in that tarball.
Thanks a lot for pointing me to this! I think it will be of great help. If anyone knows about any other references to code by people that have worked at wrapping C structs/unions/types before I'd be very thankful to know.
(Heads up: while the file has extension .tar.gz, it's a non gzipped tarball.)
While I'll look into your approach in more depth, some preliminary comments:
IIUC, the use case you talk about (handling a single struct in isolation) is handled extremely well by the default Gambit struct/union/type finalizer. Even for arrays I'd just write a C finalizer that frees their memory; I explain below why. I'm not sure why you are using wills here instead.
In any event, I'm convinced that if a library relies, to trigger finalization, on wills on foreign objects that are exposed to code written by others, then the library code can never really know for sure when the object will never be reachable again. Consider:
(define o (get-foreign-wrapper ...)) ; a will has been created for o,
which will delete the underlying C data
(define t (make-table weak-values: #t)) (table-set! t 'o o) (set! o #f) (##gc)
At this point your foreign wrapper is not strongly reachable anymore. The garbage collection has triggered your will, which has freed the C object wrapped by o. But you can still
(println (table-ref t 'o))
And get an access to invalid memory or a segmentation fault.
Note that the Gambit's ffi finalizers don't have this problem, since they only get called when your object is actually reclaimed. Nobody can attach new finalizers to your foreign objects, so at the time they get called you know that nobody else will be messing with those[1]. For more discussion on this, see:
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2013-December/007322....
[1] Well, you can do all sort of things from C code, but that is true for vanilla Scheme objects too. I'm concerned about users getting weird crashes by doing perfectly valid things in Scheme code.
2013/12/24 Estevo euccastro@gmail.com
Hi Frederick,
If I'm not wrong you can take a similar approach to the one I took in
my OpenAL wrapper on the Dumping Grounds page of the Gambit Wiki (http://dynamo.iro.umontreal.ca/wiki/images/2/2c/OpenAL.tar.gz). When I allocate a foreign struct, I attach a will to the object and in the will free the underlying C pointer when the foreign object is garbage collected. The implementation is at the bottom of the file labelled 'foreign-macros.scm' in that tarball.
Thanks a lot for pointing me to this! I think it will be of great help. If anyone knows about any other references to code by people that have worked at wrapping C structs/unions/types before I'd be very thankful to know.
(Heads up: while the file has extension .tar.gz, it's a non gzipped tarball.)
While I'll look into your approach in more depth, some preliminary comments:
IIUC, the use case you talk about (handling a single struct in isolation) is handled extremely well by the default Gambit struct/union/type finalizer. Even for arrays I'd just write a C finalizer that frees their memory; I explain below why. I'm not sure why you are using wills here instead.
In any event, I'm convinced that if a library relies, to trigger finalization, on wills on foreign objects that are exposed to code written by others, then the library code can never really know for sure when the object will never be reachable again. Consider:
(define o (get-foreign-wrapper ...)) ; a will has been created for o,
which will delete the underlying C data
(define t (make-table weak-values: #t)) (table-set! t 'o o) (set! o #f) (##gc)
At this point your foreign wrapper is not strongly reachable anymore. The garbage collection has triggered your will, which has freed the C object wrapped by o. But you can still
(println (table-ref t 'o))
And get an access to invalid memory or a segmentation fault.
Wait, what is returned by get-foreign-wrapper and are other references to it sticking around at that GC?
Note that the Gambit's ffi finalizers don't have this problem, since they only get called when your object is actually reclaimed. Nobody can attach new finalizers to your foreign objects, so at the time they get called you know that nobody else will be messing with those[1]. For more discussion on this, see:
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2013-December/007322....
[1] Well, you can do all sort of things from C code, but that is true for vanilla Scheme objects too. I'm concerned about users getting weird crashes by doing perfectly valid things in Scheme code.
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
(define o (get-foreign-wrapper ...)) ; a will has been created for o,
which will delete the underlying C data
(define t (make-table weak-values: #t)) (table-set! t 'o o) (set! o #f) (##gc)
At this point your foreign wrapper is not strongly reachable anymore. The garbage collection has triggered your will, which has freed the C object wrapped by o. But you can still
(println (table-ref t 'o))
And get an access to invalid memory or a segmentation fault.
Wait, what is returned by get-foreign-wrapper and are other references to it sticking around at that GC?
get-foreign-wrapper creates a foreign object with type (struct "something") and attachs a will to it that calls (e.g.) foreign-release! on it when executed. A complete, working example follows:
; test-invalid-access.scm ; ; Compile with ; ; gsc -cc-options -g -exe test-invalid-access.scm ; ; Test with ; ; valgrind ./test-invalid-access ; ; (Or some other memory usage checker.) ; ; Comment out last line to see that the program would otherwise never access ; invalid memory.
; BEGIN Library code
(c-declare "struct point {int x; int y;};")
(define (make-point x y) (let ((p ((c-lambda (int int) (struct "point") "struct point *p = (struct point*)___EXT(___alloc_rc)(sizeof(struct point)); p->x = ___arg1; p->y = ___arg2; ___result_voidstar = p;") x y))) (make-will p (lambda (x) (println "releasing " (point->string x)) (foreign-release! x))) p))
(define point-x (c-lambda ((struct "point")) int "___result = ((struct point*)___arg1_voidstar)->x;"))
(define point-y (c-lambda ((struct "point")) int "___result = ((struct point*)___arg1_voidstar)->y;"))
(define (point->string p) (string-append "point(" (number->string (point-x p)) ", " (number->string (point-y p)) ")"))
; END library code; BEGIN user code
(define p (make-point 1 2)) (define t (make-table weak-values: #t)) (table-set! t 'p p) (println "before releasing: " (point->string p)) (set! p #f) (##gc) (println "after releasing:") ; Comment out the following line and you get no invalid accesses. (println (point->string (table-ref t 'p)))
; END of example
Wait, what is returned by get-foreign-wrapper and are other references to
it sticking around at that GC?
As for the second question: yes, when I call (##gc) there are two weak references to the foreign object: one implied by the will that the library set on it, and other set by the user in the weak-valued hash table. The foreign object is *not* garbage collected at this point, because there are still references to it. But since none of these references is strong, the will that has it as testator will be made executable in the next garbage collection[1]. So I call (##gc) only to trigger that. Sometime after the will has been made executable, its action procedure gets called, which is what releases the foreign object.
[1] In the current implementation of Gambit, wills are only made executable on garbage collections. According to the docs, this may change in the future and shouldn't be relied upon.
Right. Just to clarify: Right now, do you see a problem about what's happening or do you consider all spinning fine?
2013/12/25 Estevo euccastro@gmail.com
[...] But since none of these references is strong, the will that has it
as testator
will be made executable in the next garbage collection[1].
(Sorry, by "the next" garbage collection I don't mean a different one, just the same one I trigger by calling (##gc).)
I think how wills work is fine. It's the particular usage of wills I described before that I find dangerous. The problem with Gambit is that it doesn't offer a better way to do that.
As I said, I'm working on a patch that enables a better way. As soon as I have a coherent proposal I'll ask the list for opinions/alternatives/suggestions.
On Wed, Dec 25, 2013 at 2:11 PM, Mikael mikael.rcv@gmail.com wrote:
Right. Just to clarify: Right now, do you see a problem about what's happening or do you consider all spinning fine?
2013/12/25 Estevo euccastro@gmail.com
[...] But since none of these references is strong, the will that has
it as testator
will be made executable in the next garbage collection[1].
(Sorry, by "the next" garbage collection I don't mean a different one, just the same one I trigger by calling (##gc).)
This is what I came up with.
https://github.com/feeley/gambit/pull/60
An usage example is included in the comments.
For rationale and background see my (withdrawn) previous shot at this:
https://github.com/feeley/gambit/pull/59/
Comments welcome!
On Wed, Dec 25, 2013 at 2:45 PM, Estevo euccastro@gmail.com wrote:
I think how wills work is fine. It's the particular usage of wills I described before that I find dangerous. The problem with Gambit is that it doesn't offer a better way to do that.
As I said, I'm working on a patch that enables a better way. As soon as I have a coherent proposal I'll ask the list for opinions/alternatives/suggestions.
On Wed, Dec 25, 2013 at 2:11 PM, Mikael mikael.rcv@gmail.com wrote:
Right. Just to clarify: Right now, do you see a problem about what's happening or do you consider all spinning fine?
2013/12/25 Estevo euccastro@gmail.com
[...] But since none of these references is strong, the will that has
it as testator
will be made executable in the next garbage collection[1].
(Sorry, by "the next" garbage collection I don't mean a different one, just the same one I trigger by calling (##gc).)
Estevo,
I think I completely lost you about what you are trying to achieve.
Please clarify, what particular use of wills do you find dangerous?
Is it that.. you find it tricky to get in place a particular sequence of C FFI structure release function invocation on their GC???
Something along the lines that if you have a C structure A that contains in it a reference to another C structure B, and you want Gambit's GC to automatically take care of this relationship in the sense that it will not release B before A??
Feel free to describe the totality of the problem you see as one or two sentences, so an elementary school kid would get it :)
Also feel free to describe some practical goal or usecase that cannot be achieved right now because of this
Mikael
2013/12/25 Estevo euccastro@gmail.com
I think how wills work is fine. It's the particular usage of wills I described before that I find dangerous. The problem with Gambit is that it doesn't offer a better way to do that.
As I said, I'm working on a patch that enables a better way. As soon as I have a coherent proposal I'll ask the list for opinions/alternatives/suggestions.
On Wed, Dec 25, 2013 at 2:11 PM, Mikael mikael.rcv@gmail.com wrote:
Right. Just to clarify: Right now, do you see a problem about what's happening or do you consider all spinning fine?
2013/12/25 Estevo euccastro@gmail.com
[...] But since none of these references is strong, the will that has
it as testator
will be made executable in the next garbage collection[1].
(Sorry, by "the next" garbage collection I don't mean a different one, just the same one I trigger by calling (##gc).)
Is it that.. you find it tricky to get in place a particular sequence of C FFI structure release function invocation on their GC???
It's not tricky if you know what you're doing. But if you are going to publish a library that exposes C bindings, you really don't want to have to be warning people against holding weak references to these foreign objects, lest they get a segfault or memory corruption.
Something along the lines that if you have a C structure A that contains in it a reference to another C structure B, and you want Gambit's GC to automatically take care of this relationship in the sense that it will not release B before A??
Yes, with the nuance that the C structure B is contained in A, not just referenced from it. So it doesn't make sense to free B at all. Another use case is that A is a union and B is another pointer to A's data. You want to free A only once.
But yes, the main point is that you want A to stick around while you have a reference to B. This kind of sanity you take for granted in the Scheme world, thanks to garbage collection. What I want is to be able to treat C objects similarly, without having to do unnecessary copies.
2013/12/25 Estevo euccastro@gmail.com
Is it that.. you find it tricky to get in place a particular sequence of C
FFI structure release function invocation on their GC???
It's not tricky if you know what you're doing. But if you are going to publish a library that exposes C bindings, you really don't want to have to be warning people against holding weak references to these foreign objects, lest they get a segfault or memory corruption.
I have never been aware of anything like that. Can you provide a proof of concept example code that shows how weak references to a FFI object would be inconsistent?
I guess the inconsistencies possible would be that the FFI object would not GC so you run out of heap, or that the weak reference would drop too early - do you see any other type of inconsistency that would need to be evaluated?
Something along the lines that if you have a C structure A that contains in
it a reference to another C structure B, and you want Gambit's GC to automatically take care of this relationship in the sense that it will not release B before A??
Yes, with the nuance that the C structure B is contained in A, not just referenced from it. So it doesn't make sense to free B at all. Another use case is that A is a union and B is another pointer to A's data. You want to free A only once.
But yes, the main point is that you want A to stick around while you have a reference to B. This kind of sanity you take for granted in the Scheme world, thanks to garbage collection. What I want is to be able to treat C objects similarly, without having to do unnecessary copies.
Aha.
You can implement this kind of behavior in Gambit (i.e. B is referenced to by or actually contained in A so you want freeing of B to be conditioned to the freeing of A happening before) yourself, for instance by
1) ensuring you have a reference to B in some vector or alike, one that guaranteedly will stick around until A is freed. Also, you could
2) use the "refcount" facility that Gambit exports to the C world, to keep B's refcount +1 as long as A refers to it, and then have A's release procedure -1 its refcount on invocation.
These would both be solid abstractions.
What practical task are you solving?
Perhaps in the module you're writing you don't expose the C defines to your users anyhow, so for instance using declare not collect-dead-variables or what its name is, would make 1) work out well. Anyhow I guess 2) is general.
There should be more solutions in the box too - any thoughts from other users?
What are your thoughts now?
Best regards, Mikael
I have never been aware of anything like that. Can you provide a proof of concept example code that shows how weak references to a FFI object would be inconsistent?
The problem is not that they're inconsistent. The problem is they can't really tell you when an object that is depended upon is safe to free. I gave an example of that in this thread:
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2013-December/007335....
You can implement this kind of behavior in Gambit (i.e. B is referenced to by or actually contained in A so you want freeing of B to be conditioned to the freeing of A happening before) yourself, for instance by
- ensuring you have a reference to B in some vector or alike, one that
guaranteedly will stick around until A is freed. Also, you could
Once user code gets hold of A, pure Scheme code can't really know when it's OK to let go of that vector. It's the same problem. Of course you can keep a reference forever, but you don't want to hold on to unneeded memory either.
- use the "refcount" facility that Gambit exports to the C world, to
keep B's refcount +1 as long as A refers to it, and then have A's release procedure -1 its refcount on invocation.
Something like this might work, thanks! I had given up on foreign release functions because they are C functions that can only be set (or so I thought) per foreign object type (the ones you create in c-define-type) and not per instance, they can't be closures, and they won't get any arguments but the foreign's pointer to C data. Also, you can only set one, so if you use it for this you can't use it for anything else.
But these restrictions need not be showstoppers. A scheme that might work: - on initalization, create an ___alloc_rc'ed table[1] and assign a global C pointer to it - whenever you create a dependent foreign pointer F, store in the table a reference to its dependent object D, keyed by the address of the F's C pointer, and - set a release function for F that will clear that entry in the table.
This should work because unlike wills, release functions will only be called when their object is not reachable from Scheme code (barring FFI black magic).
What practical task are you solving?
I'm making a library that lets you define C struct/union/type constructors, accessors and mutators using a syntax analogous to that of define-structure. Here's how you define C structure wrappers:
https://github.com/euccastro/gambit-SDL2/blob/master/c-test-ffi.scm
and here's how you use them
https://github.com/euccastro/gambit-SDL2/blob/master/test-ffi.scm
Here's a non-test example:
https://github.com/euccastro/gambit-SDL2/blob/master/sdl.scm
This is from a very old version and it shows that I didn't know what I was doing :), but it does showcase the user interface. The point is that using C structures from Gambit code should be effortless, straightforward, safe, and fit well both with Scheme and with FFI code that doesn't follow your approach.
I'll give the scheme above a go and let you know how it goes. I think the solution involving my patch[2] should yield better performance because it doesn't involve any table following and, not requiring the use of release functions, allows you to set the last parameter of c-define-type to false. But maybe this won't matter in practice.
Thanks again!
[1] Globals won't do because the garbage collector doesn't scan those. Movable objects won't do because you can't reliably keep a C pointer to them. [2] Which, by the way, I've simplified down to a 5-line change. See https://github.com/feeley/gambit/pull/61
https://github.com/feeley/gambit/pull/61 - for a quick proof of concept, that's a very neat use of the ffi type!!!
2013/12/25 Estevo euccastro@gmail.com
I have never been aware of anything like that. Can you provide a proof
of concept example code that shows how weak references to a FFI object would be inconsistent?
The problem is not that they're inconsistent. The problem is they can't really tell you when an object that is depended upon is safe to free. I gave an example of that in this thread:
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2013-December/007335....
So you tried to somehow use wills to force GC order? Without having studied this, I guess that was not what they were intended for in the first place and it makes good sense that that did not work out well.
You can implement this kind of behavior in Gambit (i.e. B is referenced to by or actually contained in A so you want freeing of B to be conditioned to the freeing of A happening before) yourself, for instance by
- ensuring you have a reference to B in some vector or alike, one that
guaranteedly will stick around until A is freed. Also, you could
Once user code gets hold of A, pure Scheme code can't really know when it's OK to let go of that vector. It's the same problem. Of course you can keep a reference forever, but you don't want to hold on to unneeded memory either.
You should be able to work that out and question is just how heavy it would be implementation-wise to do, no??
If not why not?
- use the "refcount" facility that Gambit exports to the C world, to
keep B's refcount +1 as long as A refers to it, and then have A's release procedure -1 its refcount on invocation.
Something like this might work, thanks! I had given up on foreign release functions because they are C functions that can only be set (or so I thought) per foreign object type (the ones you create in c-define-type) and not per instance, they can't be closures, and they won't get any arguments but the foreign's pointer to C data. Also, you can only set one, so if you use it for this you can't use it for anything else.
But these restrictions need not be showstoppers. A scheme that might work:
- on initalization, create an ___alloc_rc'ed table[1] and assign a global
C pointer to it
- whenever you create a dependent foreign pointer F, store in the table a
reference to its dependent object D, keyed by the address of the F's C pointer, and
- set a release function for F that will clear that entry in the table.
Why do you need a "table" (by table here you mean resizable vector)?
This should work because unlike wills, release functions will only be called when their object is not reachable from Scheme code (barring FFI black magic).
What practical task are you solving?
I'm making a library that lets you define C struct/union/type constructors, accessors and mutators using a syntax analogous to that of define-structure.
Nice!
Gambit's builtin functionality for this is fully sufficient at Gambit's level of abstraction over the underlying system, and indeed there's plenty of space for higher-level abstractions that more in this area.
So the totality of what you are looking to provide is
a) the c-struct form which is analogous to define-type with
b) Scheme-like automatic dependency GC-reference handling between c structure instances as discussed here
?
Here's how you define C structure wrappers:
https://github.com/euccastro/gambit-SDL2/blob/master/c-test-ffi.scm
and here's how you use them
https://github.com/euccastro/gambit-SDL2/blob/master/test-ffi.scm
Here's a non-test example:
https://github.com/euccastro/gambit-SDL2/blob/master/sdl.scm
This is from a very old version and it shows that I didn't know what I was doing :), but it does showcase the user interface. The point is that using C structures from Gambit code should be effortless, straightforward, safe, and fit well both with Scheme and with FFI code that doesn't follow your approach.
I'll give the scheme above a go and let you know how it goes. I think the solution involving my patch[2] should yield better performance because it doesn't involve any table following and,
not requiring the use of release functions,
well, if it's some exotic type where you need C code invoked for the release work then indeed there is the need for a release function, however if that's not the case then yep right, with this model you suggest, there's no need for a release function.
allows you to set the last parameter of c-define-type to false. But maybe this won't matter in practice.
Thanks again!
[1] Globals won't do because the garbage collector doesn't scan those. Movable objects won't do because you can't reliably keep a C pointer to them. [2] Which, by the way, I've simplified down to a 5-line change. See https://github.com/feeley/gambit/pull/61
Estevo,
To get where you are at now - at the current point, are you happy with what Gambit does right now, or are you still seeing an issue?
If so, can you provide like a three-line example illustrating the problem and how it could be resolved?
Happy Holidays, Mikael
2013/12/24 Estevo euccastro@gmail.com
I've experimented in the past with making a macro that would generate
the
appropriate ffi code to create and manage c structs/unions/types. The challenge was to handle references obtained from accessors to fields containing other structs/union/types within them in such a way that
- no copying was necessary, and
- the original structure wouldn't be released as long as derived
references
existed
Anyone know what guile does? If anything?
-- hendrik
Well, I was interested in how to make it work in Gambit as is. If we consider modifications to Gambit, there is an easy solution: give foreign objects a 'data' field that holds a user-settable strong reference to a Scheme object. Then, whenever you need to make sure that object A is not reclaimed while foreign object B is reachable, you just say (foreign-data-set! B A).
Indeed, after having tried hard, my current impression is that the above can't be done in a way that is robust and seamless to the user without modifying Gambit. I'd be very happy to be proven wrong in this!
I have made a pull request proposing that change:
https://github.com/feeley/gambit/pull/59
but I don't know whether the cost of one extra pointer per foreign object is a showstopper here.
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list