blob: 3a6bdd8a08ada35cfb53a63560d52f21518e88d1 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "io_loop.h"
#include <unistd.h>
#include <lib/async/cpp/task.h>
#include <lib/fit/function.h>
#include "garnet/lib/debugger_utils/util.h"
#include "lib/fsl/handles/object_info.h"
#include "lib/fxl/logging.h"
namespace inferior_control {
IOLoop::IOLoop(int fd, Delegate* delegate, async::Loop* origin_loop)
: quit_called_(false),
fd_(fd),
delegate_(delegate),
is_running_(false),
origin_loop_(origin_loop),
read_loop_(&kAsyncLoopConfigNoAttachToThread),
write_loop_(&kAsyncLoopConfigNoAttachToThread) {
// Allow -1 for test purposes. This is a simple test anyway, the caller
// could pass 314159 and we don't verify it's validity here.
FXL_DCHECK(fd_ >= -1);
FXL_DCHECK(delegate_);
FXL_DCHECK(origin_loop_);
}
IOLoop::~IOLoop() { Quit(); }
void IOLoop::Run() {
FXL_DCHECK(!is_running_);
read_loop_.StartThread();
write_loop_.StartThread();
is_running_ = true;
// Posts an asynchronous task on to listen for an incoming packet. This
// initiates a loop that always reads for incoming packets. Called from
// Run().
async::PostTask(read_loop_.dispatcher(),
fit::bind_member(this, &IOLoop::OnReadTask));
}
void IOLoop::Quit() {
FXL_DCHECK(is_running_);
FXL_LOG(INFO) << "Quitting socket I/O loop";
quit_called_ = true;
read_loop_.Quit();
write_loop_.Quit();
read_loop_.Shutdown();
write_loop_.Shutdown();
FXL_LOG(INFO) << "Socket I/O loop exited";
}
void IOLoop::PostWriteTask(const fxl::StringView& bytes) {
// We copy the data into the closure.
// TODO(armansito): Pass a refptr/weaktpr to |this|?
async::PostTask(write_loop_.dispatcher(), [this, bytes = bytes.ToString()] {
ssize_t bytes_written = write(fd_, bytes.data(), bytes.size());
// This cast isn't really safe, then again it should be virtually
// impossible to send a large enough packet to cause an overflow (at
// least with the GDB Remote protocol).
if (bytes_written != static_cast<ssize_t>(bytes.size())) {
FXL_LOG(ERROR) << "Failed to send bytes"
<< ", " << debugger_utils::ErrnoString(errno);
ReportError();
return;
}
FXL_VLOG(2) << "<- " << debugger_utils::EscapeNonPrintableString(bytes);
});
}
void IOLoop::ReportError() {
// TODO(armansito): Pass a refptr/weaktpr to |this|?
async::PostTask(origin_loop_->dispatcher(),
[this] { delegate_->OnIOError(); });
}
void IOLoop::ReportDisconnected() {
// TODO(armansito): Pass a refptr/weaktpr to |this|?
async::PostTask(origin_loop_->dispatcher(),
[this] { delegate_->OnDisconnected(); });
}
} // namespace inferior_control