1 //===-- MainLoop.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_MAINLOOP_H 10 #define LLDB_HOST_MAINLOOP_H 11 12 #include "lldb/Host/Config.h" 13 #include "lldb/Host/MainLoopBase.h" 14 #include "llvm/ADT/DenseMap.h" 15 #include <csignal> 16 #include <list> 17 #include <vector> 18 19 #if !HAVE_PPOLL && !HAVE_SYS_EVENT_H && !defined(__ANDROID__) 20 #define SIGNAL_POLLING_UNSUPPORTED 1 21 #endif 22 23 namespace lldb_private { 24 25 // Implementation of the MainLoopBase class. It can monitor file descriptors 26 // for readability using ppoll, kqueue, poll or WSAPoll. On Windows it only 27 // supports polling sockets, and will not work on generic file handles or 28 // pipes. On systems without kqueue or ppoll handling singnals is not 29 // supported. In addition to the common base, this class provides the ability 30 // to invoke a given handler when a signal is received. 31 // 32 // Since this class is primarily intended to be used for single-threaded 33 // processing, it does not attempt to perform any internal synchronisation and 34 // any concurrent accesses must be protected externally. However, it is 35 // perfectly legitimate to have more than one instance of this class running on 36 // separate threads, or even a single thread (with some limitations on signal 37 // monitoring). 38 // TODO: Add locking if this class is to be used in a multi-threaded context. 39 class MainLoop : public MainLoopBase { 40 private: 41 class SignalHandle; 42 43 public: 44 typedef std::unique_ptr<SignalHandle> SignalHandleUP; 45 46 MainLoop(); 47 ~MainLoop() override; 48 49 ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, 50 const Callback &callback, 51 Status &error) override; 52 53 // Listening for signals from multiple MainLoop instances is perfectly safe 54 // as long as they don't try to listen for the same signal. The callback 55 // function is invoked when the control returns to the Run() function, not 56 // when the hander is executed. This mean that you can treat the callback as 57 // a normal function and perform things which would not be safe in a signal 58 // handler. However, since the callback is not invoked synchronously, you 59 // cannot use this mechanism to handle SIGSEGV and the like. 60 SignalHandleUP RegisterSignal(int signo, const Callback &callback, 61 Status &error); 62 63 // Add a pending callback that will be executed once after all the pending 64 // events are processed. The callback will be executed even if termination 65 // was requested. 66 void AddPendingCallback(const Callback &callback) override; 67 68 Status Run() override; 69 70 // This should only be performed from a callback. Do not attempt to terminate 71 // the processing from another thread. 72 // TODO: Add synchronization if we want to be terminated from another thread. 73 void RequestTermination() override { m_terminate_request = true; } 74 75 protected: 76 void UnregisterReadObject(IOObject::WaitableHandle handle) override; 77 78 void UnregisterSignal(int signo, std::list<Callback>::iterator callback_it); 79 80 private: 81 void ProcessReadObject(IOObject::WaitableHandle handle); 82 void ProcessSignal(int signo); 83 84 class SignalHandle { 85 public: 86 ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo, m_callback_it); } 87 88 private: 89 SignalHandle(MainLoop &mainloop, int signo, 90 std::list<Callback>::iterator callback_it) 91 : m_mainloop(mainloop), m_signo(signo), m_callback_it(callback_it) {} 92 93 MainLoop &m_mainloop; 94 int m_signo; 95 std::list<Callback>::iterator m_callback_it; 96 97 friend class MainLoop; 98 SignalHandle(const SignalHandle &) = delete; 99 const SignalHandle &operator=(const SignalHandle &) = delete; 100 }; 101 102 struct SignalInfo { 103 std::list<Callback> callbacks; 104 #ifndef SIGNAL_POLLING_UNSUPPORTED 105 struct sigaction old_action; 106 #endif 107 bool was_blocked : 1; 108 }; 109 class RunImpl; 110 111 llvm::DenseMap<IOObject::WaitableHandle, Callback> m_read_fds; 112 llvm::DenseMap<int, SignalInfo> m_signals; 113 std::vector<Callback> m_pending_callbacks; 114 #if HAVE_SYS_EVENT_H 115 int m_kqueue; 116 #endif 117 bool m_terminate_request : 1; 118 }; 119 120 } // namespace lldb_private 121 122 #endif // LLDB_HOST_MAINLOOP_H 123