OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 #include "third_party/mojo/src/mojo/edk/system/dispatcher.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "third_party/mojo/src/mojo/edk/system/configuration.h" | |
9 #include "third_party/mojo/src/mojo/edk/system/data_pipe_consumer_dispatcher.h" | |
10 #include "third_party/mojo/src/mojo/edk/system/data_pipe_producer_dispatcher.h" | |
11 #include "third_party/mojo/src/mojo/edk/system/message_pipe_dispatcher.h" | |
12 #include "third_party/mojo/src/mojo/edk/system/platform_handle_dispatcher.h" | |
13 #include "third_party/mojo/src/mojo/edk/system/shared_buffer_dispatcher.h" | |
14 | |
15 namespace mojo { | |
16 namespace system { | |
17 | |
18 namespace test { | |
19 | |
20 // TODO(vtl): Maybe this should be defined in a test-only file instead. | |
21 DispatcherTransport DispatcherTryStartTransport(Dispatcher* dispatcher) { | |
22 return Dispatcher::HandleTableAccess::TryStartTransport(dispatcher); | |
23 } | |
24 | |
25 } // namespace test | |
26 | |
27 // Dispatcher ------------------------------------------------------------------ | |
28 | |
29 // TODO(vtl): The thread-safety analyzer isn't smart enough to deal with the | |
30 // fact that we give up if |TryLock()| fails. | |
31 // static | |
32 DispatcherTransport Dispatcher::HandleTableAccess::TryStartTransport( | |
33 Dispatcher* dispatcher) MOJO_NO_THREAD_SAFETY_ANALYSIS { | |
34 DCHECK(dispatcher); | |
35 | |
36 if (!dispatcher->mutex_.TryLock()) | |
37 return DispatcherTransport(); | |
38 | |
39 // We shouldn't race with things that close dispatchers, since closing can | |
40 // only take place either under |handle_table_mutex_| or when the handle is | |
41 // marked as busy. | |
42 DCHECK(!dispatcher->is_closed_); | |
43 | |
44 return DispatcherTransport(dispatcher); | |
45 } | |
46 | |
47 // static | |
48 void Dispatcher::TransportDataAccess::StartSerialize( | |
49 Dispatcher* dispatcher, | |
50 Channel* channel, | |
51 size_t* max_size, | |
52 size_t* max_platform_handles) { | |
53 DCHECK(dispatcher); | |
54 dispatcher->StartSerialize(channel, max_size, max_platform_handles); | |
55 } | |
56 | |
57 // static | |
58 bool Dispatcher::TransportDataAccess::EndSerializeAndClose( | |
59 Dispatcher* dispatcher, | |
60 Channel* channel, | |
61 void* destination, | |
62 size_t* actual_size, | |
63 embedder::PlatformHandleVector* platform_handles) { | |
64 DCHECK(dispatcher); | |
65 return dispatcher->EndSerializeAndClose(channel, destination, actual_size, | |
66 platform_handles); | |
67 } | |
68 | |
69 // static | |
70 scoped_refptr<Dispatcher> Dispatcher::TransportDataAccess::Deserialize( | |
71 Channel* channel, | |
72 int32_t type, | |
73 const void* source, | |
74 size_t size, | |
75 embedder::PlatformHandleVector* platform_handles) { | |
76 switch (static_cast<Dispatcher::Type>(type)) { | |
77 case Type::WAIT_SET: | |
78 case Type::UNKNOWN: | |
79 DVLOG(2) << "Deserializing invalid handle"; | |
80 return nullptr; | |
81 case Type::MESSAGE_PIPE: | |
82 return scoped_refptr<Dispatcher>( | |
83 MessagePipeDispatcher::Deserialize(channel, source, size)); | |
84 case Type::DATA_PIPE_PRODUCER: | |
85 return scoped_refptr<Dispatcher>( | |
86 DataPipeProducerDispatcher::Deserialize(channel, source, size)); | |
87 case Type::DATA_PIPE_CONSUMER: | |
88 return scoped_refptr<Dispatcher>( | |
89 DataPipeConsumerDispatcher::Deserialize(channel, source, size)); | |
90 case Type::SHARED_BUFFER: | |
91 return scoped_refptr<Dispatcher>(SharedBufferDispatcher::Deserialize( | |
92 channel, source, size, platform_handles)); | |
93 case Type::PLATFORM_HANDLE: | |
94 return scoped_refptr<Dispatcher>(PlatformHandleDispatcher::Deserialize( | |
95 channel, source, size, platform_handles)); | |
96 } | |
97 LOG(WARNING) << "Unknown dispatcher type " << type; | |
98 return nullptr; | |
99 } | |
100 | |
101 MojoResult Dispatcher::Close() { | |
102 MutexLocker locker(&mutex_); | |
103 if (is_closed_) | |
104 return MOJO_RESULT_INVALID_ARGUMENT; | |
105 | |
106 CloseNoLock(); | |
107 return MOJO_RESULT_OK; | |
108 } | |
109 | |
110 MojoResult Dispatcher::WriteMessage( | |
111 UserPointer<const void> bytes, | |
112 uint32_t num_bytes, | |
113 std::vector<DispatcherTransport>* transports, | |
114 MojoWriteMessageFlags flags) { | |
115 DCHECK(!transports || | |
116 (transports->size() > 0 && | |
117 transports->size() < GetConfiguration().max_message_num_handles)); | |
118 | |
119 MutexLocker locker(&mutex_); | |
120 if (is_closed_) | |
121 return MOJO_RESULT_INVALID_ARGUMENT; | |
122 | |
123 return WriteMessageImplNoLock(bytes, num_bytes, transports, flags); | |
124 } | |
125 | |
126 MojoResult Dispatcher::ReadMessage(UserPointer<void> bytes, | |
127 UserPointer<uint32_t> num_bytes, | |
128 DispatcherVector* dispatchers, | |
129 uint32_t* num_dispatchers, | |
130 MojoReadMessageFlags flags) { | |
131 DCHECK(!num_dispatchers || *num_dispatchers == 0 || | |
132 (dispatchers && dispatchers->empty())); | |
133 | |
134 MutexLocker locker(&mutex_); | |
135 if (is_closed_) | |
136 return MOJO_RESULT_INVALID_ARGUMENT; | |
137 | |
138 return ReadMessageImplNoLock(bytes, num_bytes, dispatchers, num_dispatchers, | |
139 flags); | |
140 } | |
141 | |
142 MojoResult Dispatcher::WriteData(UserPointer<const void> elements, | |
143 UserPointer<uint32_t> num_bytes, | |
144 MojoWriteDataFlags flags) { | |
145 MutexLocker locker(&mutex_); | |
146 if (is_closed_) | |
147 return MOJO_RESULT_INVALID_ARGUMENT; | |
148 | |
149 return WriteDataImplNoLock(elements, num_bytes, flags); | |
150 } | |
151 | |
152 MojoResult Dispatcher::BeginWriteData(UserPointer<void*> buffer, | |
153 UserPointer<uint32_t> buffer_num_bytes, | |
154 MojoWriteDataFlags flags) { | |
155 MutexLocker locker(&mutex_); | |
156 if (is_closed_) | |
157 return MOJO_RESULT_INVALID_ARGUMENT; | |
158 | |
159 return BeginWriteDataImplNoLock(buffer, buffer_num_bytes, flags); | |
160 } | |
161 | |
162 MojoResult Dispatcher::EndWriteData(uint32_t num_bytes_written) { | |
163 MutexLocker locker(&mutex_); | |
164 if (is_closed_) | |
165 return MOJO_RESULT_INVALID_ARGUMENT; | |
166 | |
167 return EndWriteDataImplNoLock(num_bytes_written); | |
168 } | |
169 | |
170 MojoResult Dispatcher::ReadData(UserPointer<void> elements, | |
171 UserPointer<uint32_t> num_bytes, | |
172 MojoReadDataFlags flags) { | |
173 MutexLocker locker(&mutex_); | |
174 if (is_closed_) | |
175 return MOJO_RESULT_INVALID_ARGUMENT; | |
176 | |
177 return ReadDataImplNoLock(elements, num_bytes, flags); | |
178 } | |
179 | |
180 MojoResult Dispatcher::BeginReadData(UserPointer<const void*> buffer, | |
181 UserPointer<uint32_t> buffer_num_bytes, | |
182 MojoReadDataFlags flags) { | |
183 MutexLocker locker(&mutex_); | |
184 if (is_closed_) | |
185 return MOJO_RESULT_INVALID_ARGUMENT; | |
186 | |
187 return BeginReadDataImplNoLock(buffer, buffer_num_bytes, flags); | |
188 } | |
189 | |
190 MojoResult Dispatcher::EndReadData(uint32_t num_bytes_read) { | |
191 MutexLocker locker(&mutex_); | |
192 if (is_closed_) | |
193 return MOJO_RESULT_INVALID_ARGUMENT; | |
194 | |
195 return EndReadDataImplNoLock(num_bytes_read); | |
196 } | |
197 | |
198 MojoResult Dispatcher::DuplicateBufferHandle( | |
199 UserPointer<const MojoDuplicateBufferHandleOptions> options, | |
200 scoped_refptr<Dispatcher>* new_dispatcher) { | |
201 MutexLocker locker(&mutex_); | |
202 if (is_closed_) | |
203 return MOJO_RESULT_INVALID_ARGUMENT; | |
204 | |
205 return DuplicateBufferHandleImplNoLock(options, new_dispatcher); | |
206 } | |
207 | |
208 MojoResult Dispatcher::MapBuffer( | |
209 uint64_t offset, | |
210 uint64_t num_bytes, | |
211 MojoMapBufferFlags flags, | |
212 scoped_ptr<embedder::PlatformSharedBufferMapping>* mapping) { | |
213 MutexLocker locker(&mutex_); | |
214 if (is_closed_) | |
215 return MOJO_RESULT_INVALID_ARGUMENT; | |
216 | |
217 return MapBufferImplNoLock(offset, num_bytes, flags, mapping); | |
218 } | |
219 | |
220 HandleSignalsState Dispatcher::GetHandleSignalsState() const { | |
221 MutexLocker locker(&mutex_); | |
222 if (is_closed_) | |
223 return HandleSignalsState(); | |
224 | |
225 return GetHandleSignalsStateImplNoLock(); | |
226 } | |
227 | |
228 MojoResult Dispatcher::AddAwakable(Awakable* awakable, | |
229 MojoHandleSignals signals, | |
230 uintptr_t context, | |
231 HandleSignalsState* signals_state) { | |
232 MutexLocker locker(&mutex_); | |
233 if (is_closed_) { | |
234 if (signals_state) | |
235 *signals_state = HandleSignalsState(); | |
236 return MOJO_RESULT_INVALID_ARGUMENT; | |
237 } | |
238 | |
239 return AddAwakableImplNoLock(awakable, signals, context, signals_state); | |
240 } | |
241 | |
242 void Dispatcher::RemoveAwakable(Awakable* awakable, | |
243 HandleSignalsState* handle_signals_state) { | |
244 MutexLocker locker(&mutex_); | |
245 if (is_closed_) { | |
246 if (handle_signals_state) | |
247 *handle_signals_state = HandleSignalsState(); | |
248 return; | |
249 } | |
250 | |
251 RemoveAwakableImplNoLock(awakable, handle_signals_state); | |
252 } | |
253 | |
254 MojoResult Dispatcher::AddWaitingDispatcher( | |
255 const scoped_refptr<Dispatcher>& dispatcher, | |
256 MojoHandleSignals signals, | |
257 uintptr_t context) { | |
258 MutexLocker locker(&mutex_); | |
259 if (is_closed_) | |
260 return MOJO_RESULT_INVALID_ARGUMENT; | |
261 | |
262 return AddWaitingDispatcherImplNoLock(dispatcher, signals, context); | |
263 } | |
264 | |
265 MojoResult Dispatcher::RemoveWaitingDispatcher( | |
266 const scoped_refptr<Dispatcher>& dispatcher) { | |
267 MutexLocker locker(&mutex_); | |
268 if (is_closed_) | |
269 return MOJO_RESULT_INVALID_ARGUMENT; | |
270 | |
271 return RemoveWaitingDispatcherImplNoLock(dispatcher); | |
272 } | |
273 | |
274 MojoResult Dispatcher::GetReadyDispatchers(UserPointer<uint32_t> count, | |
275 DispatcherVector* dispatchers, | |
276 UserPointer<MojoResult> results, | |
277 UserPointer<uintptr_t> contexts) { | |
278 MutexLocker locker(&mutex_); | |
279 if (is_closed_) | |
280 return MOJO_RESULT_INVALID_ARGUMENT; | |
281 | |
282 return GetReadyDispatchersImplNoLock(count, dispatchers, results, contexts); | |
283 } | |
284 | |
285 Dispatcher::Dispatcher() : is_closed_(false) { | |
286 } | |
287 | |
288 Dispatcher::~Dispatcher() { | |
289 // Make sure that |Close()| was called. | |
290 DCHECK(is_closed_); | |
291 } | |
292 | |
293 void Dispatcher::CancelAllAwakablesNoLock() { | |
294 mutex_.AssertHeld(); | |
295 DCHECK(is_closed_); | |
296 // By default, waiting isn't supported. Only dispatchers that can be waited on | |
297 // will do something nontrivial. | |
298 } | |
299 | |
300 void Dispatcher::CloseImplNoLock() { | |
301 mutex_.AssertHeld(); | |
302 DCHECK(is_closed_); | |
303 // This may not need to do anything. Dispatchers should override this to do | |
304 // any actual close-time cleanup necessary. | |
305 } | |
306 | |
307 MojoResult Dispatcher::WriteMessageImplNoLock( | |
308 UserPointer<const void> /*bytes*/, | |
309 uint32_t /*num_bytes*/, | |
310 std::vector<DispatcherTransport>* /*transports*/, | |
311 MojoWriteMessageFlags /*flags*/) { | |
312 mutex_.AssertHeld(); | |
313 DCHECK(!is_closed_); | |
314 // By default, not supported. Only needed for message pipe dispatchers. | |
315 return MOJO_RESULT_INVALID_ARGUMENT; | |
316 } | |
317 | |
318 MojoResult Dispatcher::ReadMessageImplNoLock( | |
319 UserPointer<void> /*bytes*/, | |
320 UserPointer<uint32_t> /*num_bytes*/, | |
321 DispatcherVector* /*dispatchers*/, | |
322 uint32_t* /*num_dispatchers*/, | |
323 MojoReadMessageFlags /*flags*/) { | |
324 mutex_.AssertHeld(); | |
325 DCHECK(!is_closed_); | |
326 // By default, not supported. Only needed for message pipe dispatchers. | |
327 return MOJO_RESULT_INVALID_ARGUMENT; | |
328 } | |
329 | |
330 MojoResult Dispatcher::WriteDataImplNoLock(UserPointer<const void> /*elements*/, | |
331 UserPointer<uint32_t> /*num_bytes*/, | |
332 MojoWriteDataFlags /*flags*/) { | |
333 mutex_.AssertHeld(); | |
334 DCHECK(!is_closed_); | |
335 // By default, not supported. Only needed for data pipe dispatchers. | |
336 return MOJO_RESULT_INVALID_ARGUMENT; | |
337 } | |
338 | |
339 MojoResult Dispatcher::BeginWriteDataImplNoLock( | |
340 UserPointer<void*> /*buffer*/, | |
341 UserPointer<uint32_t> /*buffer_num_bytes*/, | |
342 MojoWriteDataFlags /*flags*/) { | |
343 mutex_.AssertHeld(); | |
344 DCHECK(!is_closed_); | |
345 // By default, not supported. Only needed for data pipe dispatchers. | |
346 return MOJO_RESULT_INVALID_ARGUMENT; | |
347 } | |
348 | |
349 MojoResult Dispatcher::EndWriteDataImplNoLock(uint32_t /*num_bytes_written*/) { | |
350 mutex_.AssertHeld(); | |
351 DCHECK(!is_closed_); | |
352 // By default, not supported. Only needed for data pipe dispatchers. | |
353 return MOJO_RESULT_INVALID_ARGUMENT; | |
354 } | |
355 | |
356 MojoResult Dispatcher::ReadDataImplNoLock(UserPointer<void> /*elements*/, | |
357 UserPointer<uint32_t> /*num_bytes*/, | |
358 MojoReadDataFlags /*flags*/) { | |
359 mutex_.AssertHeld(); | |
360 DCHECK(!is_closed_); | |
361 // By default, not supported. Only needed for data pipe dispatchers. | |
362 return MOJO_RESULT_INVALID_ARGUMENT; | |
363 } | |
364 | |
365 MojoResult Dispatcher::BeginReadDataImplNoLock( | |
366 UserPointer<const void*> /*buffer*/, | |
367 UserPointer<uint32_t> /*buffer_num_bytes*/, | |
368 MojoReadDataFlags /*flags*/) { | |
369 mutex_.AssertHeld(); | |
370 DCHECK(!is_closed_); | |
371 // By default, not supported. Only needed for data pipe dispatchers. | |
372 return MOJO_RESULT_INVALID_ARGUMENT; | |
373 } | |
374 | |
375 MojoResult Dispatcher::EndReadDataImplNoLock(uint32_t /*num_bytes_read*/) { | |
376 mutex_.AssertHeld(); | |
377 DCHECK(!is_closed_); | |
378 // By default, not supported. Only needed for data pipe dispatchers. | |
379 return MOJO_RESULT_INVALID_ARGUMENT; | |
380 } | |
381 | |
382 MojoResult Dispatcher::DuplicateBufferHandleImplNoLock( | |
383 UserPointer<const MojoDuplicateBufferHandleOptions> /*options*/, | |
384 scoped_refptr<Dispatcher>* /*new_dispatcher*/) { | |
385 mutex_.AssertHeld(); | |
386 DCHECK(!is_closed_); | |
387 // By default, not supported. Only needed for buffer dispatchers. | |
388 return MOJO_RESULT_INVALID_ARGUMENT; | |
389 } | |
390 | |
391 MojoResult Dispatcher::MapBufferImplNoLock( | |
392 uint64_t /*offset*/, | |
393 uint64_t /*num_bytes*/, | |
394 MojoMapBufferFlags /*flags*/, | |
395 scoped_ptr<embedder::PlatformSharedBufferMapping>* /*mapping*/) { | |
396 mutex_.AssertHeld(); | |
397 DCHECK(!is_closed_); | |
398 // By default, not supported. Only needed for buffer dispatchers. | |
399 return MOJO_RESULT_INVALID_ARGUMENT; | |
400 } | |
401 | |
402 HandleSignalsState Dispatcher::GetHandleSignalsStateImplNoLock() const { | |
403 mutex_.AssertHeld(); | |
404 DCHECK(!is_closed_); | |
405 // By default, waiting isn't supported. Only dispatchers that can be waited on | |
406 // will do something nontrivial. | |
407 return HandleSignalsState(); | |
408 } | |
409 | |
410 MojoResult Dispatcher::AddAwakableImplNoLock( | |
411 Awakable* /*awakable*/, | |
412 MojoHandleSignals /*signals*/, | |
413 uintptr_t /*context*/, | |
414 HandleSignalsState* signals_state) { | |
415 mutex_.AssertHeld(); | |
416 DCHECK(!is_closed_); | |
417 // By default, waiting isn't supported. Only dispatchers that can be waited on | |
418 // will do something nontrivial. | |
419 if (signals_state) | |
420 *signals_state = HandleSignalsState(); | |
421 return MOJO_RESULT_FAILED_PRECONDITION; | |
422 } | |
423 | |
424 MojoResult Dispatcher::AddWaitingDispatcherImplNoLock( | |
425 const scoped_refptr<Dispatcher>& /*dispatcher*/, | |
426 MojoHandleSignals /*signals*/, | |
427 uintptr_t /*context*/) { | |
428 mutex_.AssertHeld(); | |
429 DCHECK(!is_closed_); | |
430 // By default, not supported. Only needed for wait set dispatchers. | |
431 return MOJO_RESULT_INVALID_ARGUMENT; | |
432 } | |
433 | |
434 MojoResult Dispatcher::RemoveWaitingDispatcherImplNoLock( | |
435 const scoped_refptr<Dispatcher>& /*dispatcher*/) { | |
436 mutex_.AssertHeld(); | |
437 DCHECK(!is_closed_); | |
438 // By default, not supported. Only needed for wait set dispatchers. | |
439 return MOJO_RESULT_INVALID_ARGUMENT; | |
440 } | |
441 | |
442 MojoResult Dispatcher::GetReadyDispatchersImplNoLock( | |
443 UserPointer<uint32_t> /*count*/, | |
444 DispatcherVector* /*dispatchers*/, | |
445 UserPointer<MojoResult> /*results*/, | |
446 UserPointer<uintptr_t> /*contexts*/) { | |
447 mutex_.AssertHeld(); | |
448 DCHECK(!is_closed_); | |
449 // By default, not supported. Only needed for wait set dispatchers. | |
450 return MOJO_RESULT_INVALID_ARGUMENT; | |
451 } | |
452 | |
453 void Dispatcher::RemoveAwakableImplNoLock(Awakable* /*awakable*/, | |
454 HandleSignalsState* signals_state) { | |
455 mutex_.AssertHeld(); | |
456 DCHECK(!is_closed_); | |
457 // By default, waiting isn't supported. Only dispatchers that can be waited on | |
458 // will do something nontrivial. | |
459 if (signals_state) | |
460 *signals_state = HandleSignalsState(); | |
461 } | |
462 | |
463 void Dispatcher::StartSerializeImplNoLock(Channel* /*channel*/, | |
464 size_t* max_size, | |
465 size_t* max_platform_handles) { | |
466 DCHECK(HasOneRef()); // Only one ref => no need to take the lock. | |
467 DCHECK(!is_closed_); | |
468 *max_size = 0; | |
469 *max_platform_handles = 0; | |
470 } | |
471 | |
472 bool Dispatcher::EndSerializeAndCloseImplNoLock( | |
473 Channel* /*channel*/, | |
474 void* /*destination*/, | |
475 size_t* /*actual_size*/, | |
476 embedder::PlatformHandleVector* /*platform_handles*/) { | |
477 DCHECK(HasOneRef()); // Only one ref => no need to take the lock. | |
478 DCHECK(is_closed_); | |
479 // By default, serializing isn't supported, so just close. | |
480 CloseImplNoLock(); | |
481 return false; | |
482 } | |
483 | |
484 bool Dispatcher::IsBusyNoLock() const { | |
485 mutex_.AssertHeld(); | |
486 DCHECK(!is_closed_); | |
487 // Most dispatchers support only "atomic" operations, so they are never busy | |
488 // (in this sense). | |
489 return false; | |
490 } | |
491 | |
492 void Dispatcher::CloseNoLock() { | |
493 mutex_.AssertHeld(); | |
494 DCHECK(!is_closed_); | |
495 | |
496 is_closed_ = true; | |
497 CancelAllAwakablesNoLock(); | |
498 CloseImplNoLock(); | |
499 } | |
500 | |
501 scoped_refptr<Dispatcher> | |
502 Dispatcher::CreateEquivalentDispatcherAndCloseNoLock() { | |
503 mutex_.AssertHeld(); | |
504 DCHECK(!is_closed_); | |
505 | |
506 is_closed_ = true; | |
507 CancelAllAwakablesNoLock(); | |
508 return CreateEquivalentDispatcherAndCloseImplNoLock(); | |
509 } | |
510 | |
511 void Dispatcher::StartSerialize(Channel* channel, | |
512 size_t* max_size, | |
513 size_t* max_platform_handles) { | |
514 DCHECK(channel); | |
515 DCHECK(max_size); | |
516 DCHECK(max_platform_handles); | |
517 DCHECK(HasOneRef()); // Only one ref => no need to take the lock. | |
518 DCHECK(!is_closed_); | |
519 StartSerializeImplNoLock(channel, max_size, max_platform_handles); | |
520 } | |
521 | |
522 bool Dispatcher::EndSerializeAndClose( | |
523 Channel* channel, | |
524 void* destination, | |
525 size_t* actual_size, | |
526 embedder::PlatformHandleVector* platform_handles) { | |
527 DCHECK(channel); | |
528 DCHECK(actual_size); | |
529 DCHECK(HasOneRef()); // Only one ref => no need to take the lock. | |
530 DCHECK(!is_closed_); | |
531 | |
532 // Like other |...Close()| methods, we mark ourselves as closed before calling | |
533 // the impl. But there's no need to cancel waiters: we shouldn't have any (and | |
534 // shouldn't be in |Core|'s handle table. | |
535 is_closed_ = true; | |
536 | |
537 #if !defined(NDEBUG) | |
538 // See the comment above |EndSerializeAndCloseImplNoLock()|. In brief: Locking | |
539 // isn't actually needed, but we need to satisfy assertions (which we don't | |
540 // want to remove or weaken). | |
541 MutexLocker locker(&mutex_); | |
542 #endif | |
543 | |
544 return EndSerializeAndCloseImplNoLock(channel, destination, actual_size, | |
545 platform_handles); | |
546 } | |
547 | |
548 // DispatcherTransport --------------------------------------------------------- | |
549 | |
550 void DispatcherTransport::End() { | |
551 DCHECK(dispatcher_); | |
552 dispatcher_->mutex_.Unlock(); | |
553 dispatcher_ = nullptr; | |
554 } | |
555 | |
556 } // namespace system | |
557 } // namespace mojo | |
OLD | NEW |