From a31b6a50b277c40f625f3c19ae6bec7cb1cd25f9 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Fri, 28 Aug 2026 11:31:07 +0800 Subject: [PATCH] Record that standard input is the handle zero, which one interface reserves The streams this implementation hands out are the environment's own descriptors, which is what openkal.stream's transfer operations take and what makes a stream it hands out interchangeable with one it received. Standard input is therefore the handle zero, and kal_spawn_streams reserves zero to mean "the stream the parent has". The two readings agree at position `in` --- placing standard input at standard input and inheriting it are the same act --- and cannot be told apart anywhere else. openkal-musl found it while answering openkal-linux#13: classifying "this descriptor has no stream" by the handle's VALUE refused every spawn. Nothing changes. Packing these three would make a stream this implementation hands out different in kind from the descriptors kal_fs_stream and kal_process_channel report, and the interface has no operation that would unpack it for a caller. The specification records the collision (mcpplibs/openkal#18) and openkal-musl refuses the one spawn it makes inexpressible; what was missing was a reader of this file being able to see any of that. --- src/stream.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/stream.cpp b/src/stream.cpp index a5d5bd8..3cd975c 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -3,6 +3,26 @@ extern "C" { +// THE STREAMS ARE THIS ENVIRONMENT'S OWN DESCRIPTORS AND ARE NOT PACKED, which +// is what `openkal.stream`'s transfer operations take and what makes a stream +// this implementation hands out interchangeable with one it received. +// +// ⚠️⚠️ ONE CONSEQUENCE, AND IT IS NOT VISIBLE FROM THIS FILE. Standard input is +// therefore the handle ZERO, and `kal_spawn_streams` reserves zero to mean +// "the stream the parent has" (openkal/process.h). The two readings agree at +// position `in` --- placing standard input at standard input and inheriting it +// are the same act --- and cannot be told apart anywhere else, so a caller that +// places its own standard input at position `out` is asking for something that +// structure cannot express. +// +// The specification records the collision and what a caller should do about it; +// openkal-musl refuses that spawn rather than passing on a word that would be +// read as inheritance. An implementation MAY remove the ambiguity for every +// caller by not answering any stream enquiry with zero, and this one does not: +// packing these three would make a stream this implementation hands out +// different in kind from the descriptors `kal_fs_stream` and +// `kal_process_channel` report, and the interface has no operation that would +// unpack it for the caller. kal_stream kal_stdin (void) { return kal_stream{0}; } kal_stream kal_stdout(void) { return kal_stream{1}; } kal_stream kal_stderr(void) { return kal_stream{2}; }