|
| 1 | +# openkal: plan for industrial completeness |
| 2 | + |
| 3 | +This document plans the extension of openkal from its core set to a |
| 4 | +specification sufficient to host a C library, and through it the ordinary |
| 5 | +software of a hosted system. It does not restate the decisions already taken; |
| 6 | +those are recorded in [`2026-08-20-openkal-design.md`](2026-08-20-openkal-design.md) |
| 7 | +and in the specification itself, and this plan treats them as given. |
| 8 | + |
| 9 | +## 1. Method |
| 10 | + |
| 11 | +The interfaces are derived from the kinds of resource an execution environment |
| 12 | +provides. They are not derived from what a particular program calls. |
| 13 | + |
| 14 | +The distinction is not stylistic, and the specification already records why: a |
| 15 | +boundary shaped by one client acquires that client's assumptions and obliges |
| 16 | +every other environment to reproduce them. POSIX was shaped by the C library of |
| 17 | +its time; the first preview of the WebAssembly System Interface was shaped by |
| 18 | +POSIX; an openkal shaped by a compiler would be the third instance of the same |
| 19 | +error. |
| 20 | + |
| 21 | +Programs are therefore used to **validate** the derivation and never to produce |
| 22 | +it. A program that cannot be hosted indicates that a resource kind has been |
| 23 | +omitted or decomposed incorrectly. A program that can be hosted only by |
| 24 | +reproducing its own assumptions indicates nothing about openkal, and something |
| 25 | +about the program. |
| 26 | + |
| 27 | +### 1.1 The two validation subjects, and why they form a stack |
| 28 | + |
| 29 | +``` |
| 30 | + an ordinary POSIX program, such as the GCC toolchain |
| 31 | + │ the C standard library and POSIX |
| 32 | + ▼ |
| 33 | + musl, ported to openkal |
| 34 | + │ the openkal C application binary interface |
| 35 | + ▼ |
| 36 | + an openkal implementation: Linux, Windows, a microkernel, bare metal |
| 37 | +``` |
| 38 | + |
| 39 | +The two subjects are not parallel. Porting a C library is the enabling work, |
| 40 | +and porting it once causes the software above it to run on every openkal |
| 41 | +implementation without further porting. The compiler is then an end-to-end |
| 42 | +check of that claim rather than a separate exercise. |
| 43 | + |
| 44 | +The arrangement also settles a question the derivation raises. A compiler |
| 45 | +assumes a global namespace of paths; that assumption is not universally |
| 46 | +satisfiable, since capability-based kernels and the second preview of the |
| 47 | +WebAssembly System Interface have no such namespace. The resolution of a path |
| 48 | +against a root the environment supplies is therefore work that belongs in the C |
| 49 | +library, performed once, rather than in every program or in the specification. |
| 50 | + |
| 51 | +### 1.2 Evidence gathered |
| 52 | + |
| 53 | +Measurements taken while preparing this plan. They inform coverage, which is a |
| 54 | +question about sufficiency; they do not inform shape. |
| 55 | + |
| 56 | +| Subject | Measurement | |
| 57 | +| --- | --- | |
| 58 | +| GCC driver and `cc1plus` | 189 undefined symbols, of which 149 face the environment | |
| 59 | +| Process creation in GCC | `posix_spawn` and `posix_spawnp`; neither `fork` nor `execve` appears | |
| 60 | +| Path operations in GCC | `open`, `stat`, `lstat`, `mkdir`, `unlink` alongside `fstatat`: a global namespace is assumed | |
| 61 | +| musl, static archive | file and directory operations 48, process and signal 21, memory 7, threads 81, time 8, network 23 | |
| 62 | +| musl thread construction | the pthread layer is built upon a wait-and-wake primitive rather than upon kernel mutexes | |
| 63 | + |
| 64 | +Two of these are load-bearing. |
| 65 | + |
| 66 | +The first is that GCC creates processes by spawning rather than by duplicating |
| 67 | +the calling image. A specification that copied the POSIX decomposition would |
| 68 | +have obliged an implementation on Windows to reproduce `fork`, which cannot be |
| 69 | +done faithfully, and would therefore have failed the specification's own |
| 70 | +admission criterion. The resource-derived form and the observed usage agree, |
| 71 | +which is corroboration rather than derivation. |
| 72 | + |
| 73 | +The second is that musl constructs mutexes and condition variables from a |
| 74 | +primitive that suspends an execution context until another context wakes it. |
| 75 | +The kernel boundary is therefore the primitive, and the synchronisation objects |
| 76 | +are library constructions above it. An interface offering mutexes would be |
| 77 | +placing a library at the kernel boundary. |
| 78 | + |
| 79 | +## 2. The four decisions this plan settles |
| 80 | + |
| 81 | +The core set is specified and published. Four questions were deferred, and each |
| 82 | +must be answered before the specification can host a C library. |
| 83 | + |
| 84 | +### 2.1 Optional capabilities |
| 85 | + |
| 86 | +An earlier draft deferred the mechanism. The rule adopted here follows from a |
| 87 | +distinction the specification already draws for another purpose. |
| 88 | + |
| 89 | +> An **operation** that an implementation may lack becomes an interface of its |
| 90 | +> own. A **property** that varies between implementations is reported by a |
| 91 | +> capability word. |
| 92 | +
|
| 93 | +The justification is that the two are not alike. An operation that is present |
| 94 | +and always fails is the defect the specification rejects in clause 6.4; the |
| 95 | +remedy is that its absence is expressed by its absence, which at the granularity |
| 96 | +of an interface means the linker reports it. A property, by contrast, cannot be |
| 97 | +called. Whether paths are compared case-sensitively, whether a clock advances |
| 98 | +while the machine is suspended, what the granularity of an allocation is: these |
| 99 | +are facts, and a program adapts to them rather than invoking them. |
| 100 | + |
| 101 | +Capability words are the ordinary mechanism of every system that has faced this |
| 102 | +question, including `sysconf`, `pathconf`, the auxiliary vector and the |
| 103 | +processor identification instruction. They are also the only mechanism available |
| 104 | +once the implementation is chosen at link time, which the specification's |
| 105 | +layering requires. |
| 106 | + |
| 107 | +Information therefore becomes available at three times, each being the earliest |
| 108 | +at which it exists. |
| 109 | + |
| 110 | +| Time | Mechanism | What it answers | |
| 111 | +| --- | --- | --- | |
| 112 | +| Dependency resolution | the implementation package declares the interfaces it provides | may this program be built against this implementation | |
| 113 | +| Link | an undefined symbol | was an interface used that the implementation does not provide | |
| 114 | +| Run | a capability word | how does this implementation behave within an interface it provides | |
| 115 | + |
| 116 | +### 2.2 Interfaces beyond the core |
| 117 | + |
| 118 | +Derived from resource kinds. The core set is unchanged. |
| 119 | + |
| 120 | +| Interface | Resource | Class | |
| 121 | +| --- | --- | --- | |
| 122 | +| `openkal.abort` | termination | core | |
| 123 | +| `openkal.memory` | a region of the address space | core | |
| 124 | +| `openkal.stream` | a byte stream | core | |
| 125 | +| `openkal.env` | the parameters a program receives at inception | standard | |
| 126 | +| `openkal.time` | a time source | standard | |
| 127 | +| `openkal.fs` | a directory, and an open file | standard | |
| 128 | +| `openkal.process` | a program image that has been started | standard | |
| 129 | +| `openkal.task` | an execution context, and a suspension primitive | standard | |
| 130 | +| `openkal.net` | an endpoint | optional | |
| 131 | +| `openkal.module` | a code image that has been loaded | optional | |
| 132 | +| `openkal.entropy` | a source of unpredictable bits | optional | |
| 133 | +| `openkal.event` | readiness of a set of resources | reserved | |
| 134 | + |
| 135 | +*Standard* denotes an interface an implementation hosting a C library provides. |
| 136 | +*Optional* denotes one it may omit without ceasing to host a C library, at the |
| 137 | +cost of the facilities built upon it. *Reserved* denotes a name whose contents |
| 138 | +are not yet normative. |
| 139 | + |
| 140 | +`openkal.event` is reserved rather than specified because readiness |
| 141 | +notification is the interface at which environments differ most, and because a |
| 142 | +C library can be hosted without it: blocking operations suffice, and the |
| 143 | +facilities that require readiness are those a program uses when it declines to |
| 144 | +block. Specifying it prematurely would produce an interface shaped by whichever |
| 145 | +environment was consulted first. |
| 146 | + |
| 147 | +#### 2.2.1 `openkal.fs` |
| 148 | + |
| 149 | +The resource is a directory or an open file, and operations are relative to a |
| 150 | +directory the program holds. There is no global namespace of paths. |
| 151 | + |
| 152 | +The reason is the admission criterion. A global namespace is not available in a |
| 153 | +capability-based kernel, and an implementation on such a kernel would have to |
| 154 | +construct one. Relative operations, by contrast, are natural on every |
| 155 | +environment considered: they are the primitive on capability systems, and on |
| 156 | +POSIX they are the `…at` family, which musl already uses to implement the |
| 157 | +global forms. |
| 158 | + |
| 159 | +The consequence is that the resolution of an absolute path is work performed by |
| 160 | +the C library against a root directory the environment supplies at inception. |
| 161 | +This is the arrangement the second preview of the WebAssembly System Interface |
| 162 | +adopts, and it is what allows a program to be confined without its cooperation. |
| 163 | + |
| 164 | +#### 2.2.2 `openkal.process` |
| 165 | + |
| 166 | +The resource is a program image that has been started. The operations are to |
| 167 | +start one, to wait for it, and to request its termination. |
| 168 | + |
| 169 | +Duplication of the calling image is not among them. It is not universally |
| 170 | +implementable, and the observed behaviour of the validation subject does not |
| 171 | +require it. |
| 172 | + |
| 173 | +#### 2.2.3 `openkal.task` |
| 174 | + |
| 175 | +The resource is an execution context sharing the address space, together with a |
| 176 | +primitive that suspends a context until another wakes it. |
| 177 | + |
| 178 | +Mutexes and condition variables are not among the operations. They are |
| 179 | +constructions above the primitive, as the measurement of musl demonstrates, and |
| 180 | +placing them at the kernel boundary would place a library there. |
| 181 | + |
| 182 | +### 2.3 Concurrency |
| 183 | + |
| 184 | +An implementation shall permit concurrent operations upon distinct handles. |
| 185 | + |
| 186 | +Concurrent operations upon one handle shall not damage the implementation's own |
| 187 | +state. The order in which they take effect, and whether the bytes of one |
| 188 | +transfer may be separated by those of another, are unspecified. |
| 189 | + |
| 190 | +Atomicity below a threshold, which POSIX guarantees for pipes, is not required. |
| 191 | +It is not universally implementable, and a specification that required it would |
| 192 | +oblige an implementation to introduce buffering it does not otherwise need. |
| 193 | + |
| 194 | +### 2.4 Ownership |
| 195 | + |
| 196 | +Handles obtained from the core interfaces are borrowed and are not released. |
| 197 | + |
| 198 | +Handles obtained from `openkal.fs`, `openkal.process`, `openkal.net` and |
| 199 | +`openkal.module` are owned, and each of those interfaces provides the operation |
| 200 | +that releases one. An implementation shall not treat a released handle as valid. |
| 201 | + |
| 202 | +The recommended construction divides the handle word into an index and a |
| 203 | +generation, incrementing the generation on release. The specification does not |
| 204 | +require it: it requires only the property, which this construction achieves |
| 205 | +without a lookup table and therefore without the compatibility layer that clause |
| 206 | +7.1 excludes. |
| 207 | + |
| 208 | +## 3. Work breakdown |
| 209 | + |
| 210 | +### 3.1 Groups and their dependencies |
| 211 | + |
| 212 | +``` |
| 213 | +S. specification: clauses for the four decisions ─┬─► I. interface modules ─┬─► L. Linux implementation ─┬─► M. musl port ──► G. compiler validation |
| 214 | + │ │ │ |
| 215 | + └─► C. conformance ──────┴────────────────────────────┘ |
| 216 | +``` |
| 217 | + |
| 218 | +| Group | Tasks | Depends upon | |
| 219 | +| --- | --- | --- | |
| 220 | +| S | capability rule, interface inventory, concurrency, ownership | this plan | |
| 221 | +| I | `env`, `time`, `fs`, `process`, `task` declaration modules | S | |
| 222 | +| L | the same five for Linux | I | |
| 223 | +| C | behavioural suites, surface comparison, capability-word agreement | I | |
| 224 | +| M | musl retargeted onto openkal | L, C | |
| 225 | +| G | the compiler built and run above the ported library | M | |
| 226 | + |
| 227 | +Groups I and C are independent of each other and both depend upon S. Group L |
| 228 | +may begin as soon as the declarations of a given interface exist, so the five |
| 229 | +interfaces proceed in parallel rather than in sequence. |
| 230 | + |
| 231 | +### 3.2 Sequence within an interface |
| 232 | + |
| 233 | +Each interface is taken through the same five steps, and the order is not |
| 234 | +interchangeable. |
| 235 | + |
| 236 | +1. State the resource and the operations that follow from it. |
| 237 | +2. Determine which operations may be absent, and separate those into their own |
| 238 | + interface. |
| 239 | +3. Determine which properties vary, and assign them positions in the capability |
| 240 | + word. |
| 241 | +4. Write the Linux implementation, which is where a decomposition error becomes |
| 242 | + visible. |
| 243 | +5. Write the conformance suite, which is where a claim becomes checkable. |
| 244 | + |
| 245 | +Step 4 precedes step 5 deliberately. The implementation of the core set |
| 246 | +demonstrated that a decomposition error is visible to an implementer and not to |
| 247 | +a reader of the specification: positioning was excluded from the stream |
| 248 | +interface by argument, and the exclusion was confirmed when the Linux |
| 249 | +implementation showed that positioning is a property of the individual |
| 250 | +descriptor. |
| 251 | + |
| 252 | +## 4. Assessment |
| 253 | + |
| 254 | +### 4.1 Architecture |
| 255 | + |
| 256 | +The interface remains the unit of provision and of versioning, and the |
| 257 | +specification retains ownership of every module. The extension adds interfaces; |
| 258 | +it does not add mechanisms, with the single exception of the capability word, |
| 259 | +which is confined to properties. |
| 260 | + |
| 261 | +### 4.2 Stability |
| 262 | + |
| 263 | +Structure layouts remain frozen. The capability word introduces a new obligation: |
| 264 | +a position once assigned retains its meaning, and a property that ceases to vary |
| 265 | +is not reclaimed. Unassigned positions are reserved and read as zero, so that a |
| 266 | +program compiled against a later specification behaves correctly against an |
| 267 | +earlier implementation. |
| 268 | + |
| 269 | +### 4.3 Simplicity |
| 270 | + |
| 271 | +The rule distinguishing operations from properties replaces the three mechanisms |
| 272 | +that were drafted and withdrawn: a record of capability flags, a configuration |
| 273 | +file that accompanied it, and a set of fallback overloads detected through |
| 274 | +argument-dependent lookup. Each was more elaborate than the rule that replaces |
| 275 | +them, and each solved a problem that a correct decomposition does not have. |
| 276 | + |
| 277 | +### 4.4 Consumer experience |
| 278 | + |
| 279 | +A program declares the interfaces it requires. A program built against an |
| 280 | +implementation that lacks one fails during dependency resolution, with the |
| 281 | +interface named. A program that reaches an interface it did not declare fails |
| 282 | +at link, with the function named. Neither failure is deferred to run time. |
| 283 | + |
| 284 | +### 4.5 Compatibility |
| 285 | + |
| 286 | +The core set does not change. An implementation of the core set that predates |
| 287 | +this extension remains conforming, and a program that uses only the core set is |
| 288 | +unaffected. |
| 289 | + |
| 290 | +### 4.6 Portability |
| 291 | + |
| 292 | +The interfaces are derived rather than borrowed, and each is checked against |
| 293 | +four environments before it is specified: a hosted system with a global |
| 294 | +namespace, a hosted system without one, a capability-based kernel, and a |
| 295 | +freestanding target. An interface that any of the four could satisfy only by |
| 296 | +constructing a compatibility layer is decomposed again rather than admitted. |
| 297 | + |
| 298 | +### 4.7 Upgrade |
| 299 | + |
| 300 | +An implementation adds interfaces without altering those it already provides. A |
| 301 | +program observes the addition through dependency resolution. No existing |
| 302 | +manifest requires modification. |
| 303 | + |
| 304 | +## 5. Criteria for completeness |
| 305 | + |
| 306 | +The extension is complete when the following hold. Each is an observation rather |
| 307 | +than a judgement. |
| 308 | + |
| 309 | +1. musl, retargeted onto openkal, builds and passes its own test suite against |
| 310 | + the Linux implementation. |
| 311 | +2. The compiler toolchain, built against that library, compiles and links a |
| 312 | + program, and the program runs. |
| 313 | +3. A second implementation exists for an environment without a global path |
| 314 | + namespace, and the same library binary interface is satisfied by it. |
| 315 | +4. The conformance suite verifies, for every interface, the behaviour of the |
| 316 | + operations provided, the absence of those not provided, and the agreement |
| 317 | + between each capability word and the behaviour it describes. |
| 318 | +5. No implementation requires a table, a registry or a name resolver in order to |
| 319 | + satisfy the specification. |
| 320 | + |
| 321 | +Criterion 3 is the one that distinguishes this work from a portable C library. |
| 322 | +A specification satisfied only by environments resembling the one it was written |
| 323 | +against has not been validated, however many programs it hosts. |
| 324 | + |
| 325 | +## 6. Matters this plan does not settle |
| 326 | + |
| 327 | +| Matter | Status | |
| 328 | +| --- | --- | |
| 329 | +| `openkal.event` | reserved; see 2.2 | |
| 330 | +| Symbol versioning | the evolution rule prohibits change rather than permitting coexistence, and an ecosystem that outgrows the prohibition will require a mechanism this specification does not define | |
| 331 | +| Locale and character encoding | properties of a C library rather than of a kernel boundary; the specification does not address them | |
| 332 | +| Signals as a general mechanism | the process interface provides termination; asynchronous delivery to a running program is deferred with `openkal.event` | |
0 commit comments