Im creating a scheme list of pointers to c-structs in a c-function similar to the STRINGS_to_SCMOBJ example in section 19.6 of the gambit manual. The only difference being that i put pointers into the list via POINTER_to_SCMOBJ. This works fine as long as i pass ___FAL as the second parameter and gambit treats the pointer as foreign.
Now i have a c-define-type e.g.:
(c-define-type Node* (pointer "Node"))
And some c-lambdas, e.g.:
(define rotate-node (c-lambda (Node* float) void "___arg1->rotate(___arg2)))
(define get-childnodes (c-lambda (Node*) scheme-object "LIST_to_SCMOBJ<Node*>(___arg1->childs(), &___result);")))
By calling (get-childnodes foonode), i get a list of pointers to the childs. If i now pass one of the pointers in the list to (rotate-node childnode) it segfaults, because - im just guessing - the types foreign and Node* are not compatible. If i define Node* with #f in the tag field to omit typechecks:
(c-define-type Node* (pointer "Node" #f))
It works. But i would like to preserve the typecheck by passing the right tag to POINTER_to_SCMOBJ and getting pointers with the exact type information. While digging around the generated c files i found some places where i could get it from, e.g. the ___C_OBJ_(N) defines, but it does not seem like i could rely on those, because the order can always change and i would have to look them up after compiling...
Is it possible to get the right type-tag or does it even make sense to do so? This is my first attemp at the FFI and im probably messing stuff up, because some things are unclear to me. E.g. what is the purpose of the arg_num parameter which is passed to all the *_to_SCMOBJ functions?
Im also not defining the ___BEGIN_CFUN, ___END_CFUN and SFUN macros and do not create an extra c-define-type for the list of nodes. In the STRINGS_to_SCMOBJ example a comment says:
/* * Note that result is either the empty list or a ___STILL pair * with a reference count equal to 1. There will be a call to * ___release_scmobj later on (in ___END_CFUN_STRINGS_to_SCMOBJ * or ___END_SFUN_STRINGS_to_SCMOBJ) that will allow the garbage * collector to reclaim the whole list of strings when the Scheme * world no longer references it. */
Does that mean, that in my case the returned scheme-object from get-childnodes would never be collected? Here is the LIST_to_SCMOBJ function:
template<typename T> ___SCMOBJ LIST_to_SCMOBJ(const List<T> *src, ___SCMOBJ *dst) { ___SCMOBJ ___err = ___FIX(___NO_ERR); ___SCMOBJ result = ___NUL;
const ListIter<T> iter = src->iter(); while(iter.moveNext()) { ___SCMOBJ item = ___NUL; ___err = ___POINTER_to_SCMOBJ(iter.current(), ___FAL, NULL, &item, 0);
___SCMOBJ newresult = ___EXT(___make_pair)(item, newresult, ___STILL);
___EXT(___release_scmobj)(item); ___EXT(___release_scmobj)(result);
result = newresult;
if (___FIXNUMP(result)) { return result; } }
*dst = result;
return ___FIX(___NO_ERR); }
And Hello everyone who read this far ;) this is my first post here. Cheers, Till
Afficher les réponses par date
Sorry for not responding sooner. I'm a bit busy right now, but I should have some time this afternoon to take a closer look into this.
Here are some ideas...
1) Have you compiled Gambit with the --enable-cplusplus option?
2) Are you using multiple inheritance for your Node type? The casts may cause problems in this case.
3) You say your code segfaults when not using the #f to omit typechecks. This is strange. You should get an error message, not a segfault.
4) The code:
(define get-childnodes (c-lambda (Node*) scheme-object "LIST_to_SCMOBJ<Node*>(___arg1->childs(), &___result);")))
is strange. The function LIST_to_SCMOBJ returns an error code, and a result in the second parameter. You are ignoring the error code, which is not a good idea. It is best to implement conversion operations on your type. For example:
(c-define-type Node* "Node*" "NodeSTAR_to_SCMOBJ" "SCMOBJ_to_NodeSTAR" #t)
(c-declare #<<END
#define ___BEGIN_SFUN_NodeSTAR_to_SCMOBJ(src,dst,i) \ if ((___err = NodeSTAR_to_SCMOBJ(src, &dst, i)) == ___FIX(___NO_ERR)) { #define ___END_SFUN_NodeSTAR_to_SCMOBJ(src,dst,i) \ ___EXT(___release_scmobj)(dst); }
...
END )
Finally, the arg_num parameter is there to generate precise error code which indicate which parameter of a foreign function did not have the correct type.
Marc
On 2011-07-15, at 11:24 AM, Till wrote:
Im creating a scheme list of pointers to c-structs in a c-function similar to the STRINGS_to_SCMOBJ example in section 19.6 of the gambit manual. The only difference being that i put pointers into the list via POINTER_to_SCMOBJ. This works fine as long as i pass ___FAL as the second parameter and gambit treats the pointer as foreign.
Now i have a c-define-type e.g.:
(c-define-type Node* (pointer "Node"))
And some c-lambdas, e.g.:
(define rotate-node (c-lambda (Node* float) void "___arg1->rotate(___arg2)))
(define get-childnodes (c-lambda (Node*) scheme-object "LIST_to_SCMOBJ<Node*>(___arg1->childs(), &___result);")))
By calling (get-childnodes foonode), i get a list of pointers to the childs. If i now pass one of the pointers in the list to (rotate-node childnode) it segfaults, because - im just guessing - the types foreign and Node* are not compatible. If i define Node* with #f in the tag field to omit typechecks:
(c-define-type Node* (pointer "Node" #f))
It works. But i would like to preserve the typecheck by passing the right tag to POINTER_to_SCMOBJ and getting pointers with the exact type information. While digging around the generated c files i found some places where i could get it from, e.g. the ___C_OBJ_(N) defines, but it does not seem like i could rely on those, because the order can always change and i would have to look them up after compiling...
Is it possible to get the right type-tag or does it even make sense to do so? This is my first attemp at the FFI and im probably messing stuff up, because some things are unclear to me. E.g. what is the purpose of the arg_num parameter which is passed to all the *_to_SCMOBJ functions?
Im also not defining the ___BEGIN_CFUN, ___END_CFUN and SFUN macros and do not create an extra c-define-type for the list of nodes. In the STRINGS_to_SCMOBJ example a comment says:
/*
- Note that result is either the empty list or a ___STILL pair
- with a reference count equal to 1. There will be a call to
- ___release_scmobj later on (in ___END_CFUN_STRINGS_to_SCMOBJ
- or ___END_SFUN_STRINGS_to_SCMOBJ) that will allow the garbage
- collector to reclaim the whole list of strings when the Scheme
- world no longer references it.
*/
Does that mean, that in my case the returned scheme-object from get-childnodes would never be collected? Here is the LIST_to_SCMOBJ function:
template<typename T> ___SCMOBJ LIST_to_SCMOBJ(const List<T> *src, ___SCMOBJ *dst) { ___SCMOBJ ___err = ___FIX(___NO_ERR); ___SCMOBJ result = ___NUL;
const ListIter<T> iter = src->iter(); while(iter.moveNext()) { ___SCMOBJ item = ___NUL; ___err = ___POINTER_to_SCMOBJ(iter.current(), ___FAL, NULL, &item, 0);
___SCMOBJ newresult = ___EXT(___make_pair)(item, newresult, ___STILL);
___EXT(___release_scmobj)(item); ___EXT(___release_scmobj)(result);
result = newresult;
if (___FIXNUMP(result)) { return result; } }
*dst = result;
return ___FIX(___NO_ERR); }
And Hello everyone who read this far ;) this is my first post here. Cheers, Till _______________________________________________ Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
- Have you compiled Gambit with the --enable-cplusplus option?
As far as i remember i only changed the compiler to g++. I updated from 4.6.0 to 4.6.1 and recompiled with --enable-cplusplus and it does not segfault anymore.
- Are you using multiple inheritance for your Node type? The casts may cause problems in this case.
No inheritance at all.
- You say your code segfaults when not using the #f to omit typechecks. This is strange. You should get an error message, not a segfault.
It works fine now, i dont even have to pass #f anymore. But the pointer still shows up as foreign of course. #<foreign #2 0x100855ad0>
- The code:
(define get-childnodes (c-lambda (Node*) scheme-object "LIST_to_SCMOBJ<Node*>(___arg1->childs(), &___result);")))
is strange. The function LIST_to_SCMOBJ returns an error code, and a result in the second parameter. You are ignoring the error code, which is not a good idea. It is best to implement conversion operations on your type. For example:
Ah, yeah - i should check and handle the error. I will write the conversion operations and fiddle with it. But my original question remains, when i call POINTER_to_SCMOBJ, how can i pass the Node* type tag? like in:
___SCMOBJ NodeSTAR_to_SCMOBJ(Node *src, ___SCMOBJ *dst, int arg_num) { return ___POINTER_to_SCMOBJ(src, ?????, NULL, dst, arg_num); }
___FAL works there, but gives me pointers of type foreign, which now work after after my self build problem is gone. I can leave it at that, i just thought there might be a way to tell POINTER_to_SCMOBJ the right type, if it makes any sense at all.
Thanks for looking into it! Till