1 | //===-- MainLoopPosix.h -----------------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLDB_HOST_POSIX_MAINLOOPPOSIX_H |
10 | #define LLDB_HOST_POSIX_MAINLOOPPOSIX_H |
11 | |
12 | #include "lldb/Host/Config.h" |
13 | #include "lldb/Host/MainLoopBase.h" |
14 | #include "lldb/Host/Pipe.h" |
15 | #include "llvm/ADT/DenseMap.h" |
16 | #include <atomic> |
17 | #include <csignal> |
18 | #include <list> |
19 | #include <vector> |
20 | |
21 | namespace lldb_private { |
22 | |
23 | // Implementation of the MainLoopBase class. It can monitor file descriptors for |
24 | // readability using ppoll, kqueue, or pselect. In addition to the common base, |
25 | // this class provides the ability to invoke a given handler when a signal is |
26 | // received. |
27 | class MainLoopPosix : public MainLoopBase { |
28 | private: |
29 | class SignalHandle; |
30 | |
31 | public: |
32 | typedef std::unique_ptr<SignalHandle> SignalHandleUP; |
33 | |
34 | MainLoopPosix(); |
35 | ~MainLoopPosix() override; |
36 | |
37 | ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, |
38 | const Callback &callback, |
39 | Status &error) override; |
40 | |
41 | // Listening for signals from multiple MainLoop instances is perfectly safe |
42 | // as long as they don't try to listen for the same signal. The callback |
43 | // function is invoked when the control returns to the Run() function, not |
44 | // when the hander is executed. This mean that you can treat the callback as |
45 | // a normal function and perform things which would not be safe in a signal |
46 | // handler. However, since the callback is not invoked synchronously, you |
47 | // cannot use this mechanism to handle SIGSEGV and the like. |
48 | SignalHandleUP RegisterSignal(int signo, const Callback &callback, |
49 | Status &error); |
50 | |
51 | Status Run() override; |
52 | |
53 | protected: |
54 | void UnregisterReadObject(IOObject::WaitableHandle handle) override; |
55 | void UnregisterSignal(int signo, std::list<Callback>::iterator callback_it); |
56 | |
57 | void TriggerPendingCallbacks() override; |
58 | |
59 | private: |
60 | void ProcessReadObject(IOObject::WaitableHandle handle); |
61 | void ProcessSignal(int signo); |
62 | |
63 | class SignalHandle { |
64 | public: |
65 | ~SignalHandle() { m_mainloop.UnregisterSignal(signo: m_signo, callback_it: m_callback_it); } |
66 | |
67 | private: |
68 | SignalHandle(MainLoopPosix &mainloop, int signo, |
69 | std::list<Callback>::iterator callback_it) |
70 | : m_mainloop(mainloop), m_signo(signo), m_callback_it(callback_it) {} |
71 | |
72 | MainLoopPosix &m_mainloop; |
73 | int m_signo; |
74 | std::list<Callback>::iterator m_callback_it; |
75 | |
76 | friend class MainLoopPosix; |
77 | SignalHandle(const SignalHandle &) = delete; |
78 | const SignalHandle &operator=(const SignalHandle &) = delete; |
79 | }; |
80 | |
81 | struct SignalInfo { |
82 | std::list<Callback> callbacks; |
83 | struct sigaction old_action; |
84 | bool was_blocked : 1; |
85 | }; |
86 | class RunImpl; |
87 | |
88 | llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds; |
89 | llvm::DenseMap<int, SignalInfo> m_signals; |
90 | Pipe m_trigger_pipe; |
91 | std::atomic<bool> m_triggering; |
92 | #if HAVE_SYS_EVENT_H |
93 | int m_kqueue; |
94 | #endif |
95 | }; |
96 | |
97 | } // namespace lldb_private |
98 | |
99 | #endif // LLDB_HOST_POSIX_MAINLOOPPOSIX_H |
100 | |