Add a Communication::WriteAll() that resumes Write() if the initial call did not write all data. Use it in GDBRemoteCommunication when sending packets in order to fix handling partial writes (i.e. just resume/retry them rather than erring out). This fixes LLDB failures when writing large packets to a pty. Differential Revision: https://reviews.llvm.org/D112169
385 lines
15 KiB
C++
385 lines
15 KiB
C++
//===-- Communication.h -----------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLDB_CORE_COMMUNICATION_H
|
|
#define LLDB_CORE_COMMUNICATION_H
|
|
|
|
#include "lldb/Host/HostThread.h"
|
|
#include "lldb/Utility/Broadcaster.h"
|
|
#include "lldb/Utility/Timeout.h"
|
|
#include "lldb/lldb-defines.h"
|
|
#include "lldb/lldb-enumerations.h"
|
|
#include "lldb/lldb-forward.h"
|
|
#include "lldb/lldb-types.h"
|
|
|
|
#include <atomic>
|
|
#include <mutex>
|
|
#include <ratio>
|
|
#include <string>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
|
|
namespace lldb_private {
|
|
class Connection;
|
|
class ConstString;
|
|
class Status;
|
|
|
|
/// \class Communication Communication.h "lldb/Core/Communication.h" An
|
|
/// abstract communications class.
|
|
///
|
|
/// Communication is an class that handles data communication between two data
|
|
/// sources. It uses a Connection class to do the real communication. This
|
|
/// approach has a couple of advantages: it allows a single instance of this
|
|
/// class to be used even though its connection can change. Connections could
|
|
/// negotiate for different connections based on abilities like starting with
|
|
/// Bluetooth and negotiating up to WiFi if available. It also allows this
|
|
/// class to be subclassed by any interfaces that don't want to give bytes but
|
|
/// want to validate and give out packets. This can be done by overriding:
|
|
///
|
|
/// AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast);
|
|
///
|
|
/// Communication inherits from Broadcaster which means it can be used in
|
|
/// conjunction with Listener to wait for multiple broadcaster objects and
|
|
/// multiple events from each of those objects. Communication defines a set of
|
|
/// pre-defined event bits (see enumerations definitions that start with
|
|
/// "eBroadcastBit" below).
|
|
///
|
|
/// There are two modes in which communications can occur:
|
|
/// \li single-threaded
|
|
/// \li multi-threaded
|
|
///
|
|
/// In single-threaded mode, all reads and writes happen synchronously on the
|
|
/// calling thread.
|
|
///
|
|
/// In multi-threaded mode, a read thread is spawned that continually reads
|
|
/// data and caches any received bytes. To start the read thread clients call:
|
|
///
|
|
/// bool Communication::StartReadThread (Status *);
|
|
///
|
|
/// If true is returned a read thread has been spawned that will continually
|
|
/// execute a call to the pure virtual DoRead function:
|
|
///
|
|
/// size_t Communication::ReadFromConnection (void *, size_t, uint32_t);
|
|
///
|
|
/// When bytes are received the data gets cached in \a m_bytes and this class
|
|
/// will broadcast a \b eBroadcastBitReadThreadGotBytes event. Clients that
|
|
/// want packet based communication should override AppendBytesToCache. The
|
|
/// subclasses can choose to call the built in AppendBytesToCache with the \a
|
|
/// broadcast parameter set to false. This will cause the \b
|
|
/// eBroadcastBitReadThreadGotBytes event not get broadcast, and then the
|
|
/// subclass can post a \b eBroadcastBitPacketAvailable event when a full
|
|
/// packet of data has been received.
|
|
///
|
|
/// If the connection is disconnected a \b eBroadcastBitDisconnected event
|
|
/// gets broadcast. If the read thread exits a \b
|
|
/// eBroadcastBitReadThreadDidExit event will be broadcast. Clients can also
|
|
/// post a \b eBroadcastBitReadThreadShouldExit event to this object which
|
|
/// will cause the read thread to exit.
|
|
class Communication : public Broadcaster {
|
|
public:
|
|
FLAGS_ANONYMOUS_ENUM(){
|
|
eBroadcastBitDisconnected =
|
|
(1u << 0), ///< Sent when the communications connection is lost.
|
|
eBroadcastBitReadThreadGotBytes =
|
|
(1u << 1), ///< Sent by the read thread when bytes become available.
|
|
eBroadcastBitReadThreadDidExit =
|
|
(1u
|
|
<< 2), ///< Sent by the read thread when it exits to inform clients.
|
|
eBroadcastBitReadThreadShouldExit =
|
|
(1u << 3), ///< Sent by clients that need to cancel the read thread.
|
|
eBroadcastBitPacketAvailable =
|
|
(1u << 4), ///< Sent when data received makes a complete packet.
|
|
eBroadcastBitNoMorePendingInput = (1u << 5), ///< Sent by the read thread
|
|
///to indicate all pending
|
|
///input has been processed.
|
|
kLoUserBroadcastBit =
|
|
(1u << 16), ///< Subclasses can used bits 31:16 for any needed events.
|
|
kHiUserBroadcastBit = (1u << 31),
|
|
eAllEventBits = 0xffffffff};
|
|
|
|
typedef void (*ReadThreadBytesReceived)(void *baton, const void *src,
|
|
size_t src_len);
|
|
|
|
/// Construct the Communication object with the specified name for the
|
|
/// Broadcaster that this object inherits from.
|
|
///
|
|
/// \param[in] broadcaster_name
|
|
/// The name of the broadcaster object. This name should be as
|
|
/// complete as possible to uniquely identify this object. The
|
|
/// broadcaster name can be updated after the connect function
|
|
/// is called.
|
|
Communication(const char *broadcaster_name);
|
|
|
|
/// Destructor.
|
|
///
|
|
/// The destructor is virtual since this class gets subclassed.
|
|
~Communication() override;
|
|
|
|
void Clear();
|
|
|
|
/// Connect using the current connection by passing \a url to its connect
|
|
/// function. string.
|
|
///
|
|
/// \param[in] url
|
|
/// A string that contains all information needed by the
|
|
/// subclass to connect to another client.
|
|
///
|
|
/// \return
|
|
/// \b True if the connect succeeded, \b false otherwise. The
|
|
/// internal error object should be filled in with an
|
|
/// appropriate value based on the result of this function.
|
|
///
|
|
/// \see Status& Communication::GetError ();
|
|
/// \see bool Connection::Connect (const char *url);
|
|
lldb::ConnectionStatus Connect(const char *url, Status *error_ptr);
|
|
|
|
/// Disconnect the communications connection if one is currently connected.
|
|
///
|
|
/// \return
|
|
/// \b True if the disconnect succeeded, \b false otherwise. The
|
|
/// internal error object should be filled in with an
|
|
/// appropriate value based on the result of this function.
|
|
///
|
|
/// \see Status& Communication::GetError ();
|
|
/// \see bool Connection::Disconnect ();
|
|
lldb::ConnectionStatus Disconnect(Status *error_ptr = nullptr);
|
|
|
|
/// Check if the connection is valid.
|
|
///
|
|
/// \return
|
|
/// \b True if this object is currently connected, \b false
|
|
/// otherwise.
|
|
bool IsConnected() const;
|
|
|
|
bool HasConnection() const;
|
|
|
|
lldb_private::Connection *GetConnection() { return m_connection_sp.get(); }
|
|
|
|
/// Read bytes from the current connection.
|
|
///
|
|
/// If no read thread is running, this function call the connection's
|
|
/// Connection::Read(...) function to get any available.
|
|
///
|
|
/// If a read thread has been started, this function will check for any
|
|
/// cached bytes that have already been read and return any currently
|
|
/// available bytes. If no bytes are cached, it will wait for the bytes to
|
|
/// become available by listening for the \a eBroadcastBitReadThreadGotBytes
|
|
/// event. If this function consumes all of the bytes in the cache, it will
|
|
/// reset the \a eBroadcastBitReadThreadGotBytes event bit.
|
|
///
|
|
/// \param[in] dst
|
|
/// A destination buffer that must be at least \a dst_len bytes
|
|
/// long.
|
|
///
|
|
/// \param[in] dst_len
|
|
/// The number of bytes to attempt to read, and also the max
|
|
/// number of bytes that can be placed into \a dst.
|
|
///
|
|
/// \param[in] timeout
|
|
/// A timeout value or llvm::None for no timeout.
|
|
///
|
|
/// \return
|
|
/// The number of bytes actually read.
|
|
///
|
|
/// \see size_t Connection::Read (void *, size_t);
|
|
size_t Read(void *dst, size_t dst_len, const Timeout<std::micro> &timeout,
|
|
lldb::ConnectionStatus &status, Status *error_ptr);
|
|
|
|
/// The actual write function that attempts to write to the communications
|
|
/// protocol.
|
|
///
|
|
/// Subclasses must override this function.
|
|
///
|
|
/// \param[in] src
|
|
/// A source buffer that must be at least \a src_len bytes
|
|
/// long.
|
|
///
|
|
/// \param[in] src_len
|
|
/// The number of bytes to attempt to write, and also the
|
|
/// number of bytes are currently available in \a src.
|
|
///
|
|
/// \return
|
|
/// The number of bytes actually Written.
|
|
size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status,
|
|
Status *error_ptr);
|
|
|
|
/// Repeatedly attempt writing until either \a src_len bytes are written
|
|
/// or a permanent failure occurs.
|
|
///
|
|
/// \param[in] src
|
|
/// A source buffer that must be at least \a src_len bytes
|
|
/// long.
|
|
///
|
|
/// \param[in] src_len
|
|
/// The number of bytes to attempt to write, and also the
|
|
/// number of bytes are currently available in \a src.
|
|
///
|
|
/// \return
|
|
/// The number of bytes actually Written.
|
|
size_t WriteAll(const void *src, size_t src_len,
|
|
lldb::ConnectionStatus &status, Status *error_ptr);
|
|
|
|
/// Sets the connection that it to be used by this class.
|
|
///
|
|
/// By making a communication class that uses different connections it
|
|
/// allows a single communication interface to negotiate and change its
|
|
/// connection without any interruption to the client. It also allows the
|
|
/// Communication class to be subclassed for packet based communication.
|
|
///
|
|
/// \param[in] connection
|
|
/// A connection that this class will own and destroy.
|
|
///
|
|
/// \see
|
|
/// class Connection
|
|
void SetConnection(std::unique_ptr<Connection> connection);
|
|
|
|
/// Starts a read thread whose sole purpose it to read bytes from the
|
|
/// current connection. This function will call connection's read function:
|
|
///
|
|
/// size_t Connection::Read (void *, size_t);
|
|
///
|
|
/// When bytes are read and cached, this function will call:
|
|
///
|
|
/// Communication::AppendBytesToCache (const uint8_t * bytes, size_t len,
|
|
/// bool
|
|
/// broadcast);
|
|
///
|
|
/// Subclasses should override this function if they wish to override the
|
|
/// default action of caching the bytes and broadcasting a \b
|
|
/// eBroadcastBitReadThreadGotBytes event.
|
|
///
|
|
/// \return
|
|
/// \b True if the read thread was successfully started, \b
|
|
/// false otherwise.
|
|
///
|
|
/// \see size_t Connection::Read (void *, size_t);
|
|
/// \see void Communication::AppendBytesToCache (const uint8_t * bytes,
|
|
/// size_t len, bool broadcast);
|
|
virtual bool StartReadThread(Status *error_ptr = nullptr);
|
|
|
|
/// Stops the read thread by cancelling it.
|
|
///
|
|
/// \return
|
|
/// \b True if the read thread was successfully canceled, \b
|
|
/// false otherwise.
|
|
virtual bool StopReadThread(Status *error_ptr = nullptr);
|
|
|
|
virtual bool JoinReadThread(Status *error_ptr = nullptr);
|
|
/// Checks if there is a currently running read thread.
|
|
///
|
|
/// \return
|
|
/// \b True if the read thread is running, \b false otherwise.
|
|
bool ReadThreadIsRunning();
|
|
|
|
/// The static read thread function. This function will call the "DoRead"
|
|
/// function continuously and wait for data to become available. When data
|
|
/// is received it will append the available data to the internal cache and
|
|
/// broadcast a \b eBroadcastBitReadThreadGotBytes event.
|
|
///
|
|
/// \param[in] comm_ptr
|
|
/// A pointer to an instance of this class.
|
|
///
|
|
/// \return
|
|
/// \b NULL.
|
|
///
|
|
/// \see void Communication::ReadThreadGotBytes (const uint8_t *, size_t);
|
|
static lldb::thread_result_t ReadThread(lldb::thread_arg_t comm_ptr);
|
|
|
|
void SetReadThreadBytesReceivedCallback(ReadThreadBytesReceived callback,
|
|
void *callback_baton);
|
|
|
|
/// Wait for the read thread to process all outstanding data.
|
|
///
|
|
/// After this function returns, the read thread has processed all data that
|
|
/// has been waiting in the Connection queue.
|
|
///
|
|
void SynchronizeWithReadThread();
|
|
|
|
static std::string ConnectionStatusAsString(lldb::ConnectionStatus status);
|
|
|
|
bool GetCloseOnEOF() const { return m_close_on_eof; }
|
|
|
|
void SetCloseOnEOF(bool b) { m_close_on_eof = b; }
|
|
|
|
static ConstString &GetStaticBroadcasterClass();
|
|
|
|
ConstString &GetBroadcasterClass() const override {
|
|
return GetStaticBroadcasterClass();
|
|
}
|
|
|
|
protected:
|
|
lldb::ConnectionSP m_connection_sp; ///< The connection that is current in use
|
|
///by this communications class.
|
|
HostThread m_read_thread; ///< The read thread handle in case we need to
|
|
///cancel the thread.
|
|
std::atomic<bool> m_read_thread_enabled;
|
|
std::atomic<bool> m_read_thread_did_exit;
|
|
std::string
|
|
m_bytes; ///< A buffer to cache bytes read in the ReadThread function.
|
|
std::recursive_mutex m_bytes_mutex; ///< A mutex to protect multi-threaded
|
|
///access to the cached bytes.
|
|
std::mutex
|
|
m_write_mutex; ///< Don't let multiple threads write at the same time...
|
|
std::mutex m_synchronize_mutex;
|
|
ReadThreadBytesReceived m_callback;
|
|
void *m_callback_baton;
|
|
bool m_close_on_eof;
|
|
|
|
size_t ReadFromConnection(void *dst, size_t dst_len,
|
|
const Timeout<std::micro> &timeout,
|
|
lldb::ConnectionStatus &status, Status *error_ptr);
|
|
|
|
/// Append new bytes that get read from the read thread into the internal
|
|
/// object byte cache. This will cause a \b eBroadcastBitReadThreadGotBytes
|
|
/// event to be broadcast if \a broadcast is true.
|
|
///
|
|
/// Subclasses can override this function in order to inspect the received
|
|
/// data and check if a packet is available.
|
|
///
|
|
/// Subclasses can also still call this function from the overridden method
|
|
/// to allow the caching to correctly happen and suppress the broadcasting
|
|
/// of the \a eBroadcastBitReadThreadGotBytes event by setting \a broadcast
|
|
/// to false.
|
|
///
|
|
/// \param[in] src
|
|
/// A source buffer that must be at least \a src_len bytes
|
|
/// long.
|
|
///
|
|
/// \param[in] src_len
|
|
/// The number of bytes to append to the cache.
|
|
virtual void AppendBytesToCache(const uint8_t *src, size_t src_len,
|
|
bool broadcast,
|
|
lldb::ConnectionStatus status);
|
|
|
|
/// Get any available bytes from our data cache. If this call empties the
|
|
/// data cache, the \b eBroadcastBitReadThreadGotBytes event will be reset
|
|
/// to signify no more bytes are available.
|
|
///
|
|
/// \param[in] dst
|
|
/// A destination buffer that must be at least \a dst_len bytes
|
|
/// long.
|
|
///
|
|
/// \param[in] dst_len
|
|
/// The number of bytes to attempt to read from the cache,
|
|
/// and also the max number of bytes that can be placed into
|
|
/// \a dst.
|
|
///
|
|
/// \return
|
|
/// The number of bytes extracted from the data cache.
|
|
size_t GetCachedBytes(void *dst, size_t dst_len);
|
|
|
|
private:
|
|
Communication(const Communication &) = delete;
|
|
const Communication &operator=(const Communication &) = delete;
|
|
};
|
|
|
|
} // namespace lldb_private
|
|
|
|
#endif // LLDB_CORE_COMMUNICATION_H
|