[TUHS] the true reason why c++ always wins

Bakul Shah via TUHS tuhs at tuhs.org
Thu May 28 15:41:41 AEST 2026


While I am a fan of microkernels, they won't solve the
problem of EINTR.  The real issue is that completion of such
a syscall is *beyond* the control of the process. The call is
not necessarily *slow*, it is just that it may or not
eventually finish. No matter how you construct your software,
this situation doesn't go away. If you only return control
*after* reading an entire buffer's worth from the net, the
user will be quite frustrated their ^C will have no effect.
There is no timeout constant that is right either. Let the
user decide whether they want to wait for ever or abort. 


> On May 27, 2026, at 9:01 PM, G. Branden Robinson via TUHS <tuhs at tuhs.org> wrote:
> 
> At 2026-05-27T18:43:09-0700, al kossow via TUHS wrote:
>> https://www.youtube.com/watch?v=I7fEsbksKRE
>> 
>> this video is disturbing at so many levels
> 
> Lacking patience, I read the transcript instead.
> 
>> if you follow the Gabriel paper links, the one missing is
>> 
>> https://blog.reverberate.org/2011/04/eintr-and-pc-loser-ing-is-better-case.html
> 
> This is a good resource, and sheds much light on a frustrating problem.
> 
> For me, the heart of the matter is this quote of Stevens's _APUE_:
> 
>>> A characteristic of earlier UNIX systems is that if a process caught
>>> a signal while the process was blocked in a "slow" system call, the
>>> system call was interrupted.  The system call returned an error and
>>> `errno` was set to `EINTR`.  This was done under the assumption that
>>> since a signal occurred and the process caught it, there is a good
>>> chance that something has happened that should wake up the blocked
>>> system call. [...]  The problem with interrupted system calls is that
>>> we now have to handle the error return explicitly.
> 
> I submit that there are couple of ways to cut this Gordian Knot, one
> "pragmatic", and one fundamental.  The pragmatic one could have been
> done, to all our benefit, ages ago.
> 
> The pragmatic solution
> ----------------------
> 
> Better libraries.  Period.  Userspace programs generally shouldn't be
> making system calls directly.  Instead you should have a library that
> handles interfacing with the system for you.  A library API has more
> flexibility than the OS kernel, and (paradoxically) can _permit_ more
> flexibility in the system call interface by advertising "legacy" entry
> points for system calls that change their signatures or disappear.  (I
> propose that Unix's historical failure to provide any such thing is what
> prompted Linux Torvalds to proclaim his Iron Rule about not ever
> breaking userspace.[1]  With a library layer and a bit more type
> discipline than early C had, lseek(2) could have remained simply
> seek(2).  I think I've heard someone on this list observe that this is
> how Microsoft Windows (NT and its successors?) works.
> 
> I can imagine the objections.  (1) If Microsoft's doing it, it must be
> wrong.  Well, that's not a bad way to bet, but sometimes Microsoft does
> the right thing after first trying every wrong way they can think of,
> and eventually tiring of getting burned.  (2) "I'm a C programmer and
> I'm close to the metal and therefore I go straight to system calls".
> Fine, but then your app needs to do what the library would have been
> doing: having shims to abstract the version of the OS kernel, handling
> interrupted system calls, and so forth.
> 
> I think I've posted here before about how the grudging acceptance of a
> `-u` flag to cat(1) in Eighth Edition Unix, and the vigorous rejection
> of any _other_ flags to it, was a symptom of people not really thinking
> of that program as an application, but as a test apparatus for the
> kernel.  The latter is not, I submit, an appropriate first-order purpose
> for a user-facing application.  By _all_ means, ship a kernel-testing
> apparatus with the OS!  But it doesn't need to live in the $PATH.
> 
> If one accepts that perspective, the flutter of other flags waving from
> cat's tail becomes less offensive.
> 
> The fundamental solution
> ------------------------
> 
> ...arises from consideration of this clause of Stevens.
> 
> 'if a process caught a signal while the process was blocked in a "slow"
> system call'
> 
> My thesis: An OS kernel should not _have_ "slow" system calls.
> 
> The modern Linux kernel is festooned with things called "worker threads"
> in an attempt to solve the same problem.[2]  (I presume successfully.)
> But because Linux is still monolithic--and has to be, lest its lead
> author's now largely achieved objective of "world domination"[3] be
> squandered--it has an ever-growing set of worker threads as its
> revisions steadily find more things for idle cores to do.
> 
> This strategy isn't wrong or stupid, but in my view it quietly concedes
> an argument that Torvalds and his acolytes declared themselves as having
> prevailed in over 30 years ago.
> 
> You _could_ reach the same point, with more easily managed permission/
> security boundaries (I claim), by employing a microkernel design.
> 
> And let us please forever erase, or at least suffix a fat asterisk to,
> the name "Mach" from association with microkernels.  That was indeed the
> status its promulgators hoped for, but by starting with the BSD kernel
> and cutting it down, instead of building one up from nothing, they
> picked an approach that frustrated their objectives.
> 
> https://cs.nyu.edu/~mwalfish/classes/15fa/ref/liedtke93improving.pdf
> 
> Thus my enthusiasm for microkernels.  Yes, context switches are costly,
> and mode switches are more costly still.  Where these costs are
> unbearable, you either need more CPU, more memory, or to move away from
> a general-purpose OS kernel.  Solve your problem in a free-standing, not
> a hosted, runtime environment.
> 
> As we've seen, any proper engineering problem requires making tradeoffs
> somewhere.  (If it doesn't, it's an arithmetic problem.)  An OS kernel,
> in days of yore a "job monitor", was supposed to be a small, lean thing
> of minimal footprint that perturbed the availability of CPU cycles and
> RAM storage to the "real programs"--the _jobs_--as little as possible.
> 
> But if we count lines of code, monolithic (or semi-monolthic, "modular")
> kernels are some of the biggest software projects in the world, with the
> ones we've all heard of weighing in at tens of millions of lines.
> 
> https://interestingengineering.com/lists/whats-the-biggest-software-package-by-lines-of-code
> 
> Zero-copy operations are not a silver bullet, either.  They can be
> beautiful but you then have to spend more time considering whose
> responsibility it is to the validate the data in shared buffers, lest
> you end up with _no one_ taking responsibility for it...and suffering
> security pwnage.
> 
> While researching this message I happened across the following paper
> proposing a dedicated memory allocator for I/O operations in the Linux
> kernel.
> 
> https://netdevconf.info/0x15/papers/1/maio_netdev0x15.pdf
> 
> I don't know what has become of that work.  To me, the very existence of
> {e,}BPF is a concession that monokernels are too complex, and the
> proposed MAIO (from the foregoing paper) suggests the same.
> 
> All right, tell me how I'm wrong!  :)
> 
> Regards,
> Branden
> 
> [1] https://lkml.org/lkml/2012/12/23/75
> 
>    As is the way of iron rules, people have found ways to game them.
> 
>    https://lwn.net/Articles/1070072/
> 
> [2] https://docs.kernel.org/core-api/workqueue.html
> [3] https://www.linuxjournal.com/article/36



More information about the TUHS mailing list