ChezScheme
ChezScheme copied to clipboard
errno, threads, sockets et al.
Is it generally possible to query errno using C FFI?
It is possible, but does Chez reset errno because for instance threads management or GC ?
While greping the code I found out about the following:
> (#%$errno)
0
That means there is no need to bind errno using c ffi.
It is not documented.
Anything that's called using the #%$ prefix is a system procedure (see s/primdata.ss) and not guaranteed to have consistent behavior across versions or platforms. None of them are documented.
That said, it's possible this one could have a non-system counterpart that calls the system procedure $errno, but there could be a limitation I don't know off the top of my head.
I presume the reason for wanting to do this is so that you can write some code like
(some-foreign-function ...)
($errno)
The problem with this is that the garbage collector could run between those two calls (unless you've taken steps to disable it). Whether the default garbage collector does or does not ever reset errno is irrelevant, since the garbage collector is pluggable - so arbitrary behavior could be inserted there.
So, while #%$errno could be exposed and documented, it's almost certain to be used in an unsafe way (no matter how much documentation we write to encourage safe use, IMO).
If we were to go about trying to solve the problem of getting both the return value and final value of errno from a foreign call then that sounds a whole lot like multi-value return. We could explore adding something like foreign-procedure/errno to create a function that returns the two values when invoked.
If we were to go about trying to solve the problem of getting both the return value and final value of
errnofrom a foreign call then that sounds a whole lot like multi-value return. We could explore adding something likeforeign-procedure/errnoto create a function that returns the two values when invoked.
We can have a saved-errno procedure as Racket did.
I am using:
(define-syntax call/errno
(syntax-rules ()
[(_ thunk proc)
(with-interrupts-disabled
(let ([out (thunk)])
(let ((errno (#%$errno)))
(proc out errno))))]))
It works so far.
We can have a
saved-errnoprocedure as Racket did.
Quickly looking at Racket's code, I do not see how this can work without continuation marks / attachements.
Using liburing, transparent procedures (without async / await, nor continuations), and code that can be preempted with something like make-engine; user code looks like:
(call-with-values (lambda () (listen fd backlog)
(lambda (ok? why)
(unless ok?
(error 'listen "Listen on socket failed" fd backlog why)))
ok? is set when the underlying posix listen return -1. The problem is that before (unless ok? ...) is executed the continuation can be paused, because the timer expired. That works as expected because errno is not somekind of global.
Another way to put it, using the saved-errno route, given several execution flow can be interleaved, how is that supposed to work:
(listen fd backlog)
(when (saved-errno)
(error 'listen "listen failed with message" (errno-message (saved-errno))))