Summary
I was looking at how errno
, leave_blocking_section
and uerror
interact, and although it all seems to work on Linux, I couldn’t find any guarantees that errno
would indeed be preserved over leave_blocking_section
(and you cannot call uerror
without holding the runtime lock).
In fact POSIX says:
The value of errno should only be examined when it is indicated to be valid by a function’s return value
The setting of errno after a successful call to a function is unspecified unless the description of that function specifies that errno shall not be modified.
[This has similarities with how you must really get the backtrace of an exception immediately in the exception handler, before any other call had a chance to overwrite it. errno
should be handled in a similar way]
I looked at the manpages of pthread_mutex_lock
, and they don’t mention errno
at all (these functions return error codes instead of setting errno
, but the manpage is silent about whether they leave errno
unchanged or not).
But leave_blocking_section
does much more than that, it may end up calling functions in skiplist.c
, including malloc
. Although a failed malloc
would set errno
, the manpage again doesn’t specify that a succesful call doesn’t alter it.
In fact the way the OCaml runtime and C stubs typically use errno
seems to fall into the “common mistake” pattern as documented by the Linux manpage.
I wonder whether leave_blocking_section
should explicitly save/restore errno?
(In fact in OCaml 4.14 there used to be some code there that did something similar for Windows.)
P.S. the reason I looked into this is that I thought I observed a situation where errno
was set incorrectly. But I was fooled by a Unix_error(11, ...
error message being printed, where 11
was in fact EINTR
, and not errno 11
(EAGAIN), so errno
is correct in my application
[Edit] caml_leave_blocking_section
in runtime/signals.c
already does what I was suggesting since OCaml 4.01
I was mistakenly reading caml_thread_leave_blocking_section