1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
/* vi: set sw=4 ts=4: */
/*
* Utility routines.
*
* Copyright (C) 2025 Denys Vlasenko <vda.linux@googlemail.com>
*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
//kbuild:lib-y += poll_with_signals.o
#include "libbb.h"
/* Shells, for example, need their line input and "read" builtin
* to be interruptible, and the naive handling of it a-la:
* if (bb_got_signal) {
* errno = EINTR;
* return -1;
* }
* poll(pfd, 1, -1); // signal here would set EINTR
* is racy.
* This is a bit heavy-handed, but safe wrt races:
*/
int FAST_FUNC check_got_signal_and_poll(struct pollfd pfd[1], int timeout)
{
int n;
struct timespec tv;
sigset_t orig_mask;
if (bb_got_signal) /* optimization */
goto eintr;
if (timeout >= 0) {
tv.tv_sec = timeout / 1000;
tv.tv_nsec = (timeout % 1000) * 1000000;
}
/* test bb_got_signal, then poll(), atomically wrt signals */
sigfillset(&orig_mask);
sigprocmask2(SIG_BLOCK, &orig_mask);
if (bb_got_signal) {
sigprocmask2(SIG_SETMASK, &orig_mask);
eintr:
errno = EINTR; /* inform the caller that we got a signal */
return -1;
}
n = ppoll(pfd, 1, timeout >= 0 ? &tv : NULL, &orig_mask);
sigprocmask2(SIG_SETMASK, &orig_mask);
return n;
}
|