1 //===-- MainLoopBase.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_MAINLOOPBASE_H 10 #define LLDB_HOST_MAINLOOPBASE_H 11 12 #include "lldb/Utility/IOObject.h" 13 #include "lldb/Utility/Status.h" 14 #include "llvm/ADT/DenseMap.h" 15 #include "llvm/Support/ErrorHandling.h" 16 #include <chrono> 17 #include <functional> 18 #include <mutex> 19 #include <queue> 20 21 namespace lldb_private { 22 23 // The purpose of this class is to enable multiplexed processing of data from 24 // different sources without resorting to multi-threading. Clients can register 25 // IOObjects, which will be monitored for readability, and when they become 26 // ready, the specified callback will be invoked. Monitoring for writability is 27 // not supported, but can be easily added if needed. 28 // 29 // The RegisterReadObject function return a handle, which controls the duration 30 // of the monitoring. When this handle is destroyed, the callback is 31 // deregistered. 32 // 33 // Since this class is primarily intended to be used for single-threaded 34 // processing, it does not attempt to perform any internal synchronisation and 35 // any concurrent accesses must be protected externally. However, it is 36 // perfectly legitimate to have more than one instance of this class running on 37 // separate threads, or even a single thread. 38 class MainLoopBase { 39 private: 40 class ReadHandle; 41 42 public: 43 using TimePoint = std::chrono::time_point<std::chrono::steady_clock, 44 std::chrono::nanoseconds>; 45 46 MainLoopBase() : m_terminate_request(false) {} 47 virtual ~MainLoopBase() = default; 48 49 typedef std::unique_ptr<ReadHandle> ReadHandleUP; 50 51 typedef std::function<void(MainLoopBase &)> Callback; 52 53 virtual ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, 54 const Callback &callback, 55 Status &error) = 0; 56 57 // Add a pending callback that will be executed once after all the pending 58 // events are processed. The callback will be executed even if termination 59 // was requested. 60 void AddPendingCallback(const Callback &callback) { 61 AddCallback(callback, std::chrono::steady_clock::time_point()); 62 } 63 64 // Add a callback that will be executed after a certain amount of time has 65 // passed. 66 void AddCallback(const Callback &callback, std::chrono::nanoseconds delay) { 67 AddCallback(callback, std::chrono::steady_clock::now() + delay); 68 } 69 70 // Add a callback that will be executed after a given point in time. 71 void AddCallback(const Callback &callback, TimePoint point); 72 73 // Waits for registered events and invoke the proper callbacks. Returns when 74 // all callbacks deregister themselves or when someone requests termination. 75 virtual Status Run() { llvm_unreachable("Not implemented"); } 76 77 // This should only be performed from a callback. Do not attempt to terminate 78 // the processing from another thread. 79 virtual void RequestTermination() { m_terminate_request = true; } 80 81 protected: 82 ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp) { 83 return ReadHandleUP(new ReadHandle(*this, object_sp->GetWaitableHandle())); 84 } 85 86 virtual void UnregisterReadObject(IOObject::WaitableHandle handle) = 0; 87 88 // Interrupt the loop that is currently waiting for events. 89 virtual void Interrupt() = 0; 90 91 void ProcessCallbacks(); 92 93 std::optional<TimePoint> GetNextWakeupTime(); 94 95 std::mutex m_callback_mutex; 96 std::priority_queue<std::pair<TimePoint, Callback>, 97 std::vector<std::pair<TimePoint, Callback>>, 98 llvm::on_first<std::greater<TimePoint>>> 99 m_callbacks; 100 bool m_terminate_request : 1; 101 102 private: 103 class ReadHandle { 104 public: 105 ~ReadHandle() { m_mainloop.UnregisterReadObject(m_handle); } 106 107 private: 108 ReadHandle(MainLoopBase &mainloop, IOObject::WaitableHandle handle) 109 : m_mainloop(mainloop), m_handle(handle) {} 110 111 MainLoopBase &m_mainloop; 112 IOObject::WaitableHandle m_handle; 113 114 friend class MainLoopBase; 115 ReadHandle(const ReadHandle &) = delete; 116 const ReadHandle &operator=(const ReadHandle &) = delete; 117 }; 118 119 MainLoopBase(const MainLoopBase &) = delete; 120 const MainLoopBase &operator=(const MainLoopBase &) = delete; 121 }; 122 123 } // namespace lldb_private 124 125 #endif // LLDB_HOST_MAINLOOPBASE_H 126