I have defined wrappers for openlog and syslog. The openlog function requires an ident string. Whatever I pass to openlog does not survive until a call to syslog. I have tried to protect the string with ##still-copy (with and without box/unbox) but it does not work. Here is the example:
(define const-ident #f)
(define openlog (let ((openlog (c-lambda (char-string int int) void "openlog"))) (lambda (ident option facility) (set! const-ident (box (##still-copy ident))) (openlog (unbox const-ident) option facility))))
(define syslog (let ((syslog (c-lambda (int nonnull-char-string) void "syslog"))) (lambda (priority . args) (syslog priority (apply string-append args)))))
This program:
(define (main . args) (openlog "gambit" (+ LOG_NDELAY LOG_PID) LOG_USER) (syslog LOG_INFO "hello") (closelog))
will generate random syslog tags:
Nov 21 17:58:49 sn-e0692 ��*#002[11621]: hello
What is the correct way to protect a string to be able to pass it to a const char* argument?
Afficher les réponses par date
I still do not understand ##still-copy but it is possible to protect the string on the C side. I have stored the syslog module here:
I finally understand the problem you were explaining. It is that openlog stores a pointer to the "ident" string that will be used in subsequent calls to syslog. It does not take a copy of the string. This means the C string which was converted from Scheme for the first argument of openlog must remain live after the call to openlog returns.
This can be accomplished by incrementing the reference count on the C string when openlog is called, and decrementing the reference count on the closelog call.
The FFI code must change from:
(define openlog (c-lambda (char-string int int) void "openlog"))
(define closelog (c-lambda () void "closelog"))
to something like this (untested):
(c-declare "static char *temp = NULL;")
(define openlog (c-lambda (char-string int int) void "if (temp != NULL) ___EXT(___release_string)(temp); temp = ___arg1; ___EXT(___addref_string)(___arg1); openlog(___arg1,___arg2,___arg3);"))
(define closelog (c-lambda () void "if (temp != NULL) ___EXT(___release_string)(temp); closelog();"))
Marc
On 2011-11-21, at 12:43 PM, Vok Vojwo wrote:
I have defined wrappers for openlog and syslog. The openlog function requires an ident string. Whatever I pass to openlog does not survive until a call to syslog. I have tried to protect the string with ##still-copy (with and without box/unbox) but it does not work. Here is the example:
(define const-ident #f)
(define openlog (let ((openlog (c-lambda (char-string int int) void "openlog"))) (lambda (ident option facility) (set! const-ident (box (##still-copy ident))) (openlog (unbox const-ident) option facility))))
(define syslog (let ((syslog (c-lambda (int nonnull-char-string) void "syslog"))) (lambda (priority . args) (syslog priority (apply string-append args)))))
This program:
(define (main . args) (openlog "gambit" (+ LOG_NDELAY LOG_PID) LOG_USER) (syslog LOG_INFO "hello") (closelog))
will generate random syslog tags:
Nov 21 17:58:49 sn-e0692 ��*#002[11621]: hello
What is the correct way to protect a string to be able to pass it to a const char* argument? _______________________________________________ Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 2011-12-12, at 11:20 AM, Marc Feeley wrote:
(define closelog (c-lambda () void "if (temp != NULL) ___EXT(___release_string)(temp); closelog();"))
Sorry, that should be:
(define closelog (c-lambda () void "if (temp != NULL) ___EXT(___release_string)(temp); temp = NULL; closelog();"))
Marc
2011/12/12 Marc Feeley feeley@iro.umontreal.ca:
I finally understand the problem you were explaining. It is that openlog stores a pointer to the "ident" string that will be used in subsequent calls to syslog. It does not take a copy of the string. This means the C string which was converted from Scheme for the first argument of openlog must remain live after the call to openlog returns.
Exactly.
This can be accomplished by incrementing the reference count on the C string when openlog is called, and decrementing the reference count on the closelog call.
Thank you for explaining this.
(c-declare "static char *temp = NULL;")
(define openlog (c-lambda (char-string int int) void "if (temp != NULL) ___EXT(___release_string)(temp); temp = ___arg1; ___EXT(___addref_string)(___arg1); openlog(___arg1,___arg2,___arg3);"))
(define closelog (c-lambda () void "if (temp != NULL) ___EXT(___release_string)(temp); closelog();"))
But how about the GC moving the string around? As far as I understood it is possible that the string in arg1 moves somewhere else. After that temp would not point to the string any more.
On 2011-12-14, at 5:10 AM, Vok Vojwo wrote:
2011/12/12 Marc Feeley feeley@iro.umontreal.ca:
I finally understand the problem you were explaining. It is that openlog stores a pointer to the "ident" string that will be used in subsequent calls to syslog. It does not take a copy of the string. This means the C string which was converted from Scheme for the first argument of openlog must remain live after the call to openlog returns.
Exactly.
This can be accomplished by incrementing the reference count on the C string when openlog is called, and decrementing the reference count on the closelog call.
Thank you for explaining this.
(c-declare "static char *temp = NULL;")
(define openlog (c-lambda (char-string int int) void "if (temp != NULL) ___EXT(___release_string)(temp); temp = ___arg1; ___EXT(___addref_string)(___arg1); openlog(___arg1,___arg2,___arg3);"))
(define closelog (c-lambda () void "if (temp != NULL) ___EXT(___release_string)(temp); closelog();"))
But how about the GC moving the string around? As far as I understood it is possible that the string in arg1 moves somewhere else. After that temp would not point to the string any more.
When a Scheme string is "converted" to a C string by the C-interface, it is a newly allocated object on the C heap. In other words, the object that C is receiving is unrelated to the Scheme object managed by the Gambit garbage-collector. The C string will *not* be moved around, but it does have a reference count which allows more control over the reclaiming of that string from the C side.
Marc
2011/12/14 Marc Feeley feeley@iro.umontreal.ca:
When a Scheme string is "converted" to a C string by the C-interface, it is a newly allocated object on the C heap. In other words, the object that C is receiving is unrelated to the Scheme object managed by the Gambit garbage-collector. The C string will *not* be moved around, but it does have a reference count which allows more control over the reclaiming of that string from the C side.
So there are two strings: one on the Scheme side and one on the C side. The one on the Scheme side probably does not have any Scheme references any more but has one reference coming from the C side.
Isn't this a bit much overhead to keep the string on the Scheme side, only to have a reference to the copy of the string on the C side?
And another question: if there are also references on the Scheme side to the string which get used to modify the string: will the C side know about the modification?
Example:
(let ((ident "A")) (openlog ident ...) (syslog "a") (set! ident "B") (syslog "b"))
Will the output be
A: a B: b
or
A: a A: b
?
2011/12/19 Sascha Ziemann ceving@gmail.com
2011/12/14 Marc Feeley feeley@iro.umontreal.ca:
When a Scheme string is "converted" to a C string by the C-interface, it
is a newly allocated object on the C heap. In other words, the object that C is receiving is unrelated to the Scheme object managed by the Gambit garbage-collector. The C string will *not* be moved around, but it does have a reference count which allows more control over the reclaiming of that string from the C side.
So there are two strings: one on the Scheme side and one on the C side. The one on the Scheme side probably does not have any Scheme references any more but has one reference coming from the C side.
Isn't this a bit much overhead to keep the string on the Scheme side, only to have a reference to the copy of the string on the C side?
You can access the Scheme string's content "raw" as well from C. The point with the conveniency wrapper into char* etc. in C, is to give you a latin1/utf8/etc. encoded character sequence rather than the internal 32bit/etc. unicode form.
And another question: if there are also references on the Scheme side to the string which get used to modify the string: will the C side know about the modification?
No afaik
Example:
(let ((ident "A")) (openlog ident ...) (syslog "a") (set! ident "B") (syslog "b"))
Will the output be
A: a B: b
or
A: a A: b
? _______________________________________________ Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list