OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 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/public/cpp/bindings/lib/sync_handle_watcher.h" | 5 #include "mojo/public/cpp/bindings/lib/sync_handle_watcher.h" |
6 | 6 |
7 #include "base/lazy_instance.h" | |
8 #include "base/logging.h" | 7 #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 | 8 |
13 namespace mojo { | 9 namespace mojo { |
14 namespace internal { | 10 namespace internal { |
15 namespace { | |
16 | 11 |
17 base::LazyInstance<base::ThreadLocalPointer<SyncHandleWatcher>> | 12 SyncHandleWatcher::SyncHandleWatcher( |
18 g_current_sync_handle_watcher = LAZY_INSTANCE_INITIALIZER; | 13 const Handle& handle, |
14 MojoHandleSignals handle_signals, | |
15 const SyncHandleRegistry::HandleCallback& callback) | |
16 : handle_(handle), | |
17 handle_signals_(handle_signals), | |
18 callback_(callback), | |
19 registered_(false), | |
20 register_request_count_(0), | |
21 destroyed_(new base::RefCountedData<bool>(false)) {} | |
19 | 22 |
20 } // namespace | 23 SyncHandleWatcher::~SyncHandleWatcher() { |
24 DCHECK(thread_checker_.CalledOnValidThread()); | |
25 if (registered_) | |
26 SyncHandleRegistry::current()->UnregisterHandle(handle_); | |
21 | 27 |
22 // static | 28 destroyed_->data = true; |
23 SyncHandleWatcher* SyncHandleWatcher::current() { | 29 } |
24 SyncHandleWatcher* result = g_current_sync_handle_watcher.Pointer()->Get(); | 30 |
25 if (!result) { | 31 void SyncHandleWatcher::AllowWokenUpBySyncWatchOnSameThread() { |
26 // This object will be destroyed when the current message loop goes away. | 32 DCHECK(thread_checker_.CalledOnValidThread()); |
27 result = new SyncHandleWatcher(); | 33 IncrementRegisterCount(); |
28 DCHECK_EQ(result, g_current_sync_handle_watcher.Pointer()->Get()); | 34 } |
35 | |
36 bool SyncHandleWatcher::SyncWatch(const bool* should_stop) { | |
37 DCHECK(thread_checker_.CalledOnValidThread()); | |
38 IncrementRegisterCount(); | |
39 if (!registered_) { | |
40 DecrementRegisterCount(); | |
41 return false; | |
29 } | 42 } |
43 | |
44 // This object may be destroyed during the WatchAllHandles() call. So we have | |
45 // to preserve the boolean that WatchAllHandles uses. | |
46 auto destroyed = destroyed_; | |
47 const bool* should_stop_array[] = {should_stop, &destroyed->data}; | |
48 bool result = | |
49 SyncHandleRegistry::current()->WatchAllHandles(should_stop_array, 2); | |
50 | |
51 // This object has been destroyed. | |
52 if (destroyed->data) | |
53 return false; | |
54 | |
55 DecrementRegisterCount(); | |
30 return result; | 56 return result; |
31 } | 57 } |
32 | 58 |
33 bool SyncHandleWatcher::RegisterHandle(const Handle& handle, | 59 void SyncHandleWatcher::IncrementRegisterCount() { |
34 MojoHandleSignals handle_signals, | 60 register_request_count_++; |
35 const HandleCallback& callback) { | 61 if (!registered_ && handle_.is_valid()) { |
Ken Rockot(use gerrit already)
2016/03/26 03:09:26
Is it OK to simply DCHECK that handle_.is_valid()
yzshen1
2016/03/26 06:33:17
I did it this way because I was thinking that it m
| |
36 DCHECK(thread_checker_.CalledOnValidThread()); | 62 registered_ = SyncHandleRegistry::current()->RegisterHandle( |
37 | 63 handle_, handle_signals_, callback_); |
38 if (ContainsKey(handles_, handle)) | 64 } |
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 } | 65 } |
49 | 66 |
50 void SyncHandleWatcher::UnregisterHandle(const Handle& handle) { | 67 void SyncHandleWatcher::DecrementRegisterCount() { |
51 DCHECK(thread_checker_.CalledOnValidThread()); | 68 DCHECK_GT(register_request_count_, 0u); |
52 DCHECK(ContainsKey(handles_, handle)); | |
53 | 69 |
54 MojoResult result = | 70 register_request_count_--; |
55 MojoRemoveHandle(wait_set_handle_.get().value(), handle.value()); | 71 if (register_request_count_ == 0 && registered_) { |
56 DCHECK_EQ(MOJO_RESULT_OK, result); | 72 SyncHandleRegistry::current()->UnregisterHandle(handle_); |
57 | 73 registered_ = false; |
58 handles_.erase(handle); | 74 } |
59 } | |
60 | |
61 bool SyncHandleWatcher::WatchAllHandles(const bool* should_stop[], | |
62 size_t count) { | |
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 (true) { | |
71 for (size_t i = 0; i < count; ++i) | |
72 if (*should_stop[i]) | |
73 return true; | |
74 do { | |
75 result = Wait(wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, | |
76 MOJO_DEADLINE_INDEFINITE, nullptr); | |
77 if (result != MOJO_RESULT_OK) | |
78 return false; | |
79 | |
80 // TODO(yzshen): Theoretically it can reduce sync call re-entrancy if we | |
81 // give priority to the handle that is waiting for sync response. | |
82 num_ready_handles = 1; | |
83 result = MojoGetReadyHandles(wait_set_handle_.get().value(), | |
84 &num_ready_handles, &ready_handle, | |
85 &ready_handle_result, nullptr); | |
86 if (result != MOJO_RESULT_OK && result != MOJO_RESULT_SHOULD_WAIT) | |
87 return false; | |
88 } while (result == MOJO_RESULT_SHOULD_WAIT); | |
89 | |
90 const auto iter = handles_.find(Handle(ready_handle)); | |
91 iter->second.Run(ready_handle_result); | |
92 }; | |
93 | |
94 return true; | |
95 } | |
96 | |
97 SyncHandleWatcher::SyncHandleWatcher() { | |
98 MojoHandle handle; | |
99 MojoResult result = MojoCreateWaitSet(&handle); | |
100 CHECK_EQ(MOJO_RESULT_OK, result); | |
101 wait_set_handle_.reset(Handle(handle)); | |
102 CHECK(wait_set_handle_.is_valid()); | |
103 | |
104 DCHECK(!g_current_sync_handle_watcher.Pointer()->Get()); | |
105 g_current_sync_handle_watcher.Pointer()->Set(this); | |
106 | |
107 base::MessageLoop::current()->AddDestructionObserver(this); | |
108 } | |
109 | |
110 SyncHandleWatcher::~SyncHandleWatcher() { | |
111 DCHECK(thread_checker_.CalledOnValidThread()); | |
112 DCHECK(handles_.empty()); | |
113 g_current_sync_handle_watcher.Pointer()->Set(nullptr); | |
114 } | |
115 | |
116 void SyncHandleWatcher::WillDestroyCurrentMessageLoop() { | |
117 DCHECK(thread_checker_.CalledOnValidThread()); | |
118 DCHECK_EQ(this, g_current_sync_handle_watcher.Pointer()->Get()); | |
119 | |
120 base::MessageLoop::current()->RemoveDestructionObserver(this); | |
121 delete this; | |
122 } | 75 } |
123 | 76 |
124 } // namespace internal | 77 } // namespace internal |
125 } // namespace mojo | 78 } // namespace mojo |
OLD | NEW |