5 ms·
errno is thread-local, so you don’t have to worry about context switches.
by comex 4y ago
errno is thread-local, so you don’t have to worry about context switches.
- pjmlp 4y agoYou won't find that on either ISO C nor POSIX specifications. It only happens to be implemented that way in some environments, as a macro to either thread local or some function call that retrieves the right errno. Still, even that doesn't take care about signal handling.
- xeeeeeeeeeeenu 4y agoExcerpt from C11: "[...] errno which expands to a modifiable lvalue that has type int and thread local storage duration"
- pjmlp 4y agoStill doesn't cover signals, only works if C11 threads are being used (it is all open if OS threads follow the same TLS mechanism), and those C89 and C99 code bases get nothing from it anyway.
- quietbritishjim 4y agoIn practice it works with major thread implementations even before C11, even though it doesn't say so in the standard. You can't call OS functions from a signal handler so I can't see why signals would matter. Have I missed something?
- cesarb 4y ago> You can't call OS functions from a signal handler You can, as long as these functions are "async signal safe", see https://man7.org/linux/man-pages/man7/signal-safety.7.html https://man7.org/linux/man-pages/man7/signal-safety.7.html for details.
- quietbritishjim 4y agoOh wow. I mean, fair enough for simple utilities like strlen(). But open(), write(), close()? I had no idea.
- pjmlp 4y agoYou can, it is UB in what might happen, you either get lucky, or not. Don't expect a compiler error, this is C, where the programmer knows best.
- jstimpfle 4y agoYou can call any system function that is marked as async-signal-safe. Whether that's a great idea is a different question. > Don't expect a compiler error, this is C, where the programmer knows best. As for this snark, these considerations are pretty much OS and concurrency stuff that transcend any implementation language [0]. No one prevents you to switch back to single-threaded cushy OOP-y Javascript, however note that someone has to implement and run that for you. [0] yes, signals aren't beautiful, and in 2023 a beautifully designed OS might better do delivery of asynchronous messages using event handling and/or using dedicated threads. However, that's computing history for you, and it can be worked with. If you don't like it find a different platform. C doesn't really require signals, and if you use Unix with a different language, signals won't just go away.
- pjmlp 4y agoIndeed, "Transcending POSIX: The End of an Era?" https://www.usenix.org/publications/loginonline/transcending-posix-end-era https://www.usenix.org/publications/loginonline/transcending...
- jstimpfle 4y agoSo you're going back to URL firing mode, instead of making clear statements that are reasonably backed up?
- unwind 4y agoThis [1] seems to contradict, that at least for more "recent" versions of POSIX. [1]: https://unix.org/whitepapers/reentrant.html https://unix.org/whitepapers/reentrant.html
- pjmlp 4y agoThat isn't the most recent version, this is, https://pubs.opengroup.org/onlinepubs/9699919799/functions/errno.html https://pubs.opengroup.org/onlinepubs/9699919799/functions/e...
- jstimpfle 4y agoThat's a total strawman. Errno has nothing to do with signal handling at all. While errno is archaic, it is a completely sound design. That you need to be very careful in signal handlers is common knowledge, and obvious from what they do; signals handlers as a first approximation behave like executed in a separate thread, but even worse since they hijack a running thread and thus block the hijacked thread from executing the previously running code. (So you could say they're like fibers / cooperative multitasking?) The bottom line is, you can't touch errno in your signal handler, obviously -- just like you can't printf() or any other thing that has "critical sections". And since you don't do that, you're safe. By the way, signal handler safety is specified in POSIX and/or various other documents to a degree that neither I nor you seem to have cared to research properly. https://www.gnu.org/software/libc/manual/html_node/POSIX-Safety-Concepts.html https://www.gnu.org/software/libc/manual/html_node/POSIX-Saf... BTW2: I noticed on that page that errno is explicitly mentioned, but obviously only as an example of modifying thread-local data in a signal handler. As the docs point out, any such modified data must be restored before leaving the signal handler as to not pending code running on that thread. So in that sense, thread-local variable like errno are "safer" for than functions like printf() that take locks -- you _can_ touch them in a signal handler but you need to restore them.
- pjmlp 4y agoYou call it a strawman, I call it knowing what matters when writing portable code across multiple platforms and compilers. You will notice that I have linked Open Group errno documentation in another post. That is what matters, not what GNU thinks.
- jstimpfle 4y agoSo, what does matter? What is your actual statement? That you can't use errno in a multi-threaded environment? That you can't use errno in the presence of signal handlers? What exactly is your complaint about the GNU link? As far as I can see it more or less regurgitates what POSIX has to say about async-signal-safety. You made some vague statements that a mechanism that is used on billions of devices is fundamentally unsound, while providing no evidence other than maintaining that it would break in conjunction with signal handlers -- when signal handlers are expressly to be used with caution, no matter what you intend to touch. If you worry that you can't safely touch errno in a signal handler (provided that you reset it) on some broken platform from decades ago, because a spec like this [0] is too much swallow (understandably so, since this spec is a futile attempt to reconcile all the relevant history into a useful document), then I have a solution... Don't touch errno in a signal handler, which is probably solid practical advice anyway. Oh, and how do you reconcile the fact that many syscalls are declared async-safe by POSIX that may set errno themselves? "Operations which obtain the value of errno and operations which assign a value to errno shall be async-signal-safe, provided that the signal-catching function saves the value of errno upon entry and restores it before it returns." Tada! [0] https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03 https://pubs.opengroup.org/onlinepubs/9699919799/functions/V...
- Someone 4y agoHistorically, it wasn’t (of course; Unix didn’t have multiple threads in a program). https://pubs.opengroup.org/onlinepubs/7908799/xsh/errno.html https://pubs.opengroup.org/onlinepubs/7908799/xsh/errno.html: “Previously both POSIX and X/Open documents were more restrictive than the ISO C standard in that they required errno to be defined as an external variable, whereas the ISO C standard required only that errno be defined as a modifiable lvalue with type int.” Even now that it is guaranteed to be thread-local, it still is a bad API because of (same page) “A program that uses errno for error checking should set it to 0 before a function call” And yes, that still seems true today. https://en.cppreference.com/w/cpp/error/errno https://en.cppreference.com/w/cpp/error/errno: “library functions never store 0 in errno.”
- masklinn 4y agoThat library functions don’t reset errno is considered a feature / convenience, it allows calling a bunch of them then checking if the entire thing succeeded or failed. Obviously this assumes the failure of one function does not trigger a UB down the line, and that you care about general but not specific failure. And also obviously this is easy to replicate with an API which returns error objects / codes. IIRC this is most(ly) convenient in graphics APIs, I don’t know how common leveraging this in the libc actually is.
- Someone 4y agoIt also requires code to explicitly set errno many, many times. I think there are many errors lurking in C code there, with code calling foo, not checking errno or checking it but not resetting it, later calling bar, and assuming errno was set by bar.
- masklinn 4y ago> It also requires code to explicitly set errno many, many times. Yes, errno should be cleared every time you want to check it. Although you can check it multiple times with a single clear, as long as a set errno leads to an exit. A more likely cause if the issue you outline is that errno is not context-local tho, so if you call something which causes errno to be set you might get an errno from an unexpected error. This is similar to overly broad exception contexts, but much harder to diagnose.