OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/edk/embedder/embedder.h" | 5 #include "mojo/edk/embedder/embedder.h" |
6 | 6 |
7 #include "base/atomicops.h" | 7 #include "base/atomicops.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/bind_helpers.h" |
9 #include "base/location.h" | 10 #include "base/location.h" |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
11 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
12 #include "base/message_loop/message_loop_proxy.h" | 13 #include "base/message_loop/message_loop_proxy.h" |
| 14 #include "base/task_runner.h" |
13 #include "mojo/edk/embedder/embedder_internal.h" | 15 #include "mojo/edk/embedder/embedder_internal.h" |
| 16 #include "mojo/edk/embedder/master_process_delegate.h" |
14 #include "mojo/edk/embedder/platform_support.h" | 17 #include "mojo/edk/embedder/platform_support.h" |
| 18 #include "mojo/edk/embedder/process_delegate.h" |
| 19 #include "mojo/edk/embedder/slave_process_delegate.h" |
15 #include "mojo/edk/system/channel.h" | 20 #include "mojo/edk/system/channel.h" |
16 #include "mojo/edk/system/channel_manager.h" | 21 #include "mojo/edk/system/channel_manager.h" |
17 #include "mojo/edk/system/configuration.h" | 22 #include "mojo/edk/system/configuration.h" |
| 23 #include "mojo/edk/system/connection_manager.h" |
18 #include "mojo/edk/system/core.h" | 24 #include "mojo/edk/system/core.h" |
| 25 #include "mojo/edk/system/master_connection_manager.h" |
19 #include "mojo/edk/system/message_pipe_dispatcher.h" | 26 #include "mojo/edk/system/message_pipe_dispatcher.h" |
20 #include "mojo/edk/system/platform_handle_dispatcher.h" | 27 #include "mojo/edk/system/platform_handle_dispatcher.h" |
21 #include "mojo/edk/system/raw_channel.h" | 28 #include "mojo/edk/system/raw_channel.h" |
| 29 #include "mojo/edk/system/slave_connection_manager.h" |
22 | 30 |
23 namespace mojo { | 31 namespace mojo { |
24 namespace embedder { | 32 namespace embedder { |
25 | 33 |
| 34 namespace internal { |
| 35 |
| 36 // Declared in embedder_internal.h. |
| 37 PlatformSupport* g_platform_support = nullptr; |
| 38 system::Core* g_core = nullptr; |
| 39 ProcessType g_process_type = ProcessType::UNINITIALIZED; |
| 40 |
| 41 } // namespace internal |
| 42 |
26 namespace { | 43 namespace { |
27 | 44 |
| 45 // The following global variables are set in |InitIPCSupport()| and reset by |
| 46 // |ShutdownIPCSupport()|/|ShutdownIPCSupportOnIOThread()|. |
| 47 |
| 48 // Note: This needs to be |AddRef()|ed/|Release()|d. |
| 49 base::TaskRunner* g_delegate_thread_task_runner = nullptr; |
| 50 |
| 51 ProcessDelegate* g_process_delegate = nullptr; |
| 52 |
| 53 // Note: This needs to be |AddRef()|ed/|Release()|d. |
| 54 base::TaskRunner* g_io_thread_task_runner = nullptr; |
| 55 |
| 56 // Instance of |ConnectionManager| used by the channel manager (below). |
| 57 system::ConnectionManager* g_connection_manager = nullptr; |
| 58 |
| 59 // Instance of |ChannelManager| used by the channel management functions |
| 60 // (|CreateChannel()|, etc.). |
| 61 system::ChannelManager* g_channel_manager = nullptr; |
| 62 |
28 // TODO(vtl): For now, we need this to be thread-safe (since theoretically we | 63 // TODO(vtl): For now, we need this to be thread-safe (since theoretically we |
29 // currently support multiple channel creation threads -- possibly one per | 64 // currently support multiple channel creation threads -- possibly one per |
30 // channel). Eventually, we won't need it to be thread-safe (we'll require a | 65 // channel). Eventually, we won't need it to be thread-safe (we'll require a |
31 // single I/O thread), and eventually we won't need it at all. Remember to | 66 // single I/O thread), and eventually we won't need it at all. Remember to |
32 // remove the base/atomicops.h include. | 67 // remove the base/atomicops.h include. |
33 system::ChannelId MakeChannelId() { | 68 system::ChannelId MakeChannelId() { |
34 // Note that |AtomicWord| is signed. | 69 // Note that |AtomicWord| is signed. |
35 static base::subtle::AtomicWord counter = 0; | 70 static base::subtle::AtomicWord counter = 0; |
36 | 71 |
37 base::subtle::AtomicWord new_counter_value = | 72 base::subtle::AtomicWord new_counter_value = |
38 base::subtle::NoBarrier_AtomicIncrement(&counter, 1); | 73 base::subtle::NoBarrier_AtomicIncrement(&counter, 1); |
39 // Don't allow the counter to wrap. Note that any (strictly) positive value is | 74 // Don't allow the counter to wrap. Note that any (strictly) positive value is |
40 // a valid |ChannelId| (and |NoBarrier_AtomicIncrement()| returns the value | 75 // a valid |ChannelId| (and |NoBarrier_AtomicIncrement()| returns the value |
41 // post-increment). | 76 // post-increment). |
42 CHECK_GT(new_counter_value, 0); | 77 CHECK_GT(new_counter_value, 0); |
43 // Use "negative" values for these IDs, so that we'll also be able to use | 78 // Use "negative" values for these IDs, so that we'll also be able to use |
44 // "positive" "process identifiers" (see connection_manager.h) as IDs (and | 79 // "positive" "process identifiers" (see connection_manager.h) as IDs (and |
45 // they won't conflict). | 80 // they won't conflict). |
46 return static_cast<system::ChannelId>(-new_counter_value); | 81 return static_cast<system::ChannelId>(-new_counter_value); |
47 } | 82 } |
48 | 83 |
| 84 // Note: Called on the I/O thread. |
| 85 void ShutdownIPCSupportHelper() { |
| 86 // Save these before nuking them using |ShutdownChannelOnIOThread()|. |
| 87 scoped_refptr<base::TaskRunner> delegate_thread_task_runner( |
| 88 g_delegate_thread_task_runner); |
| 89 ProcessDelegate* process_delegate = g_process_delegate; |
| 90 |
| 91 ShutdownIPCSupportOnIOThread(); |
| 92 |
| 93 bool ok = delegate_thread_task_runner->PostTask( |
| 94 FROM_HERE, base::Bind(&ProcessDelegate::OnShutdownComplete, |
| 95 base::Unretained(process_delegate))); |
| 96 DCHECK(ok); |
| 97 } |
| 98 |
49 } // namespace | 99 } // namespace |
50 | 100 |
51 namespace internal { | |
52 | |
53 // Declared in embedder_internal.h. | |
54 PlatformSupport* g_platform_support = nullptr; | |
55 system::Core* g_core = nullptr; | |
56 system::ChannelManager* g_channel_manager = nullptr; | |
57 MasterProcessDelegate* g_master_process_delegate = nullptr; | |
58 SlaveProcessDelegate* g_slave_process_delegate = nullptr; | |
59 | |
60 } // namespace internal | |
61 | |
62 Configuration* GetConfiguration() { | 101 Configuration* GetConfiguration() { |
63 return system::GetMutableConfiguration(); | 102 return system::GetMutableConfiguration(); |
64 } | 103 } |
65 | 104 |
66 void Init(scoped_ptr<PlatformSupport> platform_support) { | 105 void Init(scoped_ptr<PlatformSupport> platform_support) { |
67 DCHECK(platform_support); | 106 DCHECK(platform_support); |
68 | 107 |
69 DCHECK(!internal::g_platform_support); | 108 DCHECK(!internal::g_platform_support); |
70 internal::g_platform_support = platform_support.release(); | 109 internal::g_platform_support = platform_support.release(); |
71 | 110 |
72 DCHECK(!internal::g_core); | 111 DCHECK(!internal::g_core); |
73 internal::g_core = new system::Core(internal::g_platform_support); | 112 internal::g_core = new system::Core(internal::g_platform_support); |
74 | |
75 DCHECK(!internal::g_channel_manager); | |
76 internal::g_channel_manager = | |
77 new system::ChannelManager(internal::g_platform_support); | |
78 } | 113 } |
79 | 114 |
80 void InitMaster(scoped_refptr<base::TaskRunner> delegate_thread_task_runner, | 115 MojoResult AsyncWait(MojoHandle handle, |
81 MasterProcessDelegate* master_process_delegate, | 116 MojoHandleSignals signals, |
82 scoped_refptr<base::TaskRunner> io_thread_task_runner) { | 117 const base::Callback<void(MojoResult)>& callback) { |
| 118 return internal::g_core->AsyncWait(handle, signals, callback); |
| 119 } |
| 120 |
| 121 MojoResult CreatePlatformHandleWrapper( |
| 122 ScopedPlatformHandle platform_handle, |
| 123 MojoHandle* platform_handle_wrapper_handle) { |
| 124 DCHECK(platform_handle_wrapper_handle); |
| 125 |
| 126 scoped_refptr<system::Dispatcher> dispatcher( |
| 127 new system::PlatformHandleDispatcher(platform_handle.Pass())); |
| 128 |
| 129 DCHECK(internal::g_core); |
| 130 MojoHandle h = internal::g_core->AddDispatcher(dispatcher); |
| 131 if (h == MOJO_HANDLE_INVALID) { |
| 132 LOG(ERROR) << "Handle table full"; |
| 133 dispatcher->Close(); |
| 134 return MOJO_RESULT_RESOURCE_EXHAUSTED; |
| 135 } |
| 136 |
| 137 *platform_handle_wrapper_handle = h; |
| 138 return MOJO_RESULT_OK; |
| 139 } |
| 140 |
| 141 MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle, |
| 142 ScopedPlatformHandle* platform_handle) { |
| 143 DCHECK(platform_handle); |
| 144 |
| 145 DCHECK(internal::g_core); |
| 146 scoped_refptr<system::Dispatcher> dispatcher( |
| 147 internal::g_core->GetDispatcher(platform_handle_wrapper_handle)); |
| 148 if (!dispatcher) |
| 149 return MOJO_RESULT_INVALID_ARGUMENT; |
| 150 |
| 151 if (dispatcher->GetType() != system::Dispatcher::kTypePlatformHandle) |
| 152 return MOJO_RESULT_INVALID_ARGUMENT; |
| 153 |
| 154 *platform_handle = |
| 155 static_cast<system::PlatformHandleDispatcher*>(dispatcher.get()) |
| 156 ->PassPlatformHandle() |
| 157 .Pass(); |
| 158 return MOJO_RESULT_OK; |
| 159 } |
| 160 |
| 161 void InitIPCSupport(ProcessType process_type, |
| 162 scoped_refptr<base::TaskRunner> delegate_thread_task_runner, |
| 163 ProcessDelegate* process_delegate, |
| 164 scoped_refptr<base::TaskRunner> io_thread_task_runner, |
| 165 ScopedPlatformHandle platform_handle) { |
83 // |Init()| must have already been called. | 166 // |Init()| must have already been called. |
84 DCHECK(internal::g_core); | 167 DCHECK(internal::g_core); |
| 168 // And not |InitIPCSupport()| (without |ShutdownIPCSupport()|). |
| 169 DCHECK(internal::g_process_type == ProcessType::UNINITIALIZED); |
85 | 170 |
86 // TODO(vtl): This is temporary. We really want to construct a | 171 internal::g_process_type = process_type; |
87 // |MasterConnectionManager| here, which will in turn hold on to the delegate. | 172 |
88 internal::g_master_process_delegate = master_process_delegate; | 173 DCHECK(delegate_thread_task_runner); |
| 174 DCHECK(!g_delegate_thread_task_runner); |
| 175 g_delegate_thread_task_runner = delegate_thread_task_runner.get(); |
| 176 g_delegate_thread_task_runner->AddRef(); |
| 177 |
| 178 DCHECK(process_delegate->GetType() == process_type); |
| 179 DCHECK(!g_process_delegate); |
| 180 g_process_delegate = process_delegate; |
| 181 |
| 182 DCHECK(io_thread_task_runner); |
| 183 DCHECK(!g_io_thread_task_runner); |
| 184 g_io_thread_task_runner = io_thread_task_runner.get(); |
| 185 g_io_thread_task_runner->AddRef(); |
| 186 |
| 187 DCHECK(!g_connection_manager); |
| 188 switch (process_type) { |
| 189 case ProcessType::UNINITIALIZED: |
| 190 CHECK(false); |
| 191 break; |
| 192 case ProcessType::NONE: |
| 193 DCHECK(!platform_handle.is_valid()); // We wouldn't do anything with it. |
| 194 // Nothing to do. |
| 195 break; |
| 196 case ProcessType::MASTER: |
| 197 DCHECK(!platform_handle.is_valid()); // We wouldn't do anything with it. |
| 198 g_connection_manager = new system::MasterConnectionManager(); |
| 199 static_cast<system::MasterConnectionManager*>(g_connection_manager) |
| 200 ->Init(g_delegate_thread_task_runner, |
| 201 static_cast<MasterProcessDelegate*>(g_process_delegate)); |
| 202 break; |
| 203 case ProcessType::SLAVE: |
| 204 DCHECK(platform_handle.is_valid()); |
| 205 g_connection_manager = new system::SlaveConnectionManager(); |
| 206 static_cast<system::SlaveConnectionManager*>(g_connection_manager) |
| 207 ->Init(g_delegate_thread_task_runner, |
| 208 static_cast<SlaveProcessDelegate*>(g_process_delegate), |
| 209 platform_handle.Pass()); |
| 210 break; |
| 211 } |
| 212 |
| 213 DCHECK(!g_channel_manager); |
| 214 g_channel_manager = |
| 215 new system::ChannelManager(internal::g_platform_support, |
| 216 io_thread_task_runner, g_connection_manager); |
89 } | 217 } |
90 | 218 |
91 void InitSlave(scoped_refptr<base::TaskRunner> delegate_thread_task_runner, | 219 void ShutdownIPCSupportOnIOThread() { |
92 SlaveProcessDelegate* slave_process_delegate, | 220 DCHECK(internal::g_process_type != ProcessType::UNINITIALIZED); |
93 scoped_refptr<base::TaskRunner> io_thread_task_runner, | |
94 ScopedPlatformHandle platform_handle) { | |
95 // |Init()| must have already been called. | |
96 DCHECK(internal::g_core); | |
97 | 221 |
98 // TODO(vtl): This is temporary. We really want to construct a | 222 g_channel_manager->ShutdownOnIOThread(); |
99 // |SlaveConnectionManager| here, which will in turn hold on to the delegate. | 223 delete g_channel_manager; |
100 internal::g_slave_process_delegate = slave_process_delegate; | 224 g_channel_manager = nullptr; |
| 225 |
| 226 if (g_connection_manager) { |
| 227 g_connection_manager->Shutdown(); |
| 228 delete g_connection_manager; |
| 229 g_connection_manager = nullptr; |
| 230 } |
| 231 |
| 232 g_io_thread_task_runner->Release(); |
| 233 g_io_thread_task_runner = nullptr; |
| 234 |
| 235 g_delegate_thread_task_runner->Release(); |
| 236 g_delegate_thread_task_runner = nullptr; |
| 237 |
| 238 g_process_delegate = nullptr; |
| 239 |
| 240 internal::g_process_type = ProcessType::UNINITIALIZED; |
| 241 } |
| 242 |
| 243 void ShutdownIPCSupport() { |
| 244 DCHECK(internal::g_process_type != ProcessType::UNINITIALIZED); |
| 245 |
| 246 bool ok = g_io_thread_task_runner->PostTask( |
| 247 FROM_HERE, base::Bind(&ShutdownIPCSupportHelper)); |
| 248 DCHECK(ok); |
| 249 } |
| 250 |
| 251 void ConnectToSlave(SlaveInfo slave_info, |
| 252 ScopedPlatformHandle platform_handle) { |
| 253 DCHECK(platform_handle.is_valid()); |
| 254 DCHECK(internal::g_process_type == ProcessType::MASTER); |
| 255 static_cast<system::MasterConnectionManager*>(g_connection_manager) |
| 256 ->AddSlave(slave_info, platform_handle.Pass()); |
101 } | 257 } |
102 | 258 |
103 // TODO(vtl): Write tests for this. | 259 // TODO(vtl): Write tests for this. |
104 ScopedMessagePipeHandle CreateChannelOnIOThread( | 260 ScopedMessagePipeHandle CreateChannelOnIOThread( |
105 ScopedPlatformHandle platform_handle, | 261 ScopedPlatformHandle platform_handle, |
106 ChannelInfo** channel_info) { | 262 ChannelInfo** channel_info) { |
107 DCHECK(platform_handle.is_valid()); | 263 DCHECK(platform_handle.is_valid()); |
108 DCHECK(channel_info); | 264 DCHECK(channel_info); |
109 | 265 |
110 *channel_info = new ChannelInfo(MakeChannelId()); | 266 *channel_info = new ChannelInfo(MakeChannelId()); |
111 scoped_refptr<system::MessagePipeDispatcher> dispatcher = | 267 scoped_refptr<system::MessagePipeDispatcher> dispatcher = |
112 internal::g_channel_manager->CreateChannelOnIOThread( | 268 g_channel_manager->CreateChannelOnIOThread((*channel_info)->channel_id, |
113 (*channel_info)->channel_id, platform_handle.Pass()); | 269 platform_handle.Pass()); |
114 | 270 |
115 ScopedMessagePipeHandle rv( | 271 ScopedMessagePipeHandle rv( |
116 MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); | 272 MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); |
117 CHECK(rv.is_valid()); | 273 CHECK(rv.is_valid()); |
118 // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it | 274 // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it |
119 // once that's fixed. | 275 // once that's fixed. |
120 return rv.Pass(); | 276 return rv.Pass(); |
121 } | 277 } |
122 | 278 |
123 ScopedMessagePipeHandle CreateChannel( | 279 ScopedMessagePipeHandle CreateChannel( |
124 ScopedPlatformHandle platform_handle, | 280 ScopedPlatformHandle platform_handle, |
125 scoped_refptr<base::TaskRunner> io_thread_task_runner, | 281 scoped_refptr<base::TaskRunner> io_thread_task_runner, |
126 DidCreateChannelCallback callback, | 282 const DidCreateChannelCallback& callback, |
127 scoped_refptr<base::TaskRunner> callback_thread_task_runner) { | 283 scoped_refptr<base::TaskRunner> callback_thread_task_runner) { |
128 DCHECK(platform_handle.is_valid()); | 284 DCHECK(platform_handle.is_valid()); |
129 DCHECK(io_thread_task_runner); | 285 DCHECK(io_thread_task_runner); |
130 DCHECK(!callback.is_null()); | 286 DCHECK(!callback.is_null()); |
131 | 287 |
132 system::ChannelId channel_id = MakeChannelId(); | 288 system::ChannelId channel_id = MakeChannelId(); |
133 scoped_ptr<ChannelInfo> channel_info(new ChannelInfo(channel_id)); | 289 scoped_ptr<ChannelInfo> channel_info(new ChannelInfo(channel_id)); |
134 scoped_refptr<system::MessagePipeDispatcher> dispatcher = | 290 scoped_refptr<system::MessagePipeDispatcher> dispatcher = |
135 internal::g_channel_manager->CreateChannel( | 291 g_channel_manager->CreateChannel( |
136 channel_id, platform_handle.Pass(), io_thread_task_runner, | 292 channel_id, platform_handle.Pass(), io_thread_task_runner, |
137 base::Bind(callback, base::Unretained(channel_info.release())), | 293 base::Bind(callback, base::Unretained(channel_info.release())), |
138 callback_thread_task_runner); | 294 callback_thread_task_runner); |
139 | 295 |
140 ScopedMessagePipeHandle rv( | 296 ScopedMessagePipeHandle rv( |
141 MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); | 297 MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); |
142 CHECK(rv.is_valid()); | 298 CHECK(rv.is_valid()); |
143 // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it | 299 // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it |
144 // once that's fixed. | 300 // once that's fixed. |
145 return rv.Pass(); | 301 return rv.Pass(); |
146 } | 302 } |
147 | 303 |
148 // TODO(vtl): Write tests for this. | 304 // TODO(vtl): Write tests for this. |
149 void DestroyChannel(ChannelInfo* channel_info) { | 305 void DestroyChannelOnIOThread(ChannelInfo* channel_info) { |
150 DCHECK(channel_info); | 306 DCHECK(channel_info); |
151 DCHECK(channel_info->channel_id); | 307 DCHECK(channel_info->channel_id); |
152 DCHECK(internal::g_channel_manager); | 308 DCHECK(g_channel_manager); |
153 // This will destroy the channel synchronously if called from the channel | 309 g_channel_manager->ShutdownChannelOnIOThread(channel_info->channel_id); |
154 // thread. | 310 delete channel_info; |
155 internal::g_channel_manager->ShutdownChannel(channel_info->channel_id); | 311 } |
| 312 |
| 313 // TODO(vtl): Write tests for this. |
| 314 void DestroyChannel( |
| 315 ChannelInfo* channel_info, |
| 316 const DidDestroyChannelCallback& callback, |
| 317 scoped_refptr<base::TaskRunner> callback_thread_task_runner) { |
| 318 DCHECK(channel_info); |
| 319 DCHECK(channel_info->channel_id); |
| 320 DCHECK(!callback.is_null()); |
| 321 DCHECK(g_channel_manager); |
| 322 g_channel_manager->ShutdownChannel(channel_info->channel_id, callback, |
| 323 callback_thread_task_runner); |
156 delete channel_info; | 324 delete channel_info; |
157 } | 325 } |
158 | 326 |
159 void WillDestroyChannelSoon(ChannelInfo* channel_info) { | 327 void WillDestroyChannelSoon(ChannelInfo* channel_info) { |
160 DCHECK(channel_info); | 328 DCHECK(channel_info); |
161 DCHECK(internal::g_channel_manager); | 329 DCHECK(g_channel_manager); |
162 internal::g_channel_manager->WillShutdownChannel(channel_info->channel_id); | 330 g_channel_manager->WillShutdownChannel(channel_info->channel_id); |
163 } | |
164 | |
165 MojoResult CreatePlatformHandleWrapper( | |
166 ScopedPlatformHandle platform_handle, | |
167 MojoHandle* platform_handle_wrapper_handle) { | |
168 DCHECK(platform_handle_wrapper_handle); | |
169 | |
170 scoped_refptr<system::Dispatcher> dispatcher( | |
171 new system::PlatformHandleDispatcher(platform_handle.Pass())); | |
172 | |
173 DCHECK(internal::g_core); | |
174 MojoHandle h = internal::g_core->AddDispatcher(dispatcher); | |
175 if (h == MOJO_HANDLE_INVALID) { | |
176 LOG(ERROR) << "Handle table full"; | |
177 dispatcher->Close(); | |
178 return MOJO_RESULT_RESOURCE_EXHAUSTED; | |
179 } | |
180 | |
181 *platform_handle_wrapper_handle = h; | |
182 return MOJO_RESULT_OK; | |
183 } | |
184 | |
185 MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle, | |
186 ScopedPlatformHandle* platform_handle) { | |
187 DCHECK(platform_handle); | |
188 | |
189 DCHECK(internal::g_core); | |
190 scoped_refptr<system::Dispatcher> dispatcher( | |
191 internal::g_core->GetDispatcher(platform_handle_wrapper_handle)); | |
192 if (!dispatcher) | |
193 return MOJO_RESULT_INVALID_ARGUMENT; | |
194 | |
195 if (dispatcher->GetType() != system::Dispatcher::kTypePlatformHandle) | |
196 return MOJO_RESULT_INVALID_ARGUMENT; | |
197 | |
198 *platform_handle = | |
199 static_cast<system::PlatformHandleDispatcher*>(dispatcher.get()) | |
200 ->PassPlatformHandle() | |
201 .Pass(); | |
202 return MOJO_RESULT_OK; | |
203 } | |
204 | |
205 MojoResult AsyncWait(MojoHandle handle, | |
206 MojoHandleSignals signals, | |
207 base::Callback<void(MojoResult)> callback) { | |
208 return internal::g_core->AsyncWait(handle, signals, callback); | |
209 } | 331 } |
210 | 332 |
211 } // namespace embedder | 333 } // namespace embedder |
212 } // namespace mojo | 334 } // namespace mojo |
OLD | NEW |