Commit graph

27 commits

Author SHA1 Message Date
Craig Barnes
23cf80667a Explicitly initialize sigaction::sa_mask members with sigemptyset(3)
Not doing so before calling sigaction(3) is "undefined" according to
POSIX[1]:

> Applications shall call either sigemptyset() or sigfillset() at least
> once for each object of type sigset_t prior to any other use of that
> object. If such an object is not initialized in this way, but is
> nonetheless supplied as an argument to any of pthread_sigmask(),
> sigaction(), sigaddset(), sigdelset(), sigismember(), sigpending(),
> sigprocmask(), sigsuspend(), sigtimedwait(), sigwait(), or
> sigwaitinfo(), the results are undefined.

The use of designated initializers means that sa_mask members were
still being initialized, but sigset_t is an opaque type and implicit
initialization doesn't necessarily produce the same results as using
sigemptyset(3) (although it typically does on most implementations).

[1]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaddset.html
2022-02-12 12:26:42 +00:00
Daniel Eklöf
890dbc49cf
fdm: always check for signals after epoll_pwait(), not only on EINTR
This fixes an issue where we, at least on FreeBSD, sometimes get stuck
in epoll_pwait() after the shell has exited.

It turned out to be because the SIGCHLD signal was delivered at the
same time FDs were made readable/writeable. I.e. epoll_pwait()
returned a non-zero value even though it should have been interrupted
by the SIGCHLD.

To avoid having to search the entire signal array *every time*
epoll_pwait() returns, add a flag that is set in the signal
handler. This tells the FDM to scan the signal array after returning
from epoll_pwait().
2021-05-21 20:00:45 +02:00
Daniel Eklöf
dd5c31657e
spawn/slave: restore signal mask after fork
slave: no need to restore signal handlers; they are automatically
restored as long as they are not SIG_IGN (which they never are in
foot).

spawn(): restore signal mask after fork. This fixes an issue where a
terminal spawned with ctrl+shift+n did not terminate when its shell
exited.

Closes #366
2021-02-21 19:59:50 +01:00
Daniel Eklöf
863ae1143f
fdm: add support for managing signals
Add fdm_signal_add() and fdm_signal_del(). Signals added to the fdm
will be monitored, and the provided callback called as “soon as
possible” from the main context (i.e not from the signal handler
context).

Monitored signals are *blocked* by default. We use epoll_pwait() to
unblock them while we’re polling. This allows us to do race-free
signal detection.

We use a single handler for all monitored signals; the handler simply
updates the signal’s slot in a global array (sized to fit SIGRTMAX
signals).

When epoll_pwait() returns EINTR, we loop the global array. The
callback associated with each signal that fired is called.
2021-02-11 18:55:21 +01:00
Craig Barnes
3c86af52c2 Convert all but 2 remaining uses of xassert(false) to BUG("...") 2021-02-10 09:01:51 +00:00
Craig Barnes
1ec5684438 Convert some uses of xassert(false) to BUG("some error message") 2021-02-09 13:52:33 +00:00
Craig Barnes
e56136ce11 debug: rename assert() to xassert(), to avoid clashing with <assert.h> 2021-01-16 20:16:00 +00:00
Craig Barnes
22f25a9e4f Print stack trace on assert() failure or when calling fatal_error()
Note: this uses the __sanitizer_print_stack_trace() function from the
AddressSanitizer runtime, so it only works when AddressSanitizer is
in use.
2021-01-16 19:56:33 +00:00
Daniel Eklöf
384ba4d30d
fdm: do *not* keep polling on EINTR
This fixes an issue where foot --server did not exit on SIGINT. This
happened because we never returned out from fdm_poll(), and thus we
never saw ‘aborted’ being set.
2020-12-04 18:36:53 +01:00
Daniel Eklöf
15b35b7641
fdm: keep polling on EINTR 2020-11-26 18:23:01 +01:00
Daniel Eklöf
e32c0d9bf6
Cast printf formatter %p arguments to void* 2020-08-23 10:07:08 +02:00
Craig Barnes
7a77958ba2 Convert most dynamic allocations to use functions from xmalloc.h 2020-08-08 20:37:57 +01:00
Daniel Eklöf
a07de9ef3c
fdm: fix log message 2020-01-10 19:22:41 +01:00
Daniel Eklöf
698d5fdf06
fdm: verify FDs are non-blocking (debug builds only) 2020-01-10 19:22:10 +01:00
Daniel Eklöf
6534f64e6a
fdm: add hook priorities
There are now three hook priorities: low, normal, high.

High priority hooks are executed *first*. Normal next, and last the
low priority hooks.

The renderer's terminal refresh hook now runs as a normal priority
hook.
2020-01-04 23:26:27 +01:00
Daniel Eklöf
a3c18e72f5
fdm: add support for hooks
Hooks are functions executed just before going into a poll(). Or just
after executing all FD handlers, if you like.
2020-01-04 19:48:15 +01:00
Daniel Eklöf
5106937c7b
fdm: close fd even if we didn't find it in our list
This behavior is debatable, but helps in error handling where we're
removing a bunch of descriptors where not all of them have been added
to the FDM yet.
2019-12-15 15:06:09 +01:00
Daniel Eklöf
29cccadd1d
tllist: is now an external "library", so use <> includes 2019-11-17 19:19:55 +01:00
Daniel Eklöf
777d851282
fdm: invert check to get rid of one level of indentation 2019-11-03 00:52:24 +01:00
Daniel Eklöf
89997b97a0
fdm: add fdm_event_add() and fdm_event_del()
These functions allow users to modify already registered FDs, to add
or remove events they are interested in.
2019-11-03 00:52:24 +01:00
Daniel Eklöf
e09bda322a
fdm: bug: 'ret' was renamed to 'r', and replaced with another 'ret' 2019-11-03 00:51:47 +01:00
Daniel Eklöf
8ffa021de8
fdm: rename struct fd -> struct handler 2019-11-02 23:37:19 +01:00
Daniel Eklöf
9b67a6627a
fdm: fdm_destroy(): assert deferred delete list is empty 2019-11-02 23:36:02 +01:00
Daniel Eklöf
ba7f79af18
fdm: purge deferred delete list also when handler fails 2019-11-02 23:35:42 +01:00
Daniel Eklöf
c99c0285dc
fdm: fdm_poll(): disallow nested calls 2019-11-02 13:46:54 +01:00
Daniel Eklöf
80c4721e57
fdm: don't free FD data that may be referenced by epoll return data
It is perfectly possible, and legal, for a FDM handler to delete
another handler. The problem however is when the epoll returned array
of FD events contain the removed FD handler *after* the handler that
removed it.

That is, if the epoll returned array is:

  [FD=13, FD=37]

and the handler for FD=13 removes FD=37, then given the current
implementation, the FD user data (our handler callback etc) will point
to a free:d address.

Add support for this situation by deferring FD handler removal *when
called from another handler*.

This is done by "locking" the FDM struct before looping the handlers
for FDs with events (and unlocking afterwards).

In fdm_del(), we check if the FDM has been locked, in which case the
FD is marked as deleted, and put on a deferred list. But
not *actually* deleted.

Meanwhile, in the FDM poll function, we skip calling handlers for
marked-for-deletion FDs.

Then, when all FDs have been processed, we loop the deferred list and
finally deletes the FDs for real.
2019-11-01 19:51:33 +01:00
Daniel Eklöf
5fefb950b3
fdm: use the FDM's poll loop 2019-10-27 11:46:18 +01:00