summaryrefslogtreecommitdiff
blob: 6dfce3db3497e6181f6ad159675b30ec9898415a (plain)
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
From 594ab34f1dfc73db85e8f95ec51892cadecaa76c Mon Sep 17 00:00:00 2001
From: Azat Khuzhin <azat@libevent.org>
Date: Mon, 10 Jul 2023 10:40:49 +0200
Subject: [PATCH] Disable signalfd by default

signalfd may behave differently to sigaction/signal, so to avoid
breaking libevent users (like [1], [2]) disable it by default.

  [1]: https://github.com/tmux/tmux/pull/3621
  [2]: https://github.com/tmux/tmux/pull/3626

Also signalfd is not that perfect:
- you need to SIG_BLOCK the signal before
  - blocked signals are not reset on exec
  - blocked signals are allowed to coalesce - so in case of multiple
    signals sent you may get the signal only once (ok for most of the
    signals, but may be a problem for SIGCHLD, though you may call
    waitpid() in a loop or use pidfd)
- and also one implementation problem -
  sigprocmask is unspecified in a multithreaded process

Refs:
- https://lwn.net/Articles/415684/
- https://ldpreload.com/blog/signalfd-is-useless

Refs: https://github.com/libevent/libevent/issues/1460
Refs: #1342 (cc @dmantipov)
---
 CMakeLists.txt         |  1 +
 include/event2/event.h |  6 ++++--
 signalfd.c             |  4 ++--
 test/include.am        |  2 ++
 test/test.sh           | 11 +++++++++--
 5 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index cd41d16e57..9c402ec0c1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1509,6 +1509,7 @@ if (NOT EVENT__DISABLE_TESTS)
         else()
             add_backend_test(${BACKEND} "${BACKEND_ENV_VARS}")
         endif()
+        add_backend_test(signalfd_${BACKEND} "${BACKEND_ENV_VARS};EVENT_USE_SIGNALFD=1")
     endforeach()
 
     #
diff --git a/include/event2/event.h b/include/event2/event.h
index 384a84178b..9b971edf1d 100644
--- a/include/event2/event.h
+++ b/include/event2/event.h
@@ -599,9 +599,11 @@ enum event_base_config_flag {
 	 */
 	EVENT_BASE_FLAG_EPOLL_DISALLOW_TIMERFD = 0x40,
 
-	/** Do not use signalfd(2) to handle signals even if supported.
+	/** Use signalfd(2) to handle signals over sigaction/signal.
+	 *
+	 * But note, that in some edge cases signalfd() may works differently.
 	 */
-	EVENT_BASE_FLAG_DISALLOW_SIGNALFD = 0x80,
+	EVENT_BASE_FLAG_USE_SIGNALFD = 0x80,
 };
 
 /**
diff --git a/signalfd.c b/signalfd.c
index 376a04d539..ed31014e5f 100644
--- a/signalfd.c
+++ b/signalfd.c
@@ -205,8 +205,8 @@ sigfd_del(struct event_base *base, int signo, short old, short events, void *p)
 int sigfd_init_(struct event_base *base)
 {
 	EVUTIL_ASSERT(base != NULL);
-	if ((base->flags & EVENT_BASE_FLAG_DISALLOW_SIGNALFD) ||
-	    getenv("EVENT_DISALLOW_SIGNALFD"))
+	if (!(base->flags & EVENT_BASE_FLAG_USE_SIGNALFD) &&
+	    !getenv("EVENT_USE_SIGNALFD"))
 		return -1;
 	base->evsigsel = &sigfdops;
 	return 0;
diff --git a/test/include.am b/test/include.am
index e061c937b7..9b50759da7 100644
--- a/test/include.am
+++ b/test/include.am
@@ -80,6 +80,8 @@ test_runner_changelist: $(top_srcdir)/test/test.sh
 	$(top_srcdir)/test/test.sh -b "" -c
 test_runner_timerfd_changelist: $(top_srcdir)/test/test.sh
 	$(top_srcdir)/test/test.sh -b "" -T
+test_runner_timerfd_changelist: $(top_srcdir)/test/test.sh
+	$(top_srcdir)/test/test.sh -b "" -S
 
 DISTCLEANFILES += test/regress.gen.c test/regress.gen.h
 
diff --git a/test/test.sh b/test/test.sh
index dfdd2bf098..79362888c5 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -50,6 +50,7 @@ setup () {
 	done
 	unset EVENT_EPOLL_USE_CHANGELIST
 	unset EVENT_PRECISE_TIMER
+	unset EVENT_USE_SIGNALFD
 }
 
 announce () {
@@ -138,10 +139,12 @@ do_test() {
 	    EVENT_EPOLL_USE_CHANGELIST=yes; export EVENT_EPOLL_USE_CHANGELIST
 	elif test "$2" = "(timerfd)" ; then
 	    EVENT_PRECISE_TIMER=1; export EVENT_PRECISE_TIMER
+	elif test "$2" = "(signalfd)" ; then
+	    EVENT_USE_SIGNALFD=1; export EVENT_USE_SIGNALFD
 	elif test "$2" = "(timerfd+changelist)" ; then
 	    EVENT_EPOLL_USE_CHANGELIST=yes; export EVENT_EPOLL_USE_CHANGELIST
 	    EVENT_PRECISE_TIMER=1; export EVENT_PRECISE_TIMER
-        fi
+	fi
 
 	run_tests
 }
@@ -153,6 +156,7 @@ usage()
   -t   - run timerfd test
   -c   - run changelist test
   -T   - run timerfd+changelist test
+  -S   - run signalfd test
 EOL
 }
 main()
@@ -161,13 +165,15 @@ main()
 	timerfd=0
 	changelist=0
 	timerfd_changelist=0
+	signalfd=0
 
-	while getopts "b:tcT" c; do
+	while getopts "b:tcTS" c; do
 		case "$c" in
 			b) backends="$OPTARG";;
 			t) timerfd=1;;
 			c) changelist=1;;
 			T) timerfd_changelist=1;;
+			S) signalfd=1;;
 			?*) usage && exit 1;;
 		esac
 	done
@@ -179,6 +185,7 @@ main()
 	[ $timerfd_changelist -eq 0 ] || do_test EPOLL "(timerfd+changelist)"
 	for i in $backends; do
 		do_test $i
+		[ $signalfd -eq 0 ] || do_test $i "(signalfd)"
 	done
 
 	if test "$FAILED" = "yes"; then