blob: 020b8cb7b2585272d7fef932b03c6c2277598920 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "platform/globals.h"
#if defined(TARGET_OS_LINUX)
#include <errno.h> // NOLINT
#include <stdio.h> // NOLINT
#include <stdlib.h> // NOLINT
#include <sys/epoll.h> // NOLINT
#include "bin/dbg_connection.h"
#include "bin/fdutils.h"
#include "bin/log.h"
#include "bin/socket.h"
namespace dart {
namespace bin {
int DebuggerConnectionImpl::epoll_fd_ = -1;
int DebuggerConnectionImpl::wakeup_fds_[2] = {-1, -1};
void DebuggerConnectionImpl::HandleEvent(struct epoll_event* event) {
if (event->data.fd == DebuggerConnectionHandler::listener_fd_) {
if (DebuggerConnectionHandler::IsConnected()) {
FATAL("Cannot connect to more than one debugger.\n");
}
int fd = ServerSocket::Accept(event->data.fd);
if (fd < 0) {
FATAL("Accepting new debugger connection failed.\n");
}
FDUtils::SetBlocking(fd);
DebuggerConnectionHandler::AcceptDbgConnection(fd);
// TODO(hausner): add the debugger wire socket fd to the event poll queue
// once we poll the debugger connection.
} else if (event->data.fd == wakeup_fds_[0]) {
// Sync message. Not yet implemented.
UNIMPLEMENTED();
} else {
Log::Print("unexpected: receiving debugger connection event.\n");
UNIMPLEMENTED();
}
}
void DebuggerConnectionImpl::Handler(uword args) {
static const intptr_t kMaxEvents = 4;
struct epoll_event events[kMaxEvents];
while (1) {
const int no_timeout = -1;
intptr_t result = TEMP_FAILURE_RETRY(
epoll_wait(epoll_fd_, events, kMaxEvents, no_timeout));
ASSERT(EAGAIN == EWOULDBLOCK);
if (result == -1) {
if (errno != EWOULDBLOCK) {
perror("epoll_wait failed");
}
} else {
ASSERT(result <= kMaxEvents);
for (int i = 0; i < result; i++) {
HandleEvent(&events[i]);
}
}
}
}
void DebuggerConnectionImpl::SetupPollQueue() {
int result = TEMP_FAILURE_RETRY(pipe(wakeup_fds_));
if (result != 0) {
FATAL1("Pipe creation failed with error %d\n", result);
}
FDUtils::SetNonBlocking(wakeup_fds_[0]);
static const int kEpollInitialSize = 16;
epoll_fd_ = TEMP_FAILURE_RETRY(epoll_create(kEpollInitialSize));
if (epoll_fd_ == -1) {
FATAL("Failed creating epoll file descriptor");
}
// Register the wakeup _fd with the epoll instance.
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = wakeup_fds_[0];
int status = TEMP_FAILURE_RETRY(epoll_ctl(
epoll_fd_, EPOLL_CTL_ADD, wakeup_fds_[0], &event));
if (status == -1) {
FATAL("Failed adding wakeup fd to epoll instance");
}
// Register the listener_fd with the epoll instance.
event.events = EPOLLIN;
event.data.fd = DebuggerConnectionHandler::listener_fd_;
status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD,
DebuggerConnectionHandler::listener_fd_, &event));
if (status == -1) {
FATAL("Failed adding listener fd to epoll instance");
}
}
void DebuggerConnectionImpl::StartHandler(int port_number) {
ASSERT(DebuggerConnectionHandler::listener_fd_ != -1);
SetupPollQueue();
int result = dart::Thread::Start(&DebuggerConnectionImpl::Handler, 0);
if (result != 0) {
FATAL1("Failed to start debugger connection handler thread: %d\n", result);
}
}
intptr_t DebuggerConnectionImpl::Send(intptr_t socket,
const char* buf,
int len) {
return TEMP_FAILURE_RETRY(write(socket, buf, len));
}
intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
return TEMP_FAILURE_RETRY(read(socket, buf, len));
}
} // namespace bin
} // namespace dart
#endif // defined(TARGET_OS_LINUX)