Use poll(3) and self pipe for signal handling.

Actually safe to perform the terminal cleanup here. We keep using
exit(3) and quick_exit(3) so that only one of them actually prints the
results to the screen.
This commit is contained in:
Érico Nogueira 2022-08-12 05:38:56 -03:00
parent a0ce797775
commit b734660c96
2 changed files with 44 additions and 11 deletions

51
ef.c
View File

@ -7,6 +7,8 @@
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include <poll.h>
#include <errno.h>
#include <locale.h>
#include <curses.h>
@ -17,6 +19,7 @@
static void endwin_void(void)
{
endwin();
fflush(stdout);
}
static const char *final_name;
@ -26,10 +29,10 @@ static void print_name(void)
if (stdout_save && final_name) fputs(final_name, stdout_save);
}
static void finish(int sig)
static int signal_pipe[2];
static void signal_handler(int signum)
{
(void)sig;
quick_exit(1);
write(signal_pipe[1], &signum, sizeof signum);
}
int main()
@ -38,6 +41,15 @@ int main()
const char delim = '\n';
if (pipe(signal_pipe)) {
perror("pipe");
exit(1);
}
if (signal(SIGINT, signal_handler) || signal(SIGTERM, signal_handler)) {
perror("signal");
exit(1);
}
struct str_array entries = { 0 };
read_entries_from_stream(&entries, delim, stdin);
/* fast exit cases */
@ -63,14 +75,18 @@ int main()
}
close(tty_fd);
atexit(print_name);
enum { SIGNAL, STDIN, POLLFD_AMOUNT };
struct pollfd polls[POLLFD_AMOUNT] = {
[SIGNAL] = {signal_pipe[0], POLLIN, 0},
[STDIN] = {STDIN_FILENO, POLLIN, 0},
};
signal(SIGINT, finish);
atexit(endwin_void);
at_quick_exit(endwin_void);
atexit(print_name);
/* curses initialization */
initscr();
at_quick_exit(endwin_void);
atexit(endwin_void);
/* terminal configuration */
nonl();
cbreak();
@ -117,7 +133,7 @@ int main()
WINDOW *prompt = newwin(1, 0, LINES - 1, 0);
if (!list || !prompt) {
perror("newwin");
exit(1);
quick_exit(1);
}
keypad(prompt, TRUE);
@ -144,6 +160,23 @@ int main()
/* index inside set of matches */
size_t index_in_matched = 0;
for (;;) {
if (poll(polls, POLLFD_AMOUNT, -1) < 0) {
if (errno == EINTR) continue;
perror("poll");
quick_exit(1);
}
if (polls[SIGNAL].revents & POLLIN) {
int signum;
read(polls[SIGNAL].fd, &signum, sizeof signum);
if (signum == SIGINT || signum == SIGTERM) {
quick_exit(1);
}
}
if (!(polls[STDIN].revents & POLLIN)) continue;
if (!name) {
cap = 1024;
name = xmalloc(cap);
@ -157,7 +190,7 @@ int main()
int c = wgetch(prompt);
switch (c) {
case 27: /* Ctrl+[ or ESC */
exit(1);
quick_exit(1);
break;
case KEY_ENTER:

4
util.c
View File

@ -26,12 +26,12 @@ void *xmalloc(size_t s) {
void *r = malloc(s);
if (r) return r;
perror("malloc");
exit(1);
quick_exit(1);
}
void *xrealloc(void *p, size_t s) {
void *r = realloc(p, s);
if (r) return r;
perror("realloc");
exit(1);
quick_exit(1);
}