@mflatt If I have a native library that uses pthreads, lets the user set a callback, the callback goes to a Racket function, and the native library calls that callback from another thread, would that likely cause the Racket VM to segfault?
@leif Yes. See #:async-apply
for the way to solve that problem.
Ah, okay, that would explain a lot.
So that looks like its just a short function which is supposed to run quickly
That you can use to say, add something to a datastructure the main thread grabs.
At least that’s what it looks like to mel
me*
Would I put that on the callback _fun
type, or the function where I set the _fun
?
It’s a property of the callback
That makes sense, so in the case of: (define-libvid set-racket-log-callback
(_fun (_fun _pointer _int _string -> _void) -> _void))
It would go on the inner callback.
Or not, as this doesn’t seem to even print out ‘here’: (define-libvid set-racket-log-callback
(_fun (_fun #:async-apply (λ (th) (displayln "here") (th))
_pointer _int _string -> _void) -> _void))
so I’m going to look for examples.
Oh interesting, the only examples I see use it as a box.
There are non-box examples in “net/osx-ssl.rkt”
Hmm…that looks like what I was doing. Is it possible for the GC to collect a closure defined at the the module level?
(define and exported and immutable)
well, defined and exported and not set!
ed anyway.
no
unless the whole module instance is collected, which is unlikely
Ya, that’s what I thought. Oh well. :disappointed:
Ahhh…I’m not setting the keep flag propertly
properly*
BTW @mflatt the docs say: “…not suitable for a function used multiple times as a reatined callback”
I presume reatined -> retained, yes?
Oh wait, no. the function you can’t call multiple times is the set-callback function, not the callback itself.
Which means hmmph. I’m back to not know why I’m segfaulting. Thanks anyway. :slightly_smiling_face:
@mflatt I have a program that seems to expand differently in a sandbox vs. in a “real” top level REPL. Is this expected? Are the differences documented anywhere?
@lexi.lambda That shouldn’t normally happen, but it would be difficult to list all the ways that a namespace can be configured differently. Can you provide an example?
@leif Are you working in DrRacket or plain Racket? Going back to your earlier example, a (displayln "here")
definitely wouldn’t work in atomic mode in DrRacket, and it’s not ok in general, so the crash could be something like that.
@mflatt plain cmdline racket.
I thought it was only in automic mode if you give it #:automic? #t
The #:async-apply
callback is always in atomic mode
Ah okay.
Hmm…so I recompiled ffmpeg with pthreads explicitly disabled. And I”m still getting segfaults. So its probably something else.
@mflatt FWIW, here is the C half of the call: void (*racket_log_callback)(void*, int, const char*) = NULL;
void set_racket_log_callback(void (*callback)(void*, int, const char*)) {
racket_log_callback = callback;
}
And then later on: void ffmpeg_log_callback(void * avcl, int level, const char * fmt, va_list vl) {
int buffsize;
char *buff;
...
buffsize = ...
buff = malloc((buffsize + 1) * sizeof(char));
vsnprintf(buff, buffsize + 1, fmt, vl);
if(racket_log_callback) {
racket_log_callback(avcl, level, buff);
} else {
free(buff);
}
}
@mflatt I am having a hard time coming up with a way to reduce it to a minimal test case, but it happens with some Hackett code.
I’m starting a REPL with racket -iI hackett
and running the same code as with a sandbox created with (make-evaluator 'hackett #:require '((submod hackett configure-runtime)))
.
OH…interesting. If I call the callback within the function (rather than storing it for later), it works out just fine…
It seems to be the racket_log_callback = callback
that is problematic.
Which is odd because the function being passed in is a module level function.
AH, okay.
@samth It looks like a module level variable WILL get GCed.
And I suspect its a phase issue.
Right, if the whole module instance itself is collected
Yup, but it seems like it happens as part of compilation.
Although that could just be something strange I’m doing with my setup.
Its hard for me to tell.
Anyway, thanks. :slightly_smiling_face:
Now if only I could attach a will to a module itself…
@mflatt I managed to get a test case: #lang racket
(require racket/sandbox
syntax/location)
(module forms racket
(require (for-syntax racket/syntax)
syntax/parse/define)
(provide mac1)
(define-syntax-parser mac1
[(_)
#:with id (generate-temporary)
#'(define id (mac2 id))])
(define-syntax-parser mac2
[(_ id:id)
(local-expand #'id 'expression '())
#'(displayln "mac2" (current-error-port))]))
; works, prints "mac2"
(void (make-evaluator 'racket/base #:requires (list (quote-module-path forms)) '(mac1)))
; fails
(void ((make-evaluator 'racket/base #:requires (list (quote-module-path forms))) '(mac1)))
Adjusting the expansion of mac1
to use the (define-syntaxes (id) (values))
hack makes both work. But the fact that there is a difference is mysterious!
@lexi.lambda I see that this is yet another case where racket7
seems to behave better, so it’s likely a bug in module->namespace
handling in the current racket
; I should be able to look into it more tomorrow
@mflatt No worries, I worked around it with a define-syntaxes
forward declaration (and I would like to support existing Racket versions, anyway). Cool to see that racket7 is better here, though. :)
@vpm has joined the channel