It appears that if a POLLHUP event is returned from poll() (e.g. in wait_read()), then it will be returned to the caller.
In readtms(), which calls wait_read(), it then proceeds to call recv().
It seems (at least sometimes) that this causes recv to return a ETIMEDOUT, which is reported back to the client.
The client/user sees a "readtms(timeoutms=%d)" Connection timed out exception, which is confusing, especially when the timeout is significantly longer than the time it took to hit the poll event.