Hi,
i'm currently coding a gambit binding for sfml and could need some adivces for a specific ffi problem from you.
Assume we have a class VideoMode with the following constructor:
class VideoMode { public: VideoMode(int width, int height, int bbp); # ... }
I have defined an interface to scheme with:
;; Release hook is ignored for this example (c-define-type VideoMode* (pointer "VideoMode"))
;; Scheme's construction wrapper for VideoMode (define video-mode (c-lambda (int int int) VideoMode* "___result_voidstar = new VideoMode(___arg1, ___arg2, ___arg3);"))
Now assume a function that retrieves all supporting video-modes in C++:
std::vector<VideoMode> getFullscreenModes();
I would like to write now a scheme-function (with c-lambda) that iterators through all elements from this std::vector and constructs/returns a scheme-vector with foreign-objects of type (pointer "VideoMode").
How does the c-lambda code look like for this small issue? (Or how would you cope this problem alternatively?)
Chris
Afficher les réponses par date
Perhaps make a c-define-type for std::vector<VideoMode>* that you return the return value of .getFullscreenModes() as, and then make a -length and -ref procedure for this type.
Remember that for c-define-type :s that do not have a release procedure specified, there is *no* deallocation (such as free() etc.) invoked at their scheme-world GC.
2013/8/16 Chris Mueller ruunsmail@gmail.com
Hi,
i'm currently coding a gambit binding for sfml and could need some adivces for a specific ffi problem from you.
Assume we have a class VideoMode with the following constructor:
class VideoMode { public: VideoMode(int width, int height, int bbp); # ... }
I have defined an interface to scheme with:
;; Release hook is ignored for this example (c-define-type VideoMode* (pointer "VideoMode"))
;; Scheme's construction wrapper for VideoMode (define video-mode (c-lambda (int int int) VideoMode* "___result_voidstar = new VideoMode(___arg1, ___arg2, ___arg3);"))
Now assume a function that retrieves all supporting video-modes in C++:
std::vector<VideoMode> getFullscreenModes();
I would like to write now a scheme-function (with c-lambda) that iterators through all elements from this std::vector and constructs/returns a scheme-vector with foreign-objects of type (pointer "VideoMode").
How does the c-lambda code look like for this small issue? (Or how would you cope this problem alternatively?)
Chris
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
This works :)
38 (define (get-fullscreen-modes) 39 (define get-fullscreen-modes* 40 (c-lambda () sfml:Vector<VideoMode>* 41 "___result_voidstar = new std::vectorsf::VideoMode(sf::VideoMode::getFullscreenModes());")) 42 (define vector-video-mode-length 43 (c-lambda (sfml:Vector<VideoMode>*) size_t 44 "___result = ___arg1->size();")) 45 (define vector-video-mode-ref 46 (c-lambda (sfml:Vector<VideoMode>* size_t) sfml:VideoMode* 47 "___result_voidstar = new sf::VideoMode(___arg1->at(___arg2));")) 48 49 (let* ((modes (get-fullscreen-modes*)) 50 (size (vector-video-mode-length modes)) 51 (result (make-vector size))) 52 (let loop ((i 0)) 53 (cond 54 ((< i size) 55 (vector-set! result i (vector-video-mode-ref modes i)) 56 (loop (+ i 1))) 57 (else 58 result)))))
Is it also possible to accomplish the same directly from a c-lambda that returns a scheme-object?
Am 16.08.2013 09:54, schrieb Mikael:
Perhaps make a c-define-type for std::vector<VideoMode>* that you return the return value of .getFullscreenModes() as, and then make a -length and -ref procedure for this type.
Remember that for c-define-type :s that do not have a release procedure specified, there is *no* deallocation (such as free() etc.) invoked at their scheme-world GC.
2013/8/16 Chris Mueller <ruunsmail@gmail.com mailto:ruunsmail@gmail.com>
Hi, i'm currently coding a gambit binding for sfml and could need some adivces for a specific ffi problem from you. Assume we have a class VideoMode with the following constructor: class VideoMode { public: VideoMode(int width, int height, int bbp); # ... } I have defined an interface to scheme with: ;; Release hook is ignored for this example (c-define-type VideoMode* (pointer "VideoMode")) ;; Scheme's construction wrapper for VideoMode (define video-mode (c-lambda (int int int) VideoMode* "___result_voidstar = new VideoMode(___arg1, ___arg2, ___arg3);")) Now assume a function that retrieves all supporting video-modes in C++: std::vector<VideoMode> getFullscreenModes(); I would like to write now a scheme-function (with c-lambda) that iterators through all elements from this std::vector and constructs/returns a scheme-vector with foreign-objects of type (pointer "VideoMode"). How does the c-lambda code look like for this small issue? (Or how would you cope this problem alternatively?) Chris _______________________________________________ Gambit-list mailing list Gambit-list@iro.umontreal.ca <mailto:Gambit-list@iro.umontreal.ca> https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Hi Chris, super. Feel free to publish it when it's going.
Is it also possible to accomplish the same directly from a c-lambda that
returns a scheme-object?
Yes, however then for stability you need to sugar *all* Scheme object allocations you do in C with heap overflow handling logics.
Also a route would be you made a c-define that you have a C enumeration loop that reports to and the invoked Scheme code does the allocation. For stability you'd need to ensure other threads don't take over execution and rewind another C frame, and that you do by stopping Gambit's scheduler, and also if there'd be a heap overflow or other exception, that needs to be handled in such a way that your C enumeration loop's stack frame is rewound properly, so unless needed you don't want to take this route.
So I'd say as long as you feel it's viable to go with the form you are with now, that is the best option.
Am 16.08.2013 09:54, schrieb Mikael:
Remember that for c-define-type :s that do not have a release procedure specified, there is *no* deallocation (such as free() etc.) invoked at their scheme-world GC.
I've read in the documentation for the default release function (pointer ..) and (nonnull-pointer ...) types are not performing any deallocation like you mentioned.
I'm a little bit curious about (struct ..) type-definitions because due to the documentation it has probably a more useful default behaviour for releasing.
Can i assume if i allocate and use a (struct ...) type that the GC management system will handle this reference properly? (in contrast to pointers)
This would save me a lot of specific cleanup code for all predefined types if gambit's system is performing delete calls automatically for structs.
e.g.
(c-define-type std::string (struct "std::string")) (define string-new (c-lambda (nonnull-char-string) std::string "___result_voidstar = new std::string(___arg1);"))
Only for clarification for myself i don't create memory leaks.
Thanks, Chris
On struct it would make sense, it was indeed only pointered types I had on my mind. Allocate a billion, see for yourself and tell here?
2013/8/17 Chris Mueller ruunsmail@gmail.com
Am 16.08.2013 09:54, schrieb Mikael:
Remember that for c-define-type :s that do not have a release procedure specified, there is *no* deallocation (such as free() etc.) invoked at their scheme-world GC.
I've read in the documentation for the default release function (pointer ..) and (nonnull-pointer ...) types are not performing any deallocation like you mentioned.
I'm a little bit curious about (struct ..) type-definitions because due to the documentation it has probably a more useful default behaviour for releasing.
Can i assume if i allocate and use a (struct ...) type that the GC management system will handle this reference properly? (in contrast to pointers)
This would save me a lot of specific cleanup code for all predefined types if gambit's system is performing delete calls automatically for structs.
e.g.
(c-define-type std::string (struct "std::string")) (define string-new (c-lambda (nonnull-char-string) std::string "___result_voidstar = new std::string(___arg1);"))
Only for clarification for myself i don't create memory leaks.
Thanks, Chris
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 17.08.2013 22:59, Mikael wrote:
On struct it would make sense, it was indeed only pointered types I had on my mind. Allocate a billion, see for yourself and tell here?
I've checked this with the following example.
(define (alloc-string n) (let loop ((i 0)) (if (< i n) (let ((a (std::string "test"))) (loop (+ i 1))) (write "FIN")))))
When using (struct std::string ...) without a release function, memory grow's rapidly (checked this in htop) until it heap overflows.
With a given release function memory assumptions is constantly small.
Seems there is currently no difference in the deallocation behaviour between structs and pointer types.
Too bad :/
Chris
std::string requires delete to be used for proper deallocation and free() might just partially deallocate it, no? - what about trying with some more ordinary struct like tm ?
2013/8/18 Chris Mueller ruunsmail@gmail.com
On 17.08.2013 22:59, Mikael wrote:
On struct it would make sense, it was indeed only pointered types I had on my mind. Allocate a billion, see for yourself and tell here?
I've checked this with the following example.
(define (alloc-string n) (let loop ((i 0)) (if (< i n) (let ((a (std::string "test"))) (loop (+ i 1))) (write "FIN")))))
When using (struct std::string ...) without a release function, memory grow's rapidly (checked this in htop) until it heap overflows.
With a given release function memory assumptions is constantly small.
Seems there is currently no difference in the deallocation behaviour between structs and pointer types.
Too bad :/
Chris
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 19.08.2013 06:13, Mikael wrote:
std::string requires delete to be used for proper deallocation and free() might just partially deallocate it, no? - what about trying with some more ordinary struct like tm ?
Could be, but i think this is not the case. The documentation mentioned if gambit is using g++ it should actually use 'delete (type*) internal-pointer'.
I've also checked this with a POD struct:
struct test { int A; int B }
It's no difference if * struct test is allocated with new * struct test is allocated with malloc
It's also leaking memory.
2013/8/19 Chris Mueller ruunsmail@gmail.com
On 19.08.2013 06:13, Mikael wrote:
std::string requires delete to be used for proper deallocation and free() might just partially deallocate it, no? - what about trying with some more ordinary struct like tm ?
Could be, but i think this is not the case. The documentation mentioned if gambit is using g++ it should actually use 'delete (type*) internal-pointer'.
Ah good point.
I've also checked this with a POD struct:
struct test { int A; int B }
It's no difference if
- struct test is allocated with new
- struct test is allocated with malloc
It's also leaking memory.
So the manual goes:
When the release-function is not specified or is #f a default function is
constructed by the C-interface.
(This is the case here.)
This default function does nothing in the case of the pointer and
nonnull-pointer types (deallocation is not the responsibility of the C-interface) and returns the fixnum ‘___FIX(___NO_ERR)’ to indicate no error.
So in your past test with a pointered type, you did see the proper behavior. And here comes what applies to the current test:
In the case of the struct, union and type types, the default function
reclaims the copy on the C heap referenced by the internal pointer (when using a C++ compiler this is done using ‘delete (type*)internal-pointer’, which calls the destructor of type if it is a class) and returns ‘ ___FIX(___NO_ERR)’.
Can you paste your full test code here?
Mikael
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 19.08.2013 12:16, Mikael wrote:
So in your past test with a pointered type, you did see the proper behavior. And here comes what applies to the current test:
In the case of the |struct|, |union| and |type| types, the default function reclaims the copy on the C heap referenced by the internal pointer (when using a C++ compiler this is done using ‘delete (type*)internal-pointer’, which calls the destructor of type if it is a class) and returns ‘___FIX(___NO_ERR)’.
Can you paste your full test code here?
Of course :)
;; struct definition (c-declare "struct test { int a; int b; };")
(c-define-type struct-test (struct "test"))
(define struct-test (c-lambda () struct-test "___result_voidstar = new test;"))
;; test code (load "test")
(define (alloc-struct n) (let loop ((i 0)) (if (< i n) (let ((a (struct-test))) (loop (+ i 1)) (write "FIN")))))
(alloc-struct 100000000000)
Waait. I didn't check but I'm not so sure it's supposed to work like that - I wonder why you had access to ___result_voidstar there at all.
Please allocate such a test structure *locally on the stack* within your struct-test procedure, and then set ___result to it. I.e., by value and not by pointer passing. Then paste here again.
2013/8/19 Chris Mueller ruunsmail@gmail.com
On 19.08.2013 12:16, Mikael wrote:
So in your past test with a pointered type, you did see the proper behavior. And here comes what applies to the current test:
In the case of the |struct|, |union| and |type| types, the default function reclaims the copy on the C heap referenced by the internal pointer (when using a C++ compiler this is done using ‘delete (type*)internal-pointer’, which calls the destructor of type if it is a class) and returns ‘___FIX(___NO_ERR)’.
Can you paste your full test code here?
Of course :)
;; struct definition (c-declare "struct test { int a; int b; };")
(c-define-type struct-test (struct "test"))
(define struct-test (c-lambda () struct-test "___result_voidstar = new test;"))
;; test code (load "test")
(define (alloc-struct n) (let loop ((i 0)) (if (< i n) (let ((a (struct-test))) (loop (+ i 1)) (write "FIN")))))
(alloc-struct 100000000000)
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 20.08.2013 14:01, Mikael wrote:
Waait. I didn't check but I'm not so sure it's supposed to work like that - I wonder why you had access to ___result_voidstar there at all.
Yep, that's interesting. You can even use it in another procedures that expects a struct (it dereferences automatically the pointer).
In the documentation section 19.1 there are some interesting hints about that.
* internal pointer points to a copy of c-data type. * When an instance is converted from C to Scheme, a block of memory is allocated from C Heap and initialized with that instance. * After that a foreign-object is allocated from scheme-heap and initialized via copy-constructor from the c object in g++. * Deallocation of the copy on the C heap is under control of the release function attached to the foreign object.
i don't know whether managing the c-copy is in responsibility of the developer or the scheme compiler.
Please allocate such a test structure *locally on the stack* within your struct-test procedure, and then set ___result to it. I.e., by value and not by pointer passing. Then paste here again.
Here's the new procedure:
(define struct-test (c-lambda () struct-test "struct test x; ___result = x;"))
But if i run the test script with this function, i get a segmentation fault immediately.
There is also another option which comes in my mind:
(define struct-test (c-lambda () struct-test "struct test x; ___result_voidstar = &x;"))
This is e.g. running the allocation loop. But it will segfault when quiting the script with CTRL + X.
I've currently work around this by explicitly setting the release function with a simple c++ template.
typename <typename T> ___SCMOBJ release(void* ptr) { delete ((T*) ptr); return ___FIX(___NO_ERR); }
But it would be great, if we could clarify later the proper usage of structs in the ffi. I've gotten curious about that. :)
Hi Chris,
Yes this is a good Q.
2013/8/20 Chris Mueller ruunsmail@gmail.com ..
(define struct-test (c-lambda () struct-test "struct test x; ___result = x;"))
But if i run the test script with this function, i get a segmentation fault immediately.
Weird!
There is also another option which comes in my mind:
(define struct-test (c-lambda () struct-test "struct test x; ___result_voidstar = &x;"))
This is e.g. running the allocation loop. But it will segfault when quiting the script with CTRL + X.
Weird too!
But it would be great, if we could clarify later the proper usage of structs in the ffi. I've gotten curious about that. :)
Sounds like a good time to ask Marc!
Now just for absolute clarity, can you please paste the total code of your three different examples (the one leaking and the two sigsegv:ing).
Best regards, Mikael