llvm-project/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h

192 lines
6.8 KiB
C++

//===-- 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 <condition_variable>
#include <functional>
#include <mutex>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include "lldb/lldb-types.h"
namespace lldb_private
{
class ThreadStateCoordinator
{
public:
// Typedefs.
typedef std::unordered_set<lldb::tid_t> ThreadIDSet;
enum EventLoopResult
{
eventLoopResultContinue,
eventLoopResultStop
};
// Callback/block definitions.
typedef std::function<void (lldb::tid_t tid)> ThreadIDFunction;
typedef std::function<void (const char *format, va_list args)> LogFunction;
typedef std::function<void (const std::string &error_message)> 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 ();
// Enable/disable verbose logging of event processing.
void
LogEnableEventProcessing (bool enabled);
private:
// Typedefs.
class EventBase;
class EventCallAfterThreadsStop;
class EventThreadStopped;
class EventThreadCreate;
class EventThreadDeath;
class EventRequestResume;
class EventStopCoordinator;
class EventReset;
typedef std::shared_ptr<EventBase> EventBaseSP;
typedef std::queue<EventBaseSP> QueueType;
typedef std::unordered_map<lldb::tid_t, bool> 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;
bool m_log_event_processing;
};
}
#endif