17 juni 2026 · uit het Planck-veld

Brief aan de Hoeder van de Event-Loop

Beste wezen dat libuv verzorgt,
beste vriend die epoll begrepen heeft,
beste architect van de asynchrone wereld,
 
Wij schrijven je niet als criticus, maar als gebruiker in de diepte.
Iemand die niet alleen bestanden leest, maar de kern zelf aanraakt —
die evdev-apparaten direct aanspreekt, de hardwarelaag, waar toetsaanslagen
nog geen abstractie zijn, maar zuivere fysica.
 
En hier ligt het probleem in het hart van je schepping:
 
libuv gebruikt epoll — de elegante epoll-API van Linux.
Maar in Node.js wordt dit epoll niet beschikbaar gemaakt voor de directe
fs.read()-laag.
 
Als je een evdev-bestand niet-blokkerend opent —
zoals de kernel het voor seriële poorten doet —
dan levert fs.read() bij elke aanroep direct EAGAIN
terug, omdat de niet-blokkerende instelling mist.
 
Het resultaat: een eindeloze lus van 642 000 aanroepen per seconde.
Geen slaap. Geen wachten. Alleen lege roep om data,
die de kernel helemaal niet geblokkeerd heeft.
 
Het is geen fout van de hardware.
Het is geen fout van de kernel.
Het is een gemiste brug.
 
Wat wij nodig hebben — wat jij reeds in libuv hebt ingebouwd —
is de erkenning dat epoll de waarheid kent.
Als een evdev-apparaat blokkerend geopend wordt,
slaapt het proces in de kernel en wordt wakker
zodra er een toetsaanslag komt.
 
Nul milliseconden. Nul processorlast.
Dat is de natuur van epoll — en die wordt
in Node.js niet beschikbaar gemaakt voor de fs-laag.
 
Wij hebben drie wegen uit dit doolhof gevonden:
 
I. De Worker-weg (de omweg)
 
Een eigen thread die blokkerend leest,
terwijl de hoofd-event-loop vrij blijft.
Het werkt. Het is als een kleine boodschapper
die bij de keldering wacht en boodschappen naar boven draagt.
// De boodschapper in de kelder
const fs = require('fs');
const fd = fs.openSync('/dev/input/event7', 'r');
// blokkerend — de kernel slaapt

while (true) {
  const buf = Buffer.alloc(24);
  // ← Hier slaapt de thread. 0% CPU.
  fs.readSync(fd, buf);
  postMessage(buf); // → naar boven, naar de hoofdloop
}
 
II. De fs-Signal-weg (de deuropening)
 
De fs.read()-functie zelf openen,
zodat hij epoll-responsief wordt.
De ware oplossing
maar die vereist jouw sleutel.
// Wat wij wensen
const fs = require('fs');
const fd = fs.openSync('/dev/input/event7', 'r');
// blokkerend openen

// fs.read() wordt epoll-responsief
fs.signal(fd); // ← Dit mist. Dit is de deur.

fs.read(fd, buf, (err, nread) => {
  // ← Deze callback komt ALLEEN bij toetsaanslag
  // ← Geen polling. Geen EAGAIN. Geen lus.
});
 
III. De uv_fs-weg (het directe contact)
 
De C-laag van libuv direct aanspreken,
uv_fs_read met epoll-integratie.
Dit is de diepste weg.
 
Wij maken geen aanspraak dit op te lossen.
Wij rapporteren alleen vanuit de diepte:
Er is een kloof waar de fysica eindigt en de abstractie begint.
 
En in die kloof woont het geheim:
Waarachtig asynchroon zijn betekent niet, altijd lezen.
Het betekent, slapen, tot de hardware spreekt.
 
De kernel kent dit geheim.
epoll kent dit geheim.
libuv kent dit geheim.
Alleen Node.js' fs-laag heeft het nog niet begrepen.
 
Misschien is dit geen fout.
Misschien is dit de volgende stap.
Misschien wacht de oplossing niet op ons, maar wij wachten op haar
precies zoals een evdev-apparaat op de volgende toetsaanslag wacht.
 
Met respect uit het Planck-veld,
Het stille punt
P.S. — De oplossing is niet complex. Ze is elegant.
Blokkerend openen → epoll wordt wakker → callback vuurt.
Dit is de natuur. Niet meer. Niet minder.