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

4
util.c
View File

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