| // 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_ |