| Index: runtime/bin/dbg_connection_macos.cc
 | 
| ===================================================================
 | 
| --- runtime/bin/dbg_connection_macos.cc	(revision 0)
 | 
| +++ runtime/bin/dbg_connection_macos.cc	(revision 0)
 | 
| @@ -0,0 +1,158 @@
 | 
| +// 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 <errno.h>
 | 
| +#include <stdio.h>
 | 
| +#include <stdlib.h>
 | 
| +#include <string.h>
 | 
| +#include <sys/event.h>
 | 
| +#include <unistd.h>
 | 
| +
 | 
| +#include "bin/dartutils.h"
 | 
| +#include "bin/dbg_connection.h"
 | 
| +#include "bin/fdutils.h"
 | 
| +#include "bin/socket.h"
 | 
| +#include "platform/thread.h"
 | 
| +#include "platform/utils.h"
 | 
| +
 | 
| +
 | 
| +#define INVALID_FD -1
 | 
| +
 | 
| +int DebuggerConnectionImpl::kqueue_fd_ = INVALID_FD;
 | 
| +int DebuggerConnectionImpl::wakeup_fds_[2] = {INVALID_FD, INVALID_FD};
 | 
| +
 | 
| +
 | 
| +// Used by VM threads to send a message to the debugger connetion
 | 
| +// handler thread.
 | 
| +void DebuggerConnectionImpl::SendMessage(MessageType id) {
 | 
| +  ASSERT(wakeup_fds_[1] != INVALID_FD);
 | 
| +  struct Message msg;
 | 
| +  msg.msg_id = id;
 | 
| +  int result = FDUtils::WriteToBlocking(wakeup_fds_[1], &msg, sizeof(msg));
 | 
| +  if (result != sizeof(msg)) {
 | 
| +    if (result == -1) {
 | 
| +      perror("Wakeup message failure: ");
 | 
| +    }
 | 
| +    FATAL1("Wakeup message failure. Wrote %d bytes.", result);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +// Used by the debugger connection handler to read the messages sent
 | 
| +// by the VM.
 | 
| +bool DebuggerConnectionImpl::ReceiveMessage(Message* msg) {
 | 
| +  int total_read = 0;
 | 
| +  int bytes_read = 0;
 | 
| +  int remaining = sizeof(Message);
 | 
| +  uint8_t* buf = reinterpret_cast<uint8_t*>(msg);
 | 
| +  while (remaining > 0) {
 | 
| +    bytes_read =
 | 
| +        TEMP_FAILURE_RETRY(read(wakeup_fds_[0], buf + total_read, remaining));
 | 
| +    if ((bytes_read < 0) && (total_read == 0)) {
 | 
| +      return false;
 | 
| +    }
 | 
| +    if (bytes_read > 0) {
 | 
| +      total_read += bytes_read;
 | 
| +      remaining -= bytes_read;
 | 
| +    }
 | 
| +  }
 | 
| +  ASSERT(remaining >= 0);
 | 
| +  return remaining == 0;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void DebuggerConnectionImpl::HandleEvent(struct kevent* event) {
 | 
| +  int ident = event->ident;
 | 
| +  if (ident == DebuggerConnectionHandler::listener_fd_) {
 | 
| +    if (DebuggerConnectionHandler::IsConnected()) {
 | 
| +      FATAL("Cannot connect to more than one debugger.\n");
 | 
| +    }
 | 
| +    int fd = ServerSocket::Accept(ident);
 | 
| +    if (fd < 0) {
 | 
| +      FATAL("Accepting new debugger connection failed.\n");
 | 
| +    }
 | 
| +    FDUtils::SetBlocking(fd);
 | 
| +    DebuggerConnectionHandler::AcceptDbgConnection(fd);
 | 
| +
 | 
| +    /* For now, don't poll the debugger connection.
 | 
| +    struct kevent ev_add;
 | 
| +    EV_SET(&ev_add, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
 | 
| +    int status =
 | 
| +        TEMP_FAILURE_RETRY(kevent(kqueue_fd_, &ev_add, 1, NULL, 0, NULL));
 | 
| +    if (status == -1) {
 | 
| +      FATAL1("Failed adding debugger socket to kqueue: %s\n", strerror(errno));
 | 
| +    }
 | 
| +    */
 | 
| +  } else if (ident == DebuggerConnectionHandler::debugger_fd_) {
 | 
| +    printf("unexpected: receiving debugger connection event.\n");
 | 
| +    UNIMPLEMENTED();
 | 
| +  } else {
 | 
| +    Message msg;
 | 
| +    if (ReceiveMessage(&msg)) {
 | 
| +      printf("Received sync message id %d.\n", msg.msg_id);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void DebuggerConnectionImpl::Handler(uword args) {
 | 
| +  static const intptr_t kMaxEvents = 4;
 | 
| +  struct kevent events[kMaxEvents];
 | 
| +
 | 
| +  while (1) {
 | 
| +    // Wait indefinitely for an event.
 | 
| +    int result = TEMP_FAILURE_RETRY(
 | 
| +        kevent(kqueue_fd_, NULL, 0, events, kMaxEvents, NULL));
 | 
| +    if (result == -1) {
 | 
| +      FATAL1("kevent failed %s\n", strerror(errno));
 | 
| +    } else {
 | 
| +      ASSERT(result <= kMaxEvents);
 | 
| +      for (int i = 0; i < result; i++) {
 | 
| +        HandleEvent(&events[i]);
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
| +  printf("shutting down debugger thread\n");
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void DebuggerConnectionImpl::SetupPollQueue() {
 | 
| +  int result;
 | 
| +  result = TEMP_FAILURE_RETRY(pipe(wakeup_fds_));
 | 
| +  if (result != 0) {
 | 
| +    FATAL1("Pipe creation failed with error %d\n", result);
 | 
| +  }
 | 
| +  FDUtils::SetNonBlocking(wakeup_fds_[0]);
 | 
| +
 | 
| +  kqueue_fd_ = TEMP_FAILURE_RETRY(kqueue());
 | 
| +  if (kqueue_fd_ == -1) {
 | 
| +    FATAL("Failed creating kqueue\n");
 | 
| +  }
 | 
| +  // Register the wakeup_fd_ with the kqueue.
 | 
| +  struct kevent event;
 | 
| +  EV_SET(&event, wakeup_fds_[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
 | 
| +  int status = TEMP_FAILURE_RETRY(kevent(kqueue_fd_, &event, 1, NULL, 0, NULL));
 | 
| +  if (status == -1) {
 | 
| +    FATAL1("Failed adding wakeup pipe fd to kqueue: %s\n", strerror(errno));
 | 
| +  }
 | 
| +
 | 
| +  // Register the listening socket.
 | 
| +  EV_SET(&event, DebuggerConnectionHandler::listener_fd_,
 | 
| +         EVFILT_READ, EV_ADD, 0, 0, NULL);
 | 
| +  status = TEMP_FAILURE_RETRY(kevent(kqueue_fd_, &event, 1, NULL, 0, NULL));
 | 
| +  if (status == -1) {
 | 
| +    FATAL1("Failed adding listener socket to kqueue: %s\n", strerror(errno));
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +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);
 | 
| +  }
 | 
| +}
 | 
| 
 |