blob: 6f89d8c778c8db65b0d2826d1d94861f8ac1ee73 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_PUBLIC_PLATFORM_DART_DART_HANDLE_WATCHER_H_
#define MOJO_PUBLIC_PLATFORM_DART_DART_HANDLE_WATCHER_H_
#include <thread>
#include "dart/runtime/include/dart_api.h"
#include "mojo/public/c/system/core.h"
#include "mojo/public/cpp/environment/logging.h"
#include "mojo/public/cpp/system/macros.h"
namespace mojo {
namespace dart {
#define MOJO_HANDLE_SIGNAL_ALL (MOJO_HANDLE_SIGNAL_READABLE | \
MOJO_HANDLE_SIGNAL_WRITABLE | \
MOJO_HANDLE_SIGNAL_PEER_CLOSED)
// HandleWatcherCommands are sent to HandleWatchers.
class HandleWatcherCommand {
public:
enum Command {
kCommandAddHandle = 0,
kCommandRemoveHandle = 1,
kCommandCloseHandle = 2,
kCommandAddTimer = 3,
kCommandShutdownHandleWatcher = 4,
};
// Construct a command to listen for |handle| to have |signals| and ping
// |port| when this happens.
static HandleWatcherCommand Add(MojoHandle handle,
MojoHandleSignals signals,
Dart_Port port) {
HandleWatcherCommand result;
result.handle_or_deadline_ = static_cast<int64_t>(handle);
result.port_ = port;
result.set_data(kCommandAddHandle, signals);
return result;
}
// Construct a command to stop listening for |handle|.
static HandleWatcherCommand Remove(MojoHandle handle) {
HandleWatcherCommand result;
result.handle_or_deadline_ = static_cast<int64_t>(handle);
result.port_ = ILLEGAL_PORT;
result.set_data(kCommandRemoveHandle, MOJO_HANDLE_SIGNAL_NONE);
return result;
}
// Construct a command to close |handle| and ping |port| when done.
static HandleWatcherCommand Close(MojoHandle handle,
Dart_Port port) {
HandleWatcherCommand result;
result.handle_or_deadline_ = static_cast<int64_t>(handle);
result.port_ = port;
result.set_data(kCommandCloseHandle, MOJO_HANDLE_SIGNAL_NONE);
return result;
}
// Construct a command to ping |port| when it is |deadline|.
static HandleWatcherCommand Timer(int64_t deadline,
Dart_Port port) {
HandleWatcherCommand result;
result.handle_or_deadline_ = deadline;
result.port_ = port;
result.set_data(kCommandAddTimer, MOJO_HANDLE_SIGNAL_NONE);
return result;
}
// Construct a command to shutdown the handle watcher thread.
static HandleWatcherCommand Shutdown(Dart_Port port) {
HandleWatcherCommand result;
result.handle_or_deadline_ = MOJO_HANDLE_INVALID;
result.port_ = port;
result.set_data(kCommandShutdownHandleWatcher, MOJO_HANDLE_SIGNAL_NONE);
return result;
}
// Construct an empty command.
static HandleWatcherCommand Empty() {
HandleWatcherCommand result;
return result;
}
// Construct a command sent from Dart code.
static HandleWatcherCommand FromDart(int64_t command,
int64_t handle_or_deadline,
Dart_Port port,
int64_t signals) {
switch (command) {
case kCommandAddHandle:
return Add(handle_or_deadline, signals, port);
break;
case kCommandRemoveHandle:
return Remove(handle_or_deadline);
break;
case kCommandCloseHandle:
return Close(handle_or_deadline, port);
break;
case kCommandAddTimer:
return Timer(handle_or_deadline, port);
break;
case kCommandShutdownHandleWatcher:
return Shutdown(port);
break;
default:
// Unreachable.
MOJO_CHECK(false);
return Empty();
}
}
// Get the command.
Command command() const {
return static_cast<Command>((data_ >> 3));
}
// Get the signals associated with the command.
MojoHandleSignals signals() const {
return data_ & MOJO_HANDLE_SIGNAL_ALL;
}
// Get the handle associated with the command.
MojoHandle handle() const {
return static_cast<MojoHandle>(handle_or_deadline_);
}
// Get the deadline associated with the command.
int64_t deadline() const {
return handle_or_deadline_;
}
// Get the port associated with the command.
Dart_Port port() const {
return port_;
}
private:
HandleWatcherCommand() {
handle_or_deadline_ = 0;
port_ = ILLEGAL_PORT;
data_ = 0;
}
void set_data(Command command, MojoHandleSignals signals) {
MOJO_CHECK(MOJO_HANDLE_SIGNAL_ALL < (1 << 3));
data_ = (command << 3) | (signals & MOJO_HANDLE_SIGNAL_ALL);
}
int64_t handle_or_deadline_;
Dart_Port port_;
int64_t data_;
};
// A Dart HandleWatcher can be started by calling |HandleWatcher::Start|.
// Each |Start| call creates a message pipe for communicating with the
// handle watcher and spawns a thread where the handle watcher waits for
// events on handles.
//
// NOTE: If multiple handle watchers are needed, |Start| can be safely called
// multiple times because all state is held inside the spawned thread.
class HandleWatcher {
public:
// Starts a new HandleWatcher thread and returns the message pipe handle
// that is used to communicate with the handle watcher. Returns
// the handle that should be passed to |SendCommand|.
static MojoHandle Start();
// Encode a |command| for the handle watcher and write it to
// |control_pipe_producer_handle|.
static MojoResult SendCommand(MojoHandle control_pipe_producer_handle,
const HandleWatcherCommand& command);
private:
static void ThreadMain(MojoHandle control_pipe_consumer_handle);
MOJO_DISALLOW_COPY_AND_ASSIGN(HandleWatcher);
};
} // namespace dart
} // namespace mojo
#endif // MOJO_PUBLIC_PLATFORM_DART_DART_HANDLE_WATCHER_H_