OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "mojo/public/cpp/bindings/lib/sync_handle_watcher.h" | |
6 | |
7 #include "base/lazy_instance.h" | |
8 #include "base/logging.h" | |
9 #include "base/stl_util.h" | |
10 #include "base/threading/thread_local.h" | |
11 #include "mojo/public/c/system/core.h" | |
12 | |
13 namespace mojo { | |
14 namespace internal { | |
15 namespace { | |
16 | |
17 base::LazyInstance<base::ThreadLocalPointer<SyncHandleWatcher>> | |
18 g_current_sync_handle_watcher = LAZY_INSTANCE_INITIALIZER; | |
19 | |
20 } // namespace | |
21 | |
22 // static | |
23 SyncHandleWatcher* SyncHandleWatcher::current() { | |
24 SyncHandleWatcher* result = g_current_sync_handle_watcher.Pointer()->Get(); | |
25 if (!result) { | |
26 // This object will be destroyed when the current message loop goes away. | |
27 result = new SyncHandleWatcher(); | |
28 DCHECK_EQ(result, g_current_sync_handle_watcher.Pointer()->Get()); | |
29 } | |
30 return result; | |
31 } | |
32 | |
33 bool SyncHandleWatcher::RegisterHandle(const Handle& handle, | |
34 MojoHandleSignals handle_signals, | |
35 const HandleCallback& callback) { | |
36 DCHECK(thread_checker_.CalledOnValidThread()); | |
37 | |
38 if (ContainsKey(handles_, handle)) | |
39 return false; | |
40 | |
41 MojoResult result = MojoAddHandle(wait_set_handle_.get().value(), | |
42 handle.value(), handle_signals); | |
43 if (result != MOJO_RESULT_OK) | |
44 return false; | |
45 | |
46 handles_[handle] = callback; | |
47 return true; | |
48 } | |
49 | |
50 void SyncHandleWatcher::UnregisterHandle(const Handle& handle) { | |
51 DCHECK(thread_checker_.CalledOnValidThread()); | |
52 DCHECK(ContainsKey(handles_, handle)); | |
53 | |
54 MojoResult result = | |
55 MojoRemoveHandle(wait_set_handle_.get().value(), handle.value()); | |
56 DCHECK_EQ(MOJO_RESULT_OK, result); | |
57 | |
58 handles_.erase(handle); | |
59 } | |
60 | |
61 bool SyncHandleWatcher::WatchAllHandles(const Handle& caller_handle, | |
62 const bool* should_stop) { | |
63 DCHECK(thread_checker_.CalledOnValidThread()); | |
64 | |
65 MojoResult result; | |
66 uint32_t num_ready_handles; | |
67 MojoHandle ready_handle; | |
68 MojoResult ready_handle_result; | |
69 | |
70 while (!*should_stop) { | |
71 if (!ContainsKey(handles_, caller_handle)) | |
72 return false; | |
73 do { | |
74 result = Wait(wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, | |
75 MOJO_DEADLINE_INDEFINITE, nullptr); | |
76 if (result != MOJO_RESULT_OK) | |
77 return false; | |
78 | |
79 // TODO(yzshen): Theoretically it can reduce sync call re-entrancy if we | |
80 // give priority to the handle that is waiting for sync response. | |
81 num_ready_handles = 1; | |
82 result = MojoGetReadyHandles(wait_set_handle_.get().value(), | |
83 &num_ready_handles, &ready_handle, | |
84 &ready_handle_result, nullptr); | |
85 if (result != MOJO_RESULT_OK && result != MOJO_RESULT_SHOULD_WAIT) | |
86 return false; | |
87 } while (result == MOJO_RESULT_SHOULD_WAIT); | |
88 | |
89 const auto iter = handles_.find(Handle(ready_handle)); | |
90 iter->second.Run(ready_handle_result); | |
91 }; | |
92 | |
93 return true; | |
94 } | |
95 | |
96 SyncHandleWatcher::SyncHandleWatcher() { | |
97 MojoHandle handle; | |
98 MojoResult result = MojoCreateWaitSet(&handle); | |
99 CHECK_EQ(MOJO_RESULT_OK, result); | |
100 wait_set_handle_.reset(Handle(handle)); | |
101 CHECK(wait_set_handle_.is_valid()); | |
102 | |
103 DCHECK(!g_current_sync_handle_watcher.Pointer()->Get()); | |
104 g_current_sync_handle_watcher.Pointer()->Set(this); | |
105 | |
106 base::MessageLoop::current()->AddDestructionObserver(this); | |
107 } | |
108 | |
109 SyncHandleWatcher::~SyncHandleWatcher() { | |
110 DCHECK(thread_checker_.CalledOnValidThread()); | |
111 DCHECK(handles_.empty()); | |
112 g_current_sync_handle_watcher.Pointer()->Set(nullptr); | |
113 } | |
114 | |
115 void SyncHandleWatcher::WillDestroyCurrentMessageLoop() { | |
116 DCHECK(thread_checker_.CalledOnValidThread()); | |
117 DCHECK_EQ(this, g_current_sync_handle_watcher.Pointer()->Get()); | |
118 | |
119 base::MessageLoop::current()->RemoveDestructionObserver(this); | |
120 delete this; | |
121 } | |
122 | |
123 } // namespace internal | |
124 } // namespace mojo | |
OLD | NEW |