xref: /llvm-project/lldb/include/lldb/Host/MainLoopBase.h (revision 55068dc3b7725f24de82dd4510162865c91a4f5e)
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