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(m_signo, 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