| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef MOJO_PUBLIC_PLATFORM_DART_DART_HANDLE_WATCHER_H_ | |
| 6 #define MOJO_PUBLIC_PLATFORM_DART_DART_HANDLE_WATCHER_H_ | |
| 7 | |
| 8 #include <mojo/result.h> | |
| 9 #include <mojo/system/handle.h> | |
| 10 | |
| 11 #include <mutex> | |
| 12 #include <thread> | |
| 13 #include <unordered_map> | |
| 14 | |
| 15 #include "dart/runtime/include/dart_api.h" | |
| 16 | |
| 17 #include "mojo/public/cpp/environment/logging.h" | |
| 18 #include "mojo/public/cpp/system/macros.h" | |
| 19 | |
| 20 namespace mojo { | |
| 21 namespace dart { | |
| 22 | |
| 23 #define MOJO_HANDLE_SIGNAL_ALL (MOJO_HANDLE_SIGNAL_READABLE | \ | |
| 24 MOJO_HANDLE_SIGNAL_WRITABLE | \ | |
| 25 MOJO_HANDLE_SIGNAL_PEER_CLOSED) | |
| 26 | |
| 27 // HandleWatcherCommands are sent to HandleWatchers. | |
| 28 class HandleWatcherCommand { | |
| 29 public: | |
| 30 enum Command { | |
| 31 kCommandAddHandle = 0, | |
| 32 kCommandRemoveHandle = 1, | |
| 33 kCommandCloseHandle = 2, | |
| 34 kCommandAddTimer = 3, | |
| 35 kCommandShutdownHandleWatcher = 4, | |
| 36 }; | |
| 37 | |
| 38 // Construct a command to listen for |handle| to have |signals| and ping | |
| 39 // |port| when this happens. | |
| 40 static HandleWatcherCommand Add(MojoHandle handle, | |
| 41 MojoHandleSignals signals, | |
| 42 Dart_Port port) { | |
| 43 HandleWatcherCommand result; | |
| 44 result.handle_or_deadline_ = static_cast<int64_t>(handle); | |
| 45 result.port_ = port; | |
| 46 result.set_data(kCommandAddHandle, signals); | |
| 47 return result; | |
| 48 } | |
| 49 | |
| 50 // Construct a command to stop listening for |handle|. | |
| 51 static HandleWatcherCommand Remove(MojoHandle handle) { | |
| 52 HandleWatcherCommand result; | |
| 53 result.handle_or_deadline_ = static_cast<int64_t>(handle); | |
| 54 result.port_ = ILLEGAL_PORT; | |
| 55 result.set_data(kCommandRemoveHandle, MOJO_HANDLE_SIGNAL_NONE); | |
| 56 return result; | |
| 57 } | |
| 58 | |
| 59 // Construct a command to close |handle| and ping |port| when done. | |
| 60 static HandleWatcherCommand Close(MojoHandle handle, | |
| 61 Dart_Port port) { | |
| 62 HandleWatcherCommand result; | |
| 63 result.handle_or_deadline_ = static_cast<int64_t>(handle); | |
| 64 result.port_ = port; | |
| 65 result.set_data(kCommandCloseHandle, MOJO_HANDLE_SIGNAL_NONE); | |
| 66 return result; | |
| 67 } | |
| 68 | |
| 69 // Construct a command to ping |port| when it is |deadline|. | |
| 70 static HandleWatcherCommand Timer(int64_t deadline, | |
| 71 Dart_Port port) { | |
| 72 HandleWatcherCommand result; | |
| 73 result.handle_or_deadline_ = deadline; | |
| 74 result.port_ = port; | |
| 75 result.set_data(kCommandAddTimer, MOJO_HANDLE_SIGNAL_NONE); | |
| 76 return result; | |
| 77 } | |
| 78 | |
| 79 // Construct a command to shutdown the handle watcher thread. | |
| 80 static HandleWatcherCommand Shutdown() { | |
| 81 HandleWatcherCommand result; | |
| 82 result.handle_or_deadline_ = MOJO_HANDLE_INVALID; | |
| 83 result.port_ = ILLEGAL_PORT; | |
| 84 result.set_data(kCommandShutdownHandleWatcher, MOJO_HANDLE_SIGNAL_NONE); | |
| 85 return result; | |
| 86 } | |
| 87 | |
| 88 // Construct an empty command. | |
| 89 static HandleWatcherCommand Empty() { | |
| 90 HandleWatcherCommand result; | |
| 91 return result; | |
| 92 } | |
| 93 | |
| 94 // Construct a command sent from Dart code. | |
| 95 static HandleWatcherCommand FromDart(int64_t command, | |
| 96 int64_t handle_or_deadline, | |
| 97 Dart_Port port, | |
| 98 int64_t signals) { | |
| 99 switch (command) { | |
| 100 case kCommandAddHandle: | |
| 101 return Add(handle_or_deadline, signals, port); | |
| 102 break; | |
| 103 case kCommandRemoveHandle: | |
| 104 return Remove(handle_or_deadline); | |
| 105 break; | |
| 106 case kCommandCloseHandle: | |
| 107 return Close(handle_or_deadline, port); | |
| 108 break; | |
| 109 case kCommandAddTimer: | |
| 110 return Timer(handle_or_deadline, port); | |
| 111 break; | |
| 112 case kCommandShutdownHandleWatcher: | |
| 113 return Shutdown(); | |
| 114 break; | |
| 115 default: | |
| 116 // Unreachable. | |
| 117 MOJO_CHECK(false); | |
| 118 return Empty(); | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 // Get the command. | |
| 123 Command command() const { | |
| 124 return static_cast<Command>((data_ >> 3)); | |
| 125 } | |
| 126 | |
| 127 // Get the signals associated with the command. | |
| 128 MojoHandleSignals signals() const { | |
| 129 return data_ & MOJO_HANDLE_SIGNAL_ALL; | |
| 130 } | |
| 131 | |
| 132 // Get the handle associated with the command. | |
| 133 MojoHandle handle() const { | |
| 134 return static_cast<MojoHandle>(handle_or_deadline_); | |
| 135 } | |
| 136 | |
| 137 // Get the deadline associated with the command. | |
| 138 int64_t deadline() const { | |
| 139 return handle_or_deadline_; | |
| 140 } | |
| 141 | |
| 142 // Get the port associated with the command. | |
| 143 Dart_Port port() const { | |
| 144 return port_; | |
| 145 } | |
| 146 | |
| 147 private: | |
| 148 HandleWatcherCommand() { | |
| 149 handle_or_deadline_ = 0; | |
| 150 port_ = ILLEGAL_PORT; | |
| 151 data_ = 0; | |
| 152 } | |
| 153 | |
| 154 void set_data(Command command, MojoHandleSignals signals) { | |
| 155 MOJO_CHECK(MOJO_HANDLE_SIGNAL_ALL < (1 << 3)); | |
| 156 data_ = (command << 3) | (signals & MOJO_HANDLE_SIGNAL_ALL); | |
| 157 } | |
| 158 | |
| 159 int64_t handle_or_deadline_; | |
| 160 Dart_Port port_; | |
| 161 int64_t data_; | |
| 162 }; | |
| 163 | |
| 164 | |
| 165 // A Dart HandleWatcher can be started by calling |HandleWatcher::Start|. | |
| 166 // Each |Start| call creates a message pipe for communicating with the | |
| 167 // handle watcher and spawns a thread where the handle watcher waits for | |
| 168 // events on handles. | |
| 169 // | |
| 170 // NOTE: If multiple handle watchers are needed, |Start| can be safely called | |
| 171 // multiple times because all state is held inside the spawned thread. | |
| 172 class HandleWatcher { | |
| 173 public: | |
| 174 // Starts a new HandleWatcher thread and returns the message pipe handle | |
| 175 // that is used to communicate with the handle watcher. Returns | |
| 176 // the handle that should be passed to |SendCommand|. | |
| 177 static MojoHandle Start(); | |
| 178 | |
| 179 // Encode a |command| for the handle watcher and write it to | |
| 180 // |control_pipe_producer_handle|. | |
| 181 static MojoResult SendCommand(MojoHandle control_pipe_producer_handle, | |
| 182 const HandleWatcherCommand& command); | |
| 183 | |
| 184 // Stops and joins the handle watcher thread at the other end of the | |
| 185 // given pipe handle. | |
| 186 static void Stop(MojoHandle control_pipe_consumer_handle); | |
| 187 | |
| 188 // Stops and joins all handle watcher threads. | |
| 189 static void StopAll(); | |
| 190 | |
| 191 private: | |
| 192 static void ThreadMain(MojoHandle control_pipe_consumer_handle); | |
| 193 | |
| 194 // Remove the mapping for |handle| from |handle_watcher_threads_| and return | |
| 195 // the associated thread object. Assumes |handle_watcher_threads_mutex_| is | |
| 196 // held. | |
| 197 static std::thread* RemoveLocked(MojoHandle handle); | |
| 198 | |
| 199 // Remove the mapping for |handle| from |handle_watcher_threads_| and join | |
| 200 // the associated thread. Assumes |handle_watcher_threads_mutex_| is held. | |
| 201 static void StopLocked(MojoHandle handle); | |
| 202 | |
| 203 // A mapping from control handle to handle watcher thread. | |
| 204 static std::unordered_map<MojoHandle, std::thread*> handle_watcher_threads_; | |
| 205 | |
| 206 // Protects |handle_watcher_threads_| | |
| 207 static std::mutex handle_watcher_threads_mutex_; | |
| 208 | |
| 209 MOJO_DISALLOW_COPY_AND_ASSIGN(HandleWatcher); | |
| 210 }; | |
| 211 | |
| 212 | |
| 213 } // namespace dart | |
| 214 } // namespace mojo | |
| 215 | |
| 216 #endif // MOJO_PUBLIC_PLATFORM_DART_DART_HANDLE_WATCHER_H_ | |
| OLD | NEW |