]> git.tuebingen.mpg.de Git - paraslash.git/commit - server.c
Switch from select(2) to poll(2).
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 10 Oct 2021 20:18:24 +0000 (22:18 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 28 Aug 2022 15:36:05 +0000 (17:36 +0200)
commitcdbc8067a2e27ee7f9e0d8ff11cf415603fc0558
tree008c68fa9047d8ef9899739c0d4991bf586bd6a3
parente3a7e12639c34fd86d48a072beb48add8c498d09
Switch from select(2) to poll(2).

The select(2) API is kind of obsolete because it does not work for
file descriptors greater or equal than 1024, The general advice is
to switch to poll(2), which offers equivalent functionality and does
not suffer from this restriction. This patch implements this switch.

The fd sets of select(2) have one nice feature: One can determine in
O(1) time whether the bit for a given fd is turned on in an fd set.

For poll(2), the monitored file descriptors are organized in an array
of struct pollfd. Without information about the given fd's index in the
pollfd array, one can only perform a linear search which requires O(n)
time, with n being the number of fds being watched. Since this would
have to be done for each fd, the running time becomes quadratic in
the number of monitored fds, which is bad. Keeping the pollfd array
sorted would reduce that to n * log(n) at the cost of additional work
at insert time.

This patch implements a different approach. The scheduler now maintains
an additional array of unsigned integers which map fds to indices
into the pollfd array. This new index array is transparent to the
individual tasks, which still simply pass one or more fds from their
->pre_monitor() method to the scheduler. The length of the index array
equals the highest fd given. This might become prohibitive in theory,
but should not be an issue for the time being.

Care needs to be taken in order to deal with callers which ask for
the readiness of an fd without having called sched_monitor_readfd() or
sched_monitor_writefd() in the ->pre_monitor() step. Before the patch,
thanks to the FD_ZERO() call at the beginning of each iteration of
the scheduler's main loop, both sched_read_ok() and sched_write_ok()
returned false for fds which were not asked to be watched. We need
to keep it this way for a seamless transition.

We achieve this by replacing the FD_ZERO() call by a memset(3) call
which fills the index array with 0xff bytes. Both sched_read_ok() and
sched_write_ok() call the new get_revents() helper, where we check the
fd argument against the allocation sizes of the two arrays. If either
function is called with an fd that was not asked to be monitored in
the ->pre_monitor() step, the checks notice that the index of this
fd, 0xffffffff, is larger than the highest open fd and we return
"not ready for I/O".

Another issue is the case where the same file descriptor is submitted
twice in ->pre_monitor() to check for readiness with respect to both
reading and writing. The code in client_comon.c currently does that.
To keep it working, the scheduler needs to detect this case and re-use
the existing slot in both arrays.
13 files changed:
audioc.c
audiod.c
client.c
fd.c
fd.h
interactive.c
interactive.h
para.h
play.c
sched.c
sched.h
server.c
wmadec_filter.c