//===-- ThreadStateCoordinator.h --------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef lldb_ThreadStateCoordinator_h #define lldb_ThreadStateCoordinator_h #include #include #include #include #include #include #include "lldb/lldb-types.h" namespace lldb_private { class ThreadStateCoordinator { public: // Typedefs. typedef std::unordered_set ThreadIDSet; enum EventLoopResult { eventLoopResultContinue, eventLoopResultStop }; // Callback/block definitions. typedef std::function ThreadIDFunction; typedef std::function LogFunction; typedef std::function ErrorFunction; // Constructors. ThreadStateCoordinator (const LogFunction &log_function); // Notify the coordinator when a thread is created and/or starting to be // tracked. is_stopped should be true if the thread is currently stopped; // otherwise, it should be set false if it is already running. Will // call the error function if the thread id is already tracked. void NotifyThreadCreate (lldb::tid_t tid, bool is_stopped, const ErrorFunction &error_function); // Notify the coordinator when a previously-existing thread should no // longer be tracked. The error_function will trigger if the thread // is not being tracked. void NotifyThreadDeath (lldb::tid_t tid, const ErrorFunction &error_function); // This method is the main purpose of the class: triggering a deferred // action after a given set of threads stop. The triggering_tid is the // thread id passed to the call_after_function. The error_function will // be fired if either the triggering tid or any of the wait_for_stop_tids // are unknown at the time the method is processed. void CallAfterThreadsStop (lldb::tid_t triggering_tid, const ThreadIDSet &wait_for_stop_tids, const ThreadIDFunction &request_thread_stop_function, const ThreadIDFunction &call_after_function, const ErrorFunction &error_function); // This method is the main purpose of the class: triggering a deferred // action after all non-stopped threads stop. The triggering_tid is the // thread id passed to the call_after_function. The error_function will // be fired if the triggering tid is unknown at the time of execution. void CallAfterRunningThreadsStop (lldb::tid_t triggering_tid, const ThreadIDFunction &request_thread_stop_function, const ThreadIDFunction &call_after_function, const ErrorFunction &error_function); // Notify the thread stopped. Will trigger error at time of execution if we // already think it is stopped. void NotifyThreadStop (lldb::tid_t tid, const ErrorFunction &error_function); // Request that the given thread id should have the request_thread_resume_function // called. Will trigger the error_function if the thread is thought to be running // already at that point. void RequestThreadResume (lldb::tid_t tid, const ThreadIDFunction &request_thread_resume_function, const ErrorFunction &error_function); // Indicate the calling process did an exec and that the thread state // should be 100% cleared. // // Note this will clear out any pending notifications, but will not stop // a notification currently in progress via ProcessNextEvent(). void ResetForExec (); // Indicate when the coordinator should shut down. void StopCoordinator (); // Process the next event, returning false when the coordinator is all done. // This call is synchronous and blocks when there are no events pending. // Expected usage is to run this in a separate thread until the function // returns false. Always call this from the same thread. The processing // logic assumes the execution of this is implicitly serialized. EventLoopResult ProcessNextEvent (); private: // Typedefs. class EventBase; class EventCallAfterThreadsStop; class EventThreadStopped; class EventThreadCreate; class EventThreadDeath; class EventRequestResume; class EventStopCoordinator; class EventReset; typedef std::shared_ptr EventBaseSP; typedef std::queue QueueType; typedef std::unordered_map TIDBoolMap; // Private member functions. void EnqueueEvent (EventBaseSP event_sp); EventBaseSP DequeueEventWithWait (); void SetPendingNotification (const EventBaseSP &event_sp); void ThreadDidStop (lldb::tid_t tid, ErrorFunction &error_function); void ThreadWasCreated (lldb::tid_t tid, bool is_stopped, ErrorFunction &error_function); void ThreadDidDie (lldb::tid_t tid, ErrorFunction &error_function); void ResetNow (); void Log (const char *format, ...); EventCallAfterThreadsStop * GetPendingThreadStopNotification (); // Member variables. LogFunction m_log_function; QueueType m_event_queue; // For now we do simple read/write lock strategy with efficient wait-for-data. // We can replace with an entirely non-blocking queue later but we still want the // reader to sleep when nothing is available - this will be a bursty but infrequent // event mechanism. std::condition_variable m_queue_condition; std::mutex m_queue_mutex; EventBaseSP m_pending_notification_sp; // Maps known TIDs to stop (true) or not-stopped (false) state. TIDBoolMap m_tid_stop_map; }; } #endif