Make ptmx non-blocking. Then, when writing data to the slave would
have blocked, use the FDM to asynchronously write the remaining data.
This is done by enabling EPOLLOUT on ptmx, and enqueueing all outgoing
data. The FDM handler will go through the enqueued data, and once all
of it has been written, we turn off EPOLLOUT again (thus switching
back to synchronous writes)
When checking of a 'foot --server' instance is already running, we try
to connect to the UNIX socket we're planning on listening on.
In most cases, this will fail hard and fast. But under certain
circumstances, we can get stuck in connect() waiting for a connection
timeout.
Since it should be possible to establish a connection immediately *if*
there's someone actually listening on the socket, rely on the fact
that connect() will fail with a EINPROGRESS if a connection can *not*
be established immediately (and thus no one is listening on it).
Since fonts are cached, this adds no additional memory. However, it
makes the first terminal window in --server mode start much faster,
since the (primary) fonts have already been loaded.
Fallback fonts are still loaded on-demand.
While unusual, it *is* possible for a client *not* to terminate when
we close ptmx.
We need to handle this *somehow*. Since it is so unusual, we'll go
with a fairly easy, but synchronous method:
* Register a signal handler for SIGALRM, and setup a 2 second alarm
* Wait for slave to die
* If it didn't die, sent SIGTERM, then re-set the alarm for another 2
seconds.
* If it still hasn't died, send SIGKILL (this time without an alarm).
When there hasn't been a timeout (or in our case, there was a timeout,
but we reset the timer before we got to the read()), read() returns,
not 0, but -1 with errno == EAGAIN.
Since we cancel the timers every now and then, there's a (small)
chance that one handler cancels a timer that has triggered in the same
epoll() iteration.
When this happens, read() blocks.
Fix by making the timer FDs non-blocking, and simply returning when we
read 0 bytes.
When we need to create a new buffer (because the cache doesn't have
any buffers of correct size, or because they're all busy), purge
buffers with a size mismatch.
Each font instance has a ref-counter. Whenever we want to instantiate
a font that has already been loaded, we instead return the
already-loaded instance, and bump the ref counter.
When the last font instance is destroyed, it is also removed from the
cache.