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 <functional>
18#include <mutex>
19#include <queue>
20
21namespace 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.
39private:
40 class ReadHandle;
41
42public:
43 using TimePoint = std::chrono::time_point<std::chrono::steady_clock,
44 std::chrono::nanoseconds>;
45
47 virtual ~MainLoopBase() = default;
48
49 typedef std::unique_ptr<ReadHandle> ReadHandleUP;
50
51 typedef std::function<void(MainLoopBase &)> Callback;
52
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 // Returns false if an interrupt was needed to get the loop to act on the new
61 // callback, but the interrupt failed, true otherwise. Mostly used when the
62 // pending callback is a RequestTermination, since if the interrupt fails for
63 // that callback, waiting for the MainLoop thread to terminate could stall.
64 bool AddPendingCallback(const Callback &callback) {
65 return AddCallback(callback, std::chrono::steady_clock::time_point());
66 }
67
68 // Add a callback that will be executed after a certain amount of time has
69 // passed. See AddPendingCallback comment for the return value.
70 bool AddCallback(const Callback &callback, std::chrono::nanoseconds delay) {
71 return AddCallback(callback, std::chrono::steady_clock::now() + delay);
72 }
73
74 // Add a callback that will be executed after a given point in time.
75 // See AddPendingCallback comment for the return value.
76 bool AddCallback(const Callback &callback, TimePoint point);
77
78 // Waits for registered events and invoke the proper callbacks. Returns when
79 // all callbacks deregister themselves or when someone requests termination.
80 virtual Status Run() { llvm_unreachable("Not implemented"); }
81
82 // This should only be performed from a callback. Do not attempt to terminate
83 // the processing from another thread.
84 virtual void RequestTermination() { m_terminate_request = true; }
85
86protected:
88 return ReadHandleUP(new ReadHandle(*this, object_sp->GetWaitableHandle()));
89 }
90
92
93 /// Interrupt the loop that is currently waiting for events. Return true if
94 /// the interrupt succeeded, false if it failed.
95 virtual bool Interrupt() = 0;
96
97 void ProcessCallbacks();
98
99 std::optional<TimePoint> GetNextWakeupTime();
100
102 std::priority_queue<std::pair<TimePoint, Callback>,
103 std::vector<std::pair<TimePoint, Callback>>,
104 llvm::on_first<std::greater<TimePoint>>>
107
108private:
110 public:
111 ~ReadHandle() { m_mainloop.UnregisterReadObject(m_handle); }
112
113 private:
115 : m_mainloop(mainloop), m_handle(handle) {}
116
119
120 friend class MainLoopBase;
121 ReadHandle(const ReadHandle &) = delete;
122 const ReadHandle &operator=(const ReadHandle &) = delete;
123 };
124
125 MainLoopBase(const MainLoopBase &) = delete;
126 const MainLoopBase &operator=(const MainLoopBase &) = delete;
127};
128
129} // namespace lldb_private
130
131#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::priority_queue< std::pair< TimePoint, Callback >, std::vector< std::pair< TimePoint, Callback > >, llvm::on_first< std::greater< TimePoint > > > m_callbacks
std::chrono::time_point< std::chrono::steady_clock, std::chrono::nanoseconds > TimePoint
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