LLDB mainline
MainLoopBase.h
Go to the documentation of this file.
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
13#include "lldb/Utility/Status.h"
14#include "llvm/ADT/DenseMap.h"
15#include "llvm/Support/ErrorHandling.h"
16#include <chrono>
17#include <cstdint>
18#include <functional>
19#include <mutex>
20#include <queue>
21#include <tuple>
22#include <vector>
23
24namespace lldb_private {
25
26// The purpose of this class is to enable multiplexed processing of data from
27// different sources without resorting to multi-threading. Clients can register
28// IOObjects, which will be monitored for readability, and when they become
29// ready, the specified callback will be invoked. Monitoring for writability is
30// not supported, but can be easily added if needed.
31//
32// The RegisterReadObject function return a handle, which controls the duration
33// of the monitoring. When this handle is destroyed, the callback is
34// deregistered.
35//
36// Since this class is primarily intended to be used for single-threaded
37// processing, it does not attempt to perform any internal synchronisation and
38// any concurrent accesses must be protected externally. However, it is
39// perfectly legitimate to have more than one instance of this class running on
40// separate threads, or even a single thread.
42private:
43 class ReadHandle;
44
45public:
46 using TimePoint = std::chrono::time_point<std::chrono::steady_clock,
47 std::chrono::nanoseconds>;
48
50 virtual ~MainLoopBase() = default;
51
52 typedef std::unique_ptr<ReadHandle> ReadHandleUP;
53
54 typedef std::function<void(MainLoopBase &)> Callback;
55
57 const Callback &callback,
58 Status &error) = 0;
59
60 // Add a pending callback that will be executed once after all the pending
61 // events are processed. The callback will be executed even if termination
62 // was requested.
63 // Returns false if an interrupt was needed to get the loop to act on the new
64 // callback, but the interrupt failed, true otherwise. Mostly used when the
65 // pending callback is a RequestTermination, since if the interrupt fails for
66 // that callback, waiting for the MainLoop thread to terminate could stall.
67 bool AddPendingCallback(const Callback &callback) {
68 return AddCallback(callback, std::chrono::steady_clock::time_point());
69 }
70
71 // Add a callback that will be executed after a certain amount of time has
72 // passed. See AddPendingCallback comment for the return value.
73 bool AddCallback(const Callback &callback, std::chrono::nanoseconds delay) {
74 return AddCallback(callback, std::chrono::steady_clock::now() + delay);
75 }
76
77 // Add a callback that will be executed after a given point in time.
78 // See AddPendingCallback comment for the return value.
79 bool AddCallback(const Callback &callback, TimePoint point);
80
81 // Waits for registered events and invoke the proper callbacks. Returns when
82 // all callbacks deregister themselves or when someone requests termination.
83 virtual Status Run() { llvm_unreachable("Not implemented"); }
84
85 // This should only be performed from a callback. Do not attempt to terminate
86 // the processing from another thread.
87 virtual void RequestTermination() { m_terminate_request = true; }
88
89protected:
91 return ReadHandleUP(new ReadHandle(*this, object_sp->GetWaitableHandle()));
92 }
93
95
96 /// Interrupt the loop that is currently waiting for events. Return true if
97 /// the interrupt succeeded, false if it failed.
98 virtual bool Interrupt() = 0;
99
100 void ProcessCallbacks();
101
102 std::optional<TimePoint> GetNextWakeupTime();
103
105
109
110 CallbackEntry(TimePoint tp, Callback cb, uint64_t seq)
111 : time_point(std::move(tp)), callback(std::move(cb)), sequence(seq) {}
112
113 /// Sort using the `>`(!) operator to create a min-priority queue.
114 bool operator<(const CallbackEntry &other) const {
115 return std::tie(time_point, sequence) > // > for Min-priority queue
116 std::tie(other.time_point, other.sequence);
117 }
118
119 private:
120 uint64_t sequence;
121 };
122
123 std::priority_queue<CallbackEntry> m_callbacks;
126
127private:
129 public:
130 ~ReadHandle() { m_mainloop.UnregisterReadObject(m_handle); }
131
132 private:
134 : m_mainloop(mainloop), m_handle(handle) {}
135
138
139 friend class MainLoopBase;
140 ReadHandle(const ReadHandle &) = delete;
141 const ReadHandle &operator=(const ReadHandle &) = delete;
142 };
143
144 MainLoopBase(const MainLoopBase &) = delete;
145 const MainLoopBase &operator=(const MainLoopBase &) = delete;
146};
147
148} // namespace lldb_private
149
150#endif // LLDB_HOST_MAINLOOPBASE_H
static llvm::raw_ostream & error(Stream &strm)
lldb::file_t WaitableHandle
Definition IOObject.h:29
IOObject::WaitableHandle m_handle
ReadHandle(const ReadHandle &)=delete
ReadHandle(MainLoopBase &mainloop, IOObject::WaitableHandle handle)
const ReadHandle & operator=(const ReadHandle &)=delete
std::unique_ptr< ReadHandle > ReadHandleUP
virtual void UnregisterReadObject(IOObject::WaitableHandle handle)=0
const MainLoopBase & operator=(const MainLoopBase &)=delete
std::chrono::time_point< std::chrono::steady_clock, std::chrono::nanoseconds > TimePoint
std::priority_queue< CallbackEntry > m_callbacks
std::optional< TimePoint > GetNextWakeupTime()
virtual ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, const Callback &callback, Status &error)=0
ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp)
bool AddPendingCallback(const Callback &callback)
virtual ~MainLoopBase()=default
MainLoopBase(const MainLoopBase &)=delete
std::function< void(MainLoopBase &)> Callback
virtual bool Interrupt()=0
Interrupt the loop that is currently waiting for events.
virtual void RequestTermination()
bool AddCallback(const Callback &callback, std::chrono::nanoseconds delay)
An error handling class.
Definition Status.h:118
A class that represents a running process on the host machine.
std::shared_ptr< lldb_private::IOObject > IOObjectSP
CallbackEntry(TimePoint tp, Callback cb, uint64_t seq)
bool operator<(const CallbackEntry &other) const
Sort using the >(!) operator to create a min-priority queue.