1061da546Spatrick //===-- MainLoopBase.h ------------------------------------------*- C++ -*-===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick 9dda28197Spatrick #ifndef LLDB_HOST_MAINLOOPBASE_H 10dda28197Spatrick #define LLDB_HOST_MAINLOOPBASE_H 11061da546Spatrick 12061da546Spatrick #include "lldb/Utility/IOObject.h" 13061da546Spatrick #include "lldb/Utility/Status.h" 14*f6aab3d8Srobert #include "llvm/ADT/DenseMap.h" 15061da546Spatrick #include "llvm/Support/ErrorHandling.h" 16061da546Spatrick #include <functional> 17*f6aab3d8Srobert #include <mutex> 18061da546Spatrick 19061da546Spatrick namespace lldb_private { 20061da546Spatrick 21061da546Spatrick // The purpose of this class is to enable multiplexed processing of data from 22061da546Spatrick // different sources without resorting to multi-threading. Clients can register 23061da546Spatrick // IOObjects, which will be monitored for readability, and when they become 24061da546Spatrick // ready, the specified callback will be invoked. Monitoring for writability is 25061da546Spatrick // not supported, but can be easily added if needed. 26061da546Spatrick // 27061da546Spatrick // The RegisterReadObject function return a handle, which controls the duration 28061da546Spatrick // of the monitoring. When this handle is destroyed, the callback is 29061da546Spatrick // deregistered. 30061da546Spatrick // 31*f6aab3d8Srobert // Since this class is primarily intended to be used for single-threaded 32*f6aab3d8Srobert // processing, it does not attempt to perform any internal synchronisation and 33*f6aab3d8Srobert // any concurrent accesses must be protected externally. However, it is 34*f6aab3d8Srobert // perfectly legitimate to have more than one instance of this class running on 35*f6aab3d8Srobert // separate threads, or even a single thread. 36061da546Spatrick class MainLoopBase { 37061da546Spatrick private: 38061da546Spatrick class ReadHandle; 39061da546Spatrick 40061da546Spatrick public: MainLoopBase()41*f6aab3d8Srobert MainLoopBase() : m_terminate_request(false) {} 42be691f3bSpatrick virtual ~MainLoopBase() = default; 43061da546Spatrick 44061da546Spatrick typedef std::unique_ptr<ReadHandle> ReadHandleUP; 45061da546Spatrick 46061da546Spatrick typedef std::function<void(MainLoopBase &)> Callback; 47061da546Spatrick 48061da546Spatrick virtual ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, 49061da546Spatrick const Callback &callback, 50*f6aab3d8Srobert Status &error) = 0; 51*f6aab3d8Srobert 52*f6aab3d8Srobert // Add a pending callback that will be executed once after all the pending 53*f6aab3d8Srobert // events are processed. The callback will be executed even if termination 54*f6aab3d8Srobert // was requested. 55*f6aab3d8Srobert void AddPendingCallback(const Callback &callback); 56061da546Spatrick 57061da546Spatrick // Waits for registered events and invoke the proper callbacks. Returns when 58061da546Spatrick // all callbacks deregister themselves or when someone requests termination. Run()59061da546Spatrick virtual Status Run() { llvm_unreachable("Not implemented"); } 60061da546Spatrick 61*f6aab3d8Srobert // This should only be performed from a callback. Do not attempt to terminate 62*f6aab3d8Srobert // the processing from another thread. RequestTermination()63*f6aab3d8Srobert virtual void RequestTermination() { m_terminate_request = true; } 64061da546Spatrick 65061da546Spatrick protected: CreateReadHandle(const lldb::IOObjectSP & object_sp)66061da546Spatrick ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp) { 67061da546Spatrick return ReadHandleUP(new ReadHandle(*this, object_sp->GetWaitableHandle())); 68061da546Spatrick } 69061da546Spatrick 70*f6aab3d8Srobert virtual void UnregisterReadObject(IOObject::WaitableHandle handle) = 0; 71*f6aab3d8Srobert 72*f6aab3d8Srobert // Interrupt the loop that is currently waiting for events and execute 73*f6aab3d8Srobert // the current pending callbacks immediately. 74*f6aab3d8Srobert virtual void TriggerPendingCallbacks() = 0; 75*f6aab3d8Srobert 76*f6aab3d8Srobert void ProcessPendingCallbacks(); 77*f6aab3d8Srobert 78*f6aab3d8Srobert std::mutex m_callback_mutex; 79*f6aab3d8Srobert std::vector<Callback> m_pending_callbacks; 80*f6aab3d8Srobert bool m_terminate_request : 1; 81061da546Spatrick 82061da546Spatrick private: 83061da546Spatrick class ReadHandle { 84061da546Spatrick public: ~ReadHandle()85061da546Spatrick ~ReadHandle() { m_mainloop.UnregisterReadObject(m_handle); } 86061da546Spatrick 87061da546Spatrick private: ReadHandle(MainLoopBase & mainloop,IOObject::WaitableHandle handle)88061da546Spatrick ReadHandle(MainLoopBase &mainloop, IOObject::WaitableHandle handle) 89061da546Spatrick : m_mainloop(mainloop), m_handle(handle) {} 90061da546Spatrick 91061da546Spatrick MainLoopBase &m_mainloop; 92061da546Spatrick IOObject::WaitableHandle m_handle; 93061da546Spatrick 94061da546Spatrick friend class MainLoopBase; 95dda28197Spatrick ReadHandle(const ReadHandle &) = delete; 96dda28197Spatrick const ReadHandle &operator=(const ReadHandle &) = delete; 97061da546Spatrick }; 98061da546Spatrick 99dda28197Spatrick MainLoopBase(const MainLoopBase &) = delete; 100dda28197Spatrick const MainLoopBase &operator=(const MainLoopBase &) = delete; 101061da546Spatrick }; 102061da546Spatrick 103061da546Spatrick } // namespace lldb_private 104061da546Spatrick 105dda28197Spatrick #endif // LLDB_HOST_MAINLOOPBASE_H 106