10b57cec5SDimitry Andric //===-- MainLoopBase.h ------------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 95ffd83dbSDimitry Andric #ifndef LLDB_HOST_MAINLOOPBASE_H 105ffd83dbSDimitry Andric #define LLDB_HOST_MAINLOOPBASE_H 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "lldb/Utility/IOObject.h" 130b57cec5SDimitry Andric #include "lldb/Utility/Status.h" 14*bdd1243dSDimitry Andric #include "llvm/ADT/DenseMap.h" 150b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 160b57cec5SDimitry Andric #include <functional> 17*bdd1243dSDimitry Andric #include <mutex> 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric namespace lldb_private { 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric // The purpose of this class is to enable multiplexed processing of data from 220b57cec5SDimitry Andric // different sources without resorting to multi-threading. Clients can register 230b57cec5SDimitry Andric // IOObjects, which will be monitored for readability, and when they become 240b57cec5SDimitry Andric // ready, the specified callback will be invoked. Monitoring for writability is 250b57cec5SDimitry Andric // not supported, but can be easily added if needed. 260b57cec5SDimitry Andric // 270b57cec5SDimitry Andric // The RegisterReadObject function return a handle, which controls the duration 280b57cec5SDimitry Andric // of the monitoring. When this handle is destroyed, the callback is 290b57cec5SDimitry Andric // deregistered. 300b57cec5SDimitry Andric // 31*bdd1243dSDimitry Andric // Since this class is primarily intended to be used for single-threaded 32*bdd1243dSDimitry Andric // processing, it does not attempt to perform any internal synchronisation and 33*bdd1243dSDimitry Andric // any concurrent accesses must be protected externally. However, it is 34*bdd1243dSDimitry Andric // perfectly legitimate to have more than one instance of this class running on 35*bdd1243dSDimitry Andric // separate threads, or even a single thread. 360b57cec5SDimitry Andric class MainLoopBase { 370b57cec5SDimitry Andric private: 380b57cec5SDimitry Andric class ReadHandle; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric public: MainLoopBase()41*bdd1243dSDimitry Andric MainLoopBase() : m_terminate_request(false) {} 42fe6060f1SDimitry Andric virtual ~MainLoopBase() = default; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric typedef std::unique_ptr<ReadHandle> ReadHandleUP; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric typedef std::function<void(MainLoopBase &)> Callback; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric virtual ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, 490b57cec5SDimitry Andric const Callback &callback, 50*bdd1243dSDimitry Andric Status &error) = 0; 510b57cec5SDimitry Andric 5281ad6265SDimitry Andric // Add a pending callback that will be executed once after all the pending 5381ad6265SDimitry Andric // events are processed. The callback will be executed even if termination 5481ad6265SDimitry Andric // was requested. 55*bdd1243dSDimitry Andric void AddPendingCallback(const Callback &callback); 5681ad6265SDimitry Andric 570b57cec5SDimitry Andric // Waits for registered events and invoke the proper callbacks. Returns when 580b57cec5SDimitry Andric // all callbacks deregister themselves or when someone requests termination. Run()590b57cec5SDimitry Andric virtual Status Run() { llvm_unreachable("Not implemented"); } 600b57cec5SDimitry Andric 61*bdd1243dSDimitry Andric // This should only be performed from a callback. Do not attempt to terminate 62*bdd1243dSDimitry Andric // the processing from another thread. RequestTermination()63*bdd1243dSDimitry Andric virtual void RequestTermination() { m_terminate_request = true; } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric protected: CreateReadHandle(const lldb::IOObjectSP & object_sp)660b57cec5SDimitry Andric ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp) { 670b57cec5SDimitry Andric return ReadHandleUP(new ReadHandle(*this, object_sp->GetWaitableHandle())); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 70*bdd1243dSDimitry Andric virtual void UnregisterReadObject(IOObject::WaitableHandle handle) = 0; 71*bdd1243dSDimitry Andric 72*bdd1243dSDimitry Andric // Interrupt the loop that is currently waiting for events and execute 73*bdd1243dSDimitry Andric // the current pending callbacks immediately. 74*bdd1243dSDimitry Andric virtual void TriggerPendingCallbacks() = 0; 75*bdd1243dSDimitry Andric 76*bdd1243dSDimitry Andric void ProcessPendingCallbacks(); 77*bdd1243dSDimitry Andric 78*bdd1243dSDimitry Andric std::mutex m_callback_mutex; 79*bdd1243dSDimitry Andric std::vector<Callback> m_pending_callbacks; 80*bdd1243dSDimitry Andric bool m_terminate_request : 1; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric private: 830b57cec5SDimitry Andric class ReadHandle { 840b57cec5SDimitry Andric public: ~ReadHandle()850b57cec5SDimitry Andric ~ReadHandle() { m_mainloop.UnregisterReadObject(m_handle); } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric private: ReadHandle(MainLoopBase & mainloop,IOObject::WaitableHandle handle)880b57cec5SDimitry Andric ReadHandle(MainLoopBase &mainloop, IOObject::WaitableHandle handle) 890b57cec5SDimitry Andric : m_mainloop(mainloop), m_handle(handle) {} 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric MainLoopBase &m_mainloop; 920b57cec5SDimitry Andric IOObject::WaitableHandle m_handle; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric friend class MainLoopBase; 955ffd83dbSDimitry Andric ReadHandle(const ReadHandle &) = delete; 965ffd83dbSDimitry Andric const ReadHandle &operator=(const ReadHandle &) = delete; 970b57cec5SDimitry Andric }; 980b57cec5SDimitry Andric 995ffd83dbSDimitry Andric MainLoopBase(const MainLoopBase &) = delete; 1005ffd83dbSDimitry Andric const MainLoopBase &operator=(const MainLoopBase &) = delete; 1010b57cec5SDimitry Andric }; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric } // namespace lldb_private 1040b57cec5SDimitry Andric 1055ffd83dbSDimitry Andric #endif // LLDB_HOST_MAINLOOPBASE_H 106