I'm opening a new subject for the ffi struct issue to sum up the current discussion:
In 19.1 "The Mapping of types between C and Scheme" of the gambit documentation is mentioned:
"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)’. In many situations the default release-function will perform the appropriate cleanup for the foreign type."
If i interpret this correctly, a declared struct type in a ffi provides a default release function that automatically calls a destructor (used with g++) and frees the corresponding memory.
Unfortanetly, i'm little lost to use it correctly and experiment currently heavily to find the right way.
Assume a type:
(c-declare "struct point { int x; int y; };") (c-define-type struct-point (struct "point"))
Assume a test programm that allocates a point 1_000_000_000 times.
(define (alloc-point times) (let loop ((i 0)) (if (< i times) (let ((a (make-point 0 0))) (loop (+ i 1)))))))
(alloc-point 1000000000)
How do we implement (make-point x y) to use a ffi struct type with a default release function in Gambit?
1) With a manually allocated pointer it will leak memory.
(define make-point (c-lambda (int int) struct-point "point* a = new Point; a->x = ___arg1; a->y = ___arg2; ___result_voidstar = a;"))
2) With a stack-allocated value it will segfault immediately.
(define make-point (c-lambda (int int) struct-point "point a; a.x = ___arg1; a.y = ___arg2; ___result = a;"))
3) If we give the address of a stack-allocated value to ___result_voidstar the allocation loop is running with constant memory space but the programm will segfault after quiting with CTRL + X.
(define make-point (c-lambda (int int) struct-point "point a; a.x = ___arg1; a.y = ___arg2; ___result_voidstar = &a;"))
For more details, see discussion: https://mercure.iro.umontreal.ca/pipermail/gambit-list/2013-August/006950.ht...
Chris
Afficher les réponses par date
What about you presume that ___result_voidstar is already allocated, and you just access/mutate it? I.e.
(define make-point (c-lambda (int int) struct-point "___result_voidstar->.x = ___arg1; ___result_voidstar->y = ___arg2;"))
?
2013/8/22 Chris Mueller ruunsmail@gmail.com
I'm opening a new subject for the ffi struct issue to sum up the current discussion:
In 19.1 "The Mapping of types between C and Scheme" of the gambit documentation is mentioned:
"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)’. In many situations the default release-function will perform the appropriate cleanup for the foreign type."
If i interpret this correctly, a declared struct type in a ffi provides a default release function that automatically calls a destructor (used with g++) and frees the corresponding memory.
Unfortanetly, i'm little lost to use it correctly and experiment currently heavily to find the right way.
Assume a type:
(c-declare "struct point { int x; int y; };") (c-define-type struct-point (struct "point"))
Assume a test programm that allocates a point 1_000_000_000 times.
(define (alloc-point times) (let loop ((i 0)) (if (< i times) (let ((a (make-point 0 0))) (loop (+ i 1)))))))
(alloc-point 1000000000)
How do we implement (make-point x y) to use a ffi struct type with a default release function in Gambit?
- With a manually allocated pointer it will leak memory.
(define make-point (c-lambda (int int) struct-point "point* a = new Point; a->x = ___arg1; a->y = ___arg2; ___result_voidstar = a;"))
- With a stack-allocated value it will segfault immediately.
(define make-point (c-lambda (int int) struct-point "point a; a.x = ___arg1; a.y = ___arg2; ___result = a;"))
- If we give the address of a stack-allocated value to
___result_voidstar the allocation loop is running with constant memory space but the programm will segfault after quiting with CTRL + X.
(define make-point (c-lambda (int int) struct-point "point a; a.x = ___arg1; a.y = ___arg2; ___result_voidstar = &a;"))
For more details, see discussion:
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2013-August/006950.ht...
Chris _______________________________________________ Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Good point.
But gsc / gcc are reclaiming ___result_voidstar is of type void* and has no elements x and y therefore.
Manually casting to struct point* is of course possible, but will result in an expected segmentation fault during the execution of the script.
On 22.08.2013 08:34, Mikael wrote:
What about you presume that ___result_voidstar is already allocated, and you just access/mutate it? I.e.
(define make-point (c-lambda (int int) struct-point "___result_voidstar->.x = ___arg1; ___result_voidstar->y = ___arg2;"))
?
2013/8/22 Chris Mueller <ruunsmail@gmail.com mailto:ruunsmail@gmail.com>
I'm opening a new subject for the ffi struct issue to sum up the current discussion: In 19.1 "The Mapping of types between C and Scheme" of the gambit documentation is mentioned: "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)’. In many situations the default release-function will perform the appropriate cleanup for the foreign type." If i interpret this correctly, a declared struct type in a ffi provides a default release function that automatically calls a destructor (used with g++) and frees the corresponding memory. Unfortanetly, i'm little lost to use it correctly and experiment currently heavily to find the right way. Assume a type: (c-declare "struct point { int x; int y; };") (c-define-type struct-point (struct "point")) Assume a test programm that allocates a point 1_000_000_000 times. (define (alloc-point times) (let loop ((i 0)) (if (< i times) (let ((a (make-point 0 0))) (loop (+ i 1))))))) (alloc-point 1000000000) How do we implement (make-point x y) to use a ffi struct type with a default release function in Gambit? 1) With a manually allocated pointer it will leak memory. (define make-point (c-lambda (int int) struct-point "point* a = new Point; a->x = ___arg1; a->y = ___arg2; ___result_voidstar = a;")) 2) With a stack-allocated value it will segfault immediately. (define make-point (c-lambda (int int) struct-point "point a; a.x = ___arg1; a.y = ___arg2; ___result = a;")) 3) If we give the address of a stack-allocated value to ___result_voidstar the allocation loop is running with constant memory space but the programm will segfault after quiting with CTRL + X. (define make-point (c-lambda (int int) struct-point "point a; a.x = ___arg1; a.y = ___arg2; ___result_voidstar = &a;")) For more details, see discussion: https://mercure.iro.umontreal.ca/pipermail/gambit-list/2013-August/006950.html 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
Aha.
Very well, then I guess it's good time to ask Marc how this stuff works really. :))
Marc, would you feel like enlightening us on this one - how use and reclaim of non-pointered FFI structs works out?
Thanks, Mikael
2013/8/22 Chris Mueller ruunsmail@gmail.com
Good point.
But gsc / gcc are reclaiming ___result_voidstar is of type void* and has no elements x and y therefore.
Manually casting to struct point* is of course possible, but will result in an expected segmentation fault during the execution of the script.
On 22.08.2013 08:34, Mikael wrote:
What about you presume that ___result_voidstar is already allocated, and you just access/mutate it? I.e.
(define make-point (c-lambda (int int) struct-point "___result_voidstar->.x = ___arg1; ___result_voidstar->y = ___arg2;"))
?
2013/8/22 Chris Mueller <ruunsmail@gmail.com <mailto:ruunsmail@gmail.com
I'm opening a new subject for the ffi struct issue to sum up the
current
discussion: In 19.1 "The Mapping of types between C and Scheme" of the gambit documentation is mentioned: "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)’. In many situations the
default
release-function will perform the appropriate cleanup for the foreign type." If i interpret this correctly, a declared struct type in a ffi
provides
a default release function that automatically calls a destructor
(used
with g++) and frees the corresponding memory. Unfortanetly, i'm little lost to use it correctly and experiment currently heavily to find the right way. Assume a type: (c-declare "struct point { int x; int y; };") (c-define-type struct-point (struct "point")) Assume a test programm that allocates a point 1_000_000_000 times. (define (alloc-point times) (let loop ((i 0)) (if (< i times) (let ((a (make-point 0 0))) (loop (+ i 1))))))) (alloc-point 1000000000) How do we implement (make-point x y) to use a ffi struct type with a default release function in Gambit? 1) With a manually allocated pointer it will leak memory. (define make-point (c-lambda (int int) struct-point "point* a = new Point; a->x = ___arg1; a->y = ___arg2; ___result_voidstar = a;")) 2) With a stack-allocated value it will segfault immediately. (define make-point (c-lambda (int int) struct-point "point a; a.x = ___arg1; a.y = ___arg2; ___result = a;")) 3) If we give the address of a stack-allocated value to ___result_voidstar the allocation loop is running with constant
memory
space but the programm will segfault after quiting with CTRL + X. (define make-point (c-lambda (int int) struct-point "point a; a.x = ___arg1; a.y = ___arg2; ___result_voidstar = &a;")) For more details, see discussion:
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2013-August/006950.ht...
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
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 2013-08-22, at 9:20 AM, Mikael mikael.rcv@gmail.com wrote:
Aha.
Very well, then I guess it's good time to ask Marc how this stuff works really. :))
Marc, would you feel like enlightening us on this one - how use and reclaim of non-pointered FFI structs works out?
I tested this code and it works fine:
(declare (standard-bindings) (fixnum) (not safe))
(c-declare #<<end-of-c-declare
struct point { int x; int y; };
struct point make_point( int x, int y ) {
struct point p; p.x = x; p.y = y;
return p; }
end-of-c-declare )
(c-define-type struct-point (struct "point"))
(define make-point (c-lambda (int int) struct-point "make_point"))
(define make-point2 ;; this should be equivalent but triggers a bug in Gambit (c-lambda (int int) struct-point "struct point p; p.x = ___arg1; p.y = ___arg2; ___result = p;"))
(define (alloc-points times) (let loop ((i 0)) (if (< i times) (let ((p (make-point 0 0))) (loop (+ i 1))))))
(time (alloc-points 100000000))
Deallocation of the structures is done correctly and there is no memory leak or segmentation faults. If the return type had been a C++ class, the destructor would have been called just prior to its deallocation by the GC, as expected.
There seems to be a problem however in the "inline" c-lambda form (as used in the definition of make-point2). The definition should be equivalent to the definition of make-point, but isn't. That's a bug that I will investigate.
I suggest that for the time being, you avoid using inline c-lambda forms that return structures. This means you will have to create a C function that returns a structure, and use the plain c-lambda form to interface to that C function.
Marc
On 22.08.2013 16:53, Marc Feeley wrote:
Deallocation of the structures is done correctly and there is no memory leak or segmentation faults. If the return type had been a C++ class, the destructor would have been called just prior to its deallocation by the GC, as expected.
There seems to be a problem however in the "inline" c-lambda form (as used in the definition of make-point2). The definition should be equivalent to the definition of make-point, but isn't. That's a bug that I will investigate.
I suggest that for the time being, you avoid using inline c-lambda forms that return structures. This means you will have to create a C function that returns a structure, and use the plain c-lambda form to interface to that C function.
Marc
Okay, that makes definitely sense :-D
thanks for your clarification, Marc.
Chris