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 |