teak-llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h
Pavel Labath 0faf37333c gdb-remote: Make the sequence mutex non-recursive
Summary:
This is a preparatory commit for D22914, where I'd like to replace this mutex by an R/W lock
(which is also not recursive). This required a couple of changes:
- The only caller of Read/WriteRegister, GDBRemoteRegisterContext class, was already acquiring
  the mutex, so these functions do not need to. All functions which now do not take a lock, take
  an lock argument instead, to remind the caller of this fact.
- GetThreadSuffixSupported() was being called from locked and unlocked contexts (including
  contexts where the process was running, and the call would fail if it did not have the result
  cached). I have split this into two functions, one which computes the thread suffix support and
  caches it (this one always takes the lock), and another, which returns the cached value (and
  never needs to take the lock). This feels quite natural as ProcessGdbRemote was already
  pre-caching this value at the start.

Reviewers: clayborg

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D23802

llvm-svn: 279725
2016-08-25 08:34:57 +00:00

164 lines
5.0 KiB
C++

//===-- GDBRemoteClientBase.h -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_GDBRemoteClientBase_h_
#define liblldb_GDBRemoteClientBase_h_
#include "GDBRemoteCommunication.h"
#include <condition_variable>
namespace lldb_private
{
namespace process_gdb_remote
{
class GDBRemoteClientBase : public GDBRemoteCommunication
{
public:
struct ContinueDelegate
{
virtual ~ContinueDelegate();
virtual void
HandleAsyncStdout(llvm::StringRef out) = 0;
virtual void
HandleAsyncMisc(llvm::StringRef data) = 0;
virtual void
HandleStopReply() = 0;
//
/// Processes async structured data.
///
/// @return
/// true if the data was handled; otherwise, false.
//
virtual bool
HandleAsyncStructuredData(const StructuredData::ObjectSP
&object_sp) = 0;
};
GDBRemoteClientBase(const char *comm_name, const char *listener_name);
bool
SendAsyncSignal(int signo);
bool
Interrupt();
lldb::StateType
SendContinuePacketAndWaitForResponse(ContinueDelegate &delegate, const UnixSignals &signals,
llvm::StringRef payload, StringExtractorGDBRemote &response);
PacketResult
SendPacketAndWaitForResponse(const char *payload, size_t len, StringExtractorGDBRemote &response, bool send_async)
{
return SendPacketAndWaitForResponse(llvm::StringRef(payload, len), response, send_async);
}
PacketResult
SendPacketAndWaitForResponse(llvm::StringRef payload, StringExtractorGDBRemote &response, bool send_async);
bool
SendvContPacket(llvm::StringRef payload, StringExtractorGDBRemote &response);
class Lock
{
public:
Lock(GDBRemoteClientBase &comm, bool interrupt);
~Lock();
explicit operator bool() const { return m_acquired; }
// Whether we had to interrupt the continue thread to acquire the connection.
bool
DidInterrupt() const
{
return m_did_interrupt;
}
private:
std::unique_lock<std::mutex> m_async_lock;
GDBRemoteClientBase &m_comm;
bool m_acquired;
bool m_did_interrupt;
void
SyncWithContinueThread(bool interrupt);
};
protected:
PacketResult
SendPacketAndWaitForResponse(llvm::StringRef payload, StringExtractorGDBRemote &response, const Lock &lock);
virtual void
OnRunPacketSent(bool first);
private:
// Variables handling synchronization between the Continue thread and any other threads
// wishing to send packets over the connection. Either the continue thread has control over
// the connection (m_is_running == true) or the connection is free for an arbitrary number of
// other senders to take which indicate their interest by incrementing m_async_count.
// Semantics of individual states:
// - m_continue_packet == false, m_async_count == 0: connection is free
// - m_continue_packet == true, m_async_count == 0: only continue thread is present
// - m_continue_packet == true, m_async_count > 0: continue thread has control, async threads
// should interrupt it and wait for it to set m_continue_packet to false
// - m_continue_packet == false, m_async_count > 0: async threads have control, continue
// thread needs to wait for them to finish (m_async_count goes down to 0).
std::mutex m_mutex;
std::condition_variable m_cv;
// Packet with which to resume after an async interrupt. Can be changed by an async thread
// e.g. to inject a signal.
std::string m_continue_packet;
// When was the interrupt packet sent. Used to make sure we time out if the stub does not
// respond to interrupt requests.
std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time;
uint32_t m_async_count;
bool m_is_running;
bool m_should_stop; // Whether we should resume after a stop.
// end of continue thread synchronization block
// This handles the synchronization between individual async threads. For now they just use a
// simple mutex.
std::mutex m_async_mutex;
bool
ShouldStop(const UnixSignals &signals, StringExtractorGDBRemote &response);
class ContinueLock
{
public:
enum class LockResult
{
Success,
Cancelled,
Failed
};
explicit ContinueLock(GDBRemoteClientBase &comm);
~ContinueLock();
explicit operator bool() { return m_acquired; }
LockResult
lock();
void
unlock();
private:
GDBRemoteClientBase &m_comm;
bool m_acquired;
};
};
} // namespace process_gdb_remote
} // namespace lldb_private
#endif // liblldb_GDBRemoteCommunicationClient_h_