ChezScheme icon indicating copy to clipboard operation
ChezScheme copied to clipboard

errno, threads, sockets et al.

Open amirouche opened this issue 3 years ago • 7 comments

Is it generally possible to query errno using C FFI?

amirouche avatar Feb 12 '21 16:02 amirouche

It is possible, but does Chez reset errno because for instance threads management or GC ?

amirouche avatar Feb 12 '21 16:02 amirouche

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.

amirouche avatar Feb 12 '21 18:02 amirouche

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.

cjfrisz avatar Feb 12 '21 18:02 cjfrisz

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.

jltaylor-us avatar Apr 01 '21 16:04 jltaylor-us

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.

We can have a saved-errno procedure as Racket did.

qzivli avatar Mar 08 '23 15:03 qzivli

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.

amirouche avatar Mar 23 '23 21:03 amirouche

We can have a saved-errno procedure 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))))

amirouche avatar Mar 23 '23 21:03 amirouche