Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lldb/tools/lldb-dap/DAP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "lldb/API/SBListener.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBStream.h"
#include "lldb/Utility/IOObject.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
Expand Down Expand Up @@ -59,7 +60,7 @@ const char DEV_NULL[] = "/dev/null";
namespace lldb_dap {

DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log,
StreamDescriptor input, StreamDescriptor output, ReplMode repl_mode,
lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode,
std::vector<std::string> pre_init_commands)
: name(std::move(name)), debug_adaptor_path(path), log(log),
input(std::move(input)), output(std::move(output)),
Expand Down
3 changes: 2 additions & 1 deletion lldb/tools/lldb-dap/DAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "lldb/API/SBThread.h"
#include "lldb/API/SBValue.h"
#include "lldb/API/SBValueList.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
Expand Down Expand Up @@ -211,7 +212,7 @@ struct DAP {
std::string last_nonempty_var_expression;

DAP(std::string name, llvm::StringRef path, std::ofstream *log,
StreamDescriptor input, StreamDescriptor output, ReplMode repl_mode,
lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode,
std::vector<std::string> pre_init_commands);
~DAP();
DAP(const DAP &rhs) = delete;
Expand Down
117 changes: 13 additions & 104 deletions lldb/tools/lldb-dap/IOStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,125 +7,34 @@
//===----------------------------------------------------------------------===//

#include "IOStream.h"
#include "lldb/Utility/IOObject.h"
#include "lldb/Utility/Status.h"
#include <fstream>
#include <string>

#if defined(_WIN32)
#include <io.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#endif

using namespace lldb_dap;

StreamDescriptor::StreamDescriptor() = default;

StreamDescriptor::StreamDescriptor(StreamDescriptor &&other) {
*this = std::move(other);
}

StreamDescriptor::~StreamDescriptor() {
if (!m_close)
return;

if (m_is_socket)
#if defined(_WIN32)
::closesocket(m_socket);
#else
::close(m_socket);
#endif
else
::close(m_fd);
}

StreamDescriptor &StreamDescriptor::operator=(StreamDescriptor &&other) {
m_close = other.m_close;
other.m_close = false;
m_is_socket = other.m_is_socket;
if (m_is_socket)
m_socket = other.m_socket;
else
m_fd = other.m_fd;
return *this;
}

StreamDescriptor StreamDescriptor::from_socket(SOCKET s, bool close) {
StreamDescriptor sd;
sd.m_is_socket = true;
sd.m_socket = s;
sd.m_close = close;
return sd;
}

StreamDescriptor StreamDescriptor::from_file(int fd, bool close) {
StreamDescriptor sd;
sd.m_is_socket = false;
sd.m_fd = fd;
sd.m_close = close;
return sd;
}

bool OutputStream::write_full(llvm::StringRef str) {
while (!str.empty()) {
int bytes_written = 0;
if (descriptor.m_is_socket)
bytes_written = ::send(descriptor.m_socket, str.data(), str.size(), 0);
else
bytes_written = ::write(descriptor.m_fd, str.data(), str.size());

if (bytes_written < 0) {
if (errno == EINTR || errno == EAGAIN)
continue;
return false;
}
str = str.drop_front(bytes_written);
}
if (!descriptor)
return false;

return true;
size_t num_bytes = str.size();
auto status = descriptor->Write(str.data(), num_bytes);
return status.Success();
}

bool InputStream::read_full(std::ofstream *log, size_t length,
std::string &text) {
if (!descriptor)
return false;

std::string data;
data.resize(length);

char *ptr = &data[0];
while (length != 0) {
int bytes_read = 0;
if (descriptor.m_is_socket)
bytes_read = ::recv(descriptor.m_socket, ptr, length, 0);
else
bytes_read = ::read(descriptor.m_fd, ptr, length);

if (bytes_read == 0) {
if (log)
*log << "End of file (EOF) reading from input file.\n";
return false;
}
if (bytes_read < 0) {
int reason = 0;
#if defined(_WIN32)
if (descriptor.m_is_socket)
reason = WSAGetLastError();
else
reason = errno;
#else
reason = errno;
if (reason == EINTR || reason == EAGAIN)
continue;
#endif

if (log)
*log << "Error " << reason << " reading from input file.\n";
return false;
}
auto status = descriptor->Read(data.data(), length);
if (status.Fail())
return false;

assert(bytes_read >= 0 && (size_t)bytes_read <= length);
ptr += bytes_read;
length -= bytes_read;
}
text += data;
return true;
}
Expand Down
38 changes: 5 additions & 33 deletions lldb/tools/lldb-dap/IOStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,17 @@
#ifndef LLDB_TOOLS_LLDB_DAP_IOSTREAM_H
#define LLDB_TOOLS_LLDB_DAP_IOSTREAM_H

#if defined(_WIN32)
#include "lldb/Host/windows/windows.h"
#include <winsock2.h>
#else
typedef int SOCKET;
#endif

#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringRef.h"

#include <fstream>
#include <string>

// Windows requires different system calls for dealing with sockets and other
// types of files, so we can't simply have one code path that just uses read
// and write everywhere. So we need an abstraction in order to allow us to
// treat them identically.
namespace lldb_dap {
struct StreamDescriptor {
StreamDescriptor();
~StreamDescriptor();
StreamDescriptor(StreamDescriptor &&other);

StreamDescriptor &operator=(StreamDescriptor &&other);

static StreamDescriptor from_socket(SOCKET s, bool close);
static StreamDescriptor from_file(int fd, bool close);

bool m_is_socket = false;
bool m_close = false;
union {
int m_fd;
SOCKET m_socket;
};
};

struct InputStream {
StreamDescriptor descriptor;
lldb::IOObjectSP descriptor;

explicit InputStream(StreamDescriptor descriptor)
explicit InputStream(lldb::IOObjectSP descriptor)
: descriptor(std::move(descriptor)) {}

bool read_full(std::ofstream *log, size_t length, std::string &text);
Expand All @@ -58,9 +30,9 @@ struct InputStream {
};

struct OutputStream {
StreamDescriptor descriptor;
lldb::IOObjectSP descriptor;

explicit OutputStream(StreamDescriptor descriptor)
explicit OutputStream(lldb::IOObjectSP descriptor)
: descriptor(std::move(descriptor)) {}

bool write_full(llvm::StringRef str);
Expand Down
36 changes: 20 additions & 16 deletions lldb/tools/lldb-dap/lldb-dap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "RunInTerminal.h"
#include "lldb/API/SBStream.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/File.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Host/MainLoopBase.h"
#include "lldb/Host/Socket.h"
Expand Down Expand Up @@ -80,7 +81,11 @@ typedef int socklen_t;
#endif

using namespace lldb_dap;
using lldb_private::NativeSocket;
using lldb_private::File;
using lldb_private::IOObject;
using lldb_private::MainLoop;
using lldb_private::MainLoopBase;
using lldb_private::NativeFile;
using lldb_private::Socket;
using lldb_private::Status;

Expand Down Expand Up @@ -309,14 +314,14 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
// address.
llvm::outs().flush();

static lldb_private::MainLoop g_loop;
static MainLoop g_loop;
llvm::sys::SetInterruptFunction([]() {
g_loop.AddPendingCallback(
[](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
[](MainLoopBase &loop) { loop.RequestTermination(); });
});
std::condition_variable dap_sessions_condition;
std::mutex dap_sessions_mutex;
std::map<Socket *, DAP *> dap_sessions;
std::map<IOObject *, DAP *> dap_sessions;
unsigned int clientCount = 0;
auto handle = listener->Accept(g_loop, [=, &dap_sessions_condition,
&dap_sessions_mutex, &dap_sessions,
Expand All @@ -330,18 +335,15 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
<< " client connected: " << name << "\n";
}

lldb::IOObjectSP io(std::move(sock));

// Move the client into a background thread to unblock accepting the next
// client.
std::thread client([=, &dap_sessions_condition, &dap_sessions_mutex,
&dap_sessions, sock = std::move(sock)]() {
&dap_sessions]() {
llvm::set_thread_name(name + ".runloop");
StreamDescriptor input =
StreamDescriptor::from_socket(sock->GetNativeSocket(), false);
// Close the output last for the best chance at error reporting.
StreamDescriptor output =
StreamDescriptor::from_socket(sock->GetNativeSocket(), false);
DAP dap = DAP(name, program_path, log, std::move(input),
std::move(output), default_repl_mode, pre_init_commands);
DAP dap = DAP(name, program_path, log, io, io, default_repl_mode,
pre_init_commands);

if (auto Err = dap.ConfigureIO()) {
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
Expand All @@ -353,7 +355,7 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,

{
std::scoped_lock<std::mutex> lock(dap_sessions_mutex);
dap_sessions[sock.get()] = &dap;
dap_sessions[io.get()] = &dap;
}

if (auto Err = dap.Loop()) {
Expand All @@ -369,7 +371,7 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name,
}

std::unique_lock<std::mutex> lock(dap_sessions_mutex);
dap_sessions.erase(sock.get());
dap_sessions.erase(io.get());
std::notify_all_at_thread_exit(dap_sessions_condition, std::move(lock));
});
client.detach();
Expand Down Expand Up @@ -561,8 +563,10 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}

StreamDescriptor input = StreamDescriptor::from_file(fileno(stdin), false);
StreamDescriptor output = StreamDescriptor::from_file(stdout_fd, false);
lldb::IOObjectSP input = std::make_shared<NativeFile>(
fileno(stdin), File::eOpenOptionReadOnly, true);
lldb::IOObjectSP output = std::make_shared<NativeFile>(
stdout_fd, File::eOpenOptionWriteOnly, false);

DAP dap = DAP("stdin/stdout", program_path, log.get(), std::move(input),
std::move(output), default_repl_mode, pre_init_commands);
Expand Down