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