ref: ad9748422e740128174f51090d7ca776681569ac
parent: 0f9c172712e834b8f45630a9665f2e271161692c
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Mar 24 16:37:01 EDT 2024
kernel: Fix qio flow control There is a pathological case with qio that triggers a dead-lock for single threaded servers and multiple requesters that can be reproduced like this: int pfd[2]; void main(int argc, char *argv[]) { char buf[0x10000]; int i, n; ARGBEGIN { } ARGEND; if(pipe(pfd) < 0) sysfatal("pipe: %r"); if(fork() == 0){ while((n = read(pfd[0], buf, sizeof(buf))) > 0){ sleep(10); write(pfd[0], buf, n); } exits(nil); } for(i = 0; i < PROCS; i++){ if(fork() == 0){ buf[0] = i; for(;;){ write(pfd[1], buf, sizeof(buf)); if(read(pfd[1], buf, sizeof(buf)) <= 0) break; print("%d %d\n", i, buf[0]); } exits(nil); } } waitpid(); } The problem is how the reader decides to wake up the writer, which was based only on the global queue length, but it should really depend on the local queuing position of the writers and their distance to the reader position. Otherwise, a writer can be blocked even tho its message has already been consumed by the reader. When the reader tries to reply, it can get blocked himself on writing the reply. The new qio code basically makes sure that writers get unblocked in order avoiding the issue. The qio block statistics and qwindow() are gone now as they where mostly unused.