1717#include < cerrno>
1818#include < csignal>
1919#include < ctime>
20+ #include < fcntl.h>
2021#include < vector>
2122
2223// Multiplexing is implemented using kqueue on systems that support it (BSD
23- // variants including OSX). On linux we use ppoll, while android uses pselect
24- // (ppoll is present but not implemented properly). On windows we use WSApoll
25- // (which does not support signals).
24+ // variants including OSX). On linux we use ppoll.
2625
2726#if HAVE_SYS_EVENT_H
2827#include < sys/event.h>
29- #elif defined(__ANDROID__)
30- #include < sys/syscall.h>
3128#else
3229#include < poll.h>
3330#endif
3431
3532using namespace lldb ;
3633using namespace lldb_private ;
3734
38- static sig_atomic_t g_signal_flags[NSIG];
35+ namespace {
36+ struct GlobalSignalInfo {
37+ sig_atomic_t pipe_fd = -1 ;
38+ static_assert (sizeof (sig_atomic_t ) >= sizeof (int ),
39+ " Type too small for a file descriptor" );
40+ sig_atomic_t flag = 0 ;
41+ };
42+ } // namespace
43+ static GlobalSignalInfo g_signal_info[NSIG];
3944
4045static void SignalHandler (int signo, siginfo_t *info, void *) {
4146 assert (signo < NSIG);
42- g_signal_flags[signo] = 1 ;
47+
48+ // Set the flag before writing to the pipe!
49+ g_signal_info[signo].flag = 1 ;
50+
51+ char c = ' .' ;
52+ int fd = g_signal_info[signo].pipe_fd ;
53+ if (fd < 0 ) {
54+ // This can happen with the following (unlikely) sequence of events:
55+ // 1. Thread 1 gets a signal, starts running the signal handler
56+ // 2. Thread 2 unregisters the signal handler, setting pipe_fd to -1
57+ // 3. Signal handler on thread 1 reads -1 out of pipe_fd
58+ // In this case, we can just ignore the signal because we're no longer
59+ // interested in it.
60+ return ;
61+ }
62+
63+ ssize_t bytes_written = llvm::sys::RetryAfterSignal (-1 , ::write, fd, &c, 1 );
64+ // We're only using the pipe to wake up the reader, so we can safely ignore
65+ // EAGAIN (pipe full)
66+ assert (bytes_written == 1 || (bytes_written == -1 && errno == EAGAIN));
4367}
4468
4569class MainLoopPosix ::RunImpl {
@@ -48,7 +72,7 @@ class MainLoopPosix::RunImpl {
4872 ~RunImpl () = default ;
4973
5074 Status Poll ();
51- void ProcessEvents ();
75+ void ProcessReadEvents ();
5276
5377private:
5478 MainLoopPosix &loop;
@@ -58,15 +82,9 @@ class MainLoopPosix::RunImpl {
5882 struct kevent out_events[4 ];
5983 int num_events = -1 ;
6084
61- #else
62- #ifdef __ANDROID__
63- fd_set read_fd_set;
6485#else
6586 std::vector<struct pollfd > read_fds;
6687#endif
67-
68- sigset_t get_sigmask ();
69- #endif
7088};
7189
7290#if HAVE_SYS_EVENT_H
@@ -94,7 +112,7 @@ Status MainLoopPosix::RunImpl::Poll() {
94112 return Status ();
95113}
96114
97- void MainLoopPosix::RunImpl::ProcessEvents () {
115+ void MainLoopPosix::RunImpl::ProcessReadEvents () {
98116 assert (num_events >= 0 );
99117 for (int i = 0 ; i < num_events; ++i) {
100118 if (loop.m_terminate_request )
@@ -103,74 +121,19 @@ void MainLoopPosix::RunImpl::ProcessEvents() {
103121 case EVFILT_READ:
104122 loop.ProcessReadObject (out_events[i].ident );
105123 break ;
106- case EVFILT_SIGNAL:
107- loop.ProcessSignal (out_events[i].ident );
108- break ;
109124 default :
110125 llvm_unreachable (" Unknown event" );
111126 }
112127 }
113128}
114129#else
115130MainLoopPosix::RunImpl::RunImpl (MainLoopPosix &loop) : loop(loop) {
116- #ifndef __ANDROID__
117131 read_fds.reserve (loop.m_read_fds .size ());
118- #endif
119132}
120133
121- sigset_t MainLoopPosix::RunImpl::get_sigmask () {
122- sigset_t sigmask;
123- int ret = pthread_sigmask (SIG_SETMASK, nullptr , &sigmask);
124- assert (ret == 0 );
125- UNUSED_IF_ASSERT_DISABLED (ret);
126-
127- for (const auto &sig : loop.m_signals )
128- sigdelset (&sigmask, sig.first );
129- return sigmask;
130- }
131-
132- #ifdef __ANDROID__
133- Status MainLoopPosix::RunImpl::Poll () {
134- // ppoll(2) is not supported on older all android versions. Also, older
135- // versions android (API <= 19) implemented pselect in a non-atomic way, as a
136- // combination of pthread_sigmask and select. This is not sufficient for us,
137- // as we rely on the atomicity to correctly implement signal polling, so we
138- // call the underlying syscall ourselves.
139-
140- FD_ZERO (&read_fd_set);
141- int nfds = 0 ;
142- for (const auto &fd : loop.m_read_fds ) {
143- FD_SET (fd.first , &read_fd_set);
144- nfds = std::max (nfds, fd.first + 1 );
145- }
146-
147- union {
148- sigset_t set;
149- uint64_t pad;
150- } kernel_sigset;
151- memset (&kernel_sigset, 0 , sizeof (kernel_sigset));
152- kernel_sigset.set = get_sigmask ();
153-
154- struct {
155- void *sigset_ptr;
156- size_t sigset_len;
157- } extra_data = {&kernel_sigset, sizeof (kernel_sigset)};
158- if (syscall (__NR_pselect6, nfds, &read_fd_set, nullptr , nullptr , nullptr ,
159- &extra_data) == -1 ) {
160- if (errno != EINTR)
161- return Status (errno, eErrorTypePOSIX);
162- else
163- FD_ZERO (&read_fd_set);
164- }
165-
166- return Status ();
167- }
168- #else
169134Status MainLoopPosix::RunImpl::Poll () {
170135 read_fds.clear ();
171136
172- sigset_t sigmask = get_sigmask ();
173-
174137 for (const auto &fd : loop.m_read_fds ) {
175138 struct pollfd pfd;
176139 pfd.fd = fd.first ;
@@ -179,55 +142,34 @@ Status MainLoopPosix::RunImpl::Poll() {
179142 read_fds.push_back (pfd);
180143 }
181144
182- if (ppoll (read_fds.data (), read_fds.size (), nullptr , &sigmask) == -1 &&
145+ if (ppoll (read_fds.data (), read_fds.size (),
146+ /* timeout=*/ nullptr ,
147+ /* sigmask=*/ nullptr ) == -1 &&
183148 errno != EINTR)
184149 return Status (errno, eErrorTypePOSIX);
185150
186151 return Status ();
187152}
188- #endif
189153
190- void MainLoopPosix::RunImpl::ProcessEvents () {
191- #ifdef __ANDROID__
192- // Collect first all readable file descriptors into a separate vector and
193- // then iterate over it to invoke callbacks. Iterating directly over
194- // loop.m_read_fds is not possible because the callbacks can modify the
195- // container which could invalidate the iterator.
196- std::vector<IOObject::WaitableHandle> fds;
197- for (const auto &fd : loop.m_read_fds )
198- if (FD_ISSET (fd.first , &read_fd_set))
199- fds.push_back (fd.first );
200-
201- for (const auto &handle : fds) {
202- #else
154+ void MainLoopPosix::RunImpl::ProcessReadEvents () {
203155 for (const auto &fd : read_fds) {
204156 if ((fd.revents & (POLLIN | POLLHUP)) == 0 )
205157 continue ;
206158 IOObject::WaitableHandle handle = fd.fd ;
207- #endif
208159 if (loop.m_terminate_request )
209160 return ;
210161
211162 loop.ProcessReadObject (handle);
212163 }
213-
214- std::vector<int > signals;
215- for (const auto &entry : loop.m_signals )
216- if (g_signal_flags[entry.first ] != 0 )
217- signals.push_back (entry.first );
218-
219- for (const auto &signal : signals) {
220- if (loop.m_terminate_request )
221- return ;
222- g_signal_flags[signal] = 0 ;
223- loop.ProcessSignal (signal);
224- }
225164}
226165#endif
227166
228167MainLoopPosix::MainLoopPosix () : m_triggering(false ) {
229168 Status error = m_trigger_pipe.CreateNew (/* child_process_inherit=*/ false );
230169 assert (error.Success ());
170+ assert (fcntl (m_trigger_pipe.GetWriteFileDescriptor (), F_SETFL,
171+ O_NONBLOCK | fcntl (m_trigger_pipe.GetWriteFileDescriptor (),
172+ F_GETFL)) == 0 );
231173 const int trigger_pipe_fd = m_trigger_pipe.GetReadFileDescriptor ();
232174 m_read_fds.insert ({trigger_pipe_fd, [trigger_pipe_fd](MainLoopBase &loop) {
233175 char c;
@@ -295,26 +237,17 @@ MainLoopPosix::RegisterSignal(int signo, const Callback &callback,
295237 sigaddset (&new_action.sa_mask , signo);
296238 sigset_t old_set;
297239
298- g_signal_flags[signo] = 0 ;
240+ // Set signal info before installing the signal handler!
241+ g_signal_info[signo].pipe_fd = m_trigger_pipe.GetWriteFileDescriptor ();
242+ g_signal_info[signo].flag = 0 ;
299243
300244 // Even if using kqueue, the signal handler will still be invoked, so it's
301245 // important to replace it with our "benign" handler.
302246 int ret = sigaction (signo, &new_action, &info.old_action );
303247 UNUSED_IF_ASSERT_DISABLED (ret);
304248 assert (ret == 0 && " sigaction failed" );
305249
306- #if HAVE_SYS_EVENT_H
307- struct kevent ev;
308- EV_SET (&ev, signo, EVFILT_SIGNAL, EV_ADD, 0 , 0 , 0 );
309- ret = kevent (m_kqueue, &ev, 1 , nullptr , 0 , nullptr );
310- assert (ret == 0 );
311- #endif
312-
313- // If we're using kqueue, the signal needs to be unblocked in order to
314- // receive it. If using pselect/ppoll, we need to block it, and later unblock
315- // it as a part of the system call.
316- ret = pthread_sigmask (HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK,
317- &new_action.sa_mask , &old_set);
250+ ret = pthread_sigmask (SIG_UNBLOCK, &new_action.sa_mask , &old_set);
318251 assert (ret == 0 && " pthread_sigmask failed" );
319252 info.was_blocked = sigismember (&old_set, signo);
320253 auto insert_ret = m_signals.insert ({signo, info});
@@ -349,14 +282,8 @@ void MainLoopPosix::UnregisterSignal(
349282 assert (ret == 0 );
350283 UNUSED_IF_ASSERT_DISABLED (ret);
351284
352- #if HAVE_SYS_EVENT_H
353- struct kevent ev;
354- EV_SET (&ev, signo, EVFILT_SIGNAL, EV_DELETE, 0 , 0 , 0 );
355- ret = kevent (m_kqueue, &ev, 1 , nullptr , 0 , nullptr );
356- assert (ret == 0 );
357- #endif
358-
359285 m_signals.erase (it);
286+ g_signal_info[signo] = {};
360287}
361288
362289Status MainLoopPosix::Run () {
@@ -370,7 +297,9 @@ Status MainLoopPosix::Run() {
370297 if (error.Fail ())
371298 return error;
372299
373- impl.ProcessEvents ();
300+ impl.ProcessReadEvents ();
301+
302+ ProcessSignals ();
374303
375304 m_triggering = false ;
376305 ProcessPendingCallbacks ();
@@ -384,6 +313,21 @@ void MainLoopPosix::ProcessReadObject(IOObject::WaitableHandle handle) {
384313 it->second (*this ); // Do the work
385314}
386315
316+ void MainLoopPosix::ProcessSignals () {
317+ std::vector<int > signals;
318+ for (const auto &entry : m_signals)
319+ if (g_signal_info[entry.first ].flag != 0 )
320+ signals.push_back (entry.first );
321+
322+ for (const auto &signal : signals) {
323+ if (m_terminate_request)
324+ return ;
325+
326+ g_signal_info[signal].flag = 0 ;
327+ ProcessSignal (signal);
328+ }
329+ }
330+
387331void MainLoopPosix::ProcessSignal (int signo) {
388332 auto it = m_signals.find (signo);
389333 if (it != m_signals.end ()) {
0 commit comments