I've learned some interesting things about libpager that I'd like to share with the list.
I've found two bugs in the existing code that were "fixed" by the new demuxer that sequentially services requests on each pager object.
For example, the data return code sets a flag PAGINGOUT in the pagemap before it starts calling pager_write_page (which could be slow; writing to a hard drive, say). Future data returns check the PAGINGOUT flag and wait on a condition variable if it's set. The problem is that if multiple threads start waiting on that, pthreads doesn't guarantee what order they will run in when the conditional variable is signaled, so the data writes can get reordered. If three data returns come in 1, 2, 3, (maybe because pager_sync is called three times), number 1 starts writing, but if it doesn't finish quick enough, 2 and 3 can get reordered.
Except that they can't. The new demux code queues the second and third writes. They don't process until the first one is done. The pager object is essentially locked until the pager_write_page() completes.
I went so far as to write a test case to exercise the bug! Just good coding practice - develop tests for your known bugs first. Then I ran it, and it couldn't reproduce the bug! Only after thinking about the code more did I understand why.
I know the demuxer code was rewritten to avoid thread storms, but it's obviously got some issues and could become a performance bottleneck at some point. There's no good reason to block all access to page 100 while a disk operation completes on page 1. I'm not looking to re-write it right now, but I'm curious. Does anybody remember what characterized the thread storms? What conditions triggered them? What kind of pager operations were being done?