Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(199)

Side by Side Diff: mojo/public/cpp/system/wait.cc

Issue 2744943002: Mojo: Move waiting APIs to public library (Closed)
Patch Set: . Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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/system/wait.h"
6
7 #include <memory>
8 #include <vector>
9
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "mojo/public/c/system/watcher.h"
14 #include "mojo/public/cpp/system/watcher.h"
15
16 namespace mojo {
17 namespace {
18
19 class WatchContext : public base::RefCountedThreadSafe<WatchContext> {
20 public:
21 WatchContext()
22 : event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
23 base::WaitableEvent::InitialState::NOT_SIGNALED) {}
24
25 base::WaitableEvent& event() { return event_; }
26 MojoResult wait_result() const { return wait_result_; }
27 MojoHandleSignalsState wait_state() const { return wait_state_; }
28 uintptr_t context_value() const { return reinterpret_cast<uintptr_t>(this); }
29
30 static void OnNotification(uintptr_t context_value,
31 MojoResult result,
32 MojoHandleSignalsState state,
33 MojoWatcherNotificationFlags flags) {
34 auto* context = reinterpret_cast<WatchContext*>(context_value);
35 context->Notify(result, state);
36 if (result == MOJO_RESULT_CANCELLED) {
37 // Balanced in Wait() or WaitMany().
38 context->Release();
39 }
40 }
41
42 private:
43 friend class base::RefCountedThreadSafe<WatchContext>;
44
45 ~WatchContext() {}
46
47 void Notify(MojoResult result, MojoHandleSignalsState state) {
48 if (wait_result_ == MOJO_RESULT_UNKNOWN) {
49 wait_result_ = result;
50 wait_state_ = state;
51 }
52 event_.Signal();
53 }
54
55 base::WaitableEvent event_;
56
57 // NOTE: Although these are modified in Notify() which may be called from any
58 // thread, Notify() is guaranteed to never run concurrently with itself.
59 // Furthermore, they are only modified once, before |event_| signals; so there
60 // is no need for a WatchContext user to synchronize access to these fields
61 // apart from waiting on |event()|.
62 MojoResult wait_result_ = MOJO_RESULT_UNKNOWN;
63 MojoHandleSignalsState wait_state_ = {0, 0};
64
65 DISALLOW_COPY_AND_ASSIGN(WatchContext);
66 };
67
68 } // namespace
69
70 MojoResult Wait(Handle handle,
71 MojoHandleSignals signals,
72 MojoHandleSignalsState* signals_state) {
73 ScopedWatcherHandle watcher;
74 MojoResult rv = CreateWatcher(&WatchContext::OnNotification, &watcher);
75 DCHECK_EQ(MOJO_RESULT_OK, rv);
76
77 scoped_refptr<WatchContext> context = new WatchContext;
78
79 // Balanced in WatchContext::OnNotification if MojoWatch() is successful.
80 // Otherwise balanced immediately below.
81 context->AddRef();
82
83 rv = MojoWatch(watcher.get().value(), handle.value(), signals,
84 context->context_value());
85 if (rv == MOJO_RESULT_INVALID_ARGUMENT) {
86 // Balanced above.
87 context->Release();
88 return rv;
89 }
90 DCHECK_EQ(MOJO_RESULT_OK, rv);
91
92 uint32_t num_ready_contexts = 1;
93 uintptr_t ready_context;
94 MojoResult ready_result;
95 MojoHandleSignalsState ready_state;
96 rv = MojoArmWatcher(watcher.get().value(), &num_ready_contexts,
97 &ready_context, &ready_result, &ready_state);
98 if (rv == MOJO_RESULT_FAILED_PRECONDITION) {
99 DCHECK_EQ(1u, num_ready_contexts);
100 if (signals_state)
101 *signals_state = ready_state;
102 return ready_result;
103 }
104
105 // Wait for the first notification only.
106 context->event().Wait();
107
108 ready_result = context->wait_result();
109 DCHECK_NE(MOJO_RESULT_UNKNOWN, ready_result);
110
111 if (signals_state)
112 *signals_state = context->wait_state();
113
114 return ready_result;
115 }
116
117 MojoResult WaitMany(const Handle* handles,
118 const MojoHandleSignals* signals,
119 size_t num_handles,
120 size_t* result_index,
121 MojoHandleSignalsState* signals_states) {
122 if (!handles || !signals)
123 return MOJO_RESULT_INVALID_ARGUMENT;
124
125 ScopedWatcherHandle watcher;
126 MojoResult rv = CreateWatcher(&WatchContext::OnNotification, &watcher);
127 DCHECK_EQ(MOJO_RESULT_OK, rv);
128
129 std::vector<scoped_refptr<WatchContext>> contexts(num_handles);
130 std::vector<base::WaitableEvent*> events(num_handles);
131 for (size_t i = 0; i < num_handles; ++i) {
132 contexts[i] = new WatchContext();
133
134 // Balanced in WatchContext::OnNotification if MojoWatch() is successful.
135 // Otherwise balanced immediately below.
136 contexts[i]->AddRef();
137
138 MojoResult rv = MojoWatch(watcher.get().value(), handles[i].value(),
139 signals[i], contexts[i]->context_value());
140 if (rv == MOJO_RESULT_INVALID_ARGUMENT) {
141 if (result_index)
142 *result_index = i;
143
144 // Balanced above.
145 contexts[i]->Release();
146
147 return MOJO_RESULT_INVALID_ARGUMENT;
148 }
149
150 events[i] = &contexts[i]->event();
151 }
152
153 uint32_t num_ready_contexts = 1;
154 uintptr_t ready_context = 0;
155 MojoResult ready_result = MOJO_RESULT_UNKNOWN;
156 MojoHandleSignalsState ready_state{0, 0};
157 rv = MojoArmWatcher(watcher.get().value(), &num_ready_contexts,
158 &ready_context, &ready_result, &ready_state);
159
160 size_t index = num_handles;
161 if (rv == MOJO_RESULT_FAILED_PRECONDITION) {
162 DCHECK_EQ(1u, num_ready_contexts);
163
164 // Most commonly we only watch a small number of handles. Just scan for
165 // the right index.
166 for (size_t i = 0; i < num_handles; ++i) {
167 if (contexts[i]->context_value() == ready_context) {
168 index = i;
169 break;
170 }
171 }
172 } else {
173 DCHECK_EQ(MOJO_RESULT_OK, rv);
174
175 // Wait for one of the contexts to signal. First one wins.
176 index = base::WaitableEvent::WaitMany(events.data(), events.size());
177 ready_result = contexts[index]->wait_result();
178 ready_state = contexts[index]->wait_state();
179 }
180
181 DCHECK_NE(MOJO_RESULT_UNKNOWN, ready_result);
182 DCHECK_LT(index, num_handles);
183
184 if (result_index)
185 *result_index = index;
186
187 if (signals_states) {
188 for (size_t i = 0; i < num_handles; ++i) {
189 if (i == index) {
190 signals_states[i] = ready_state;
191 } else {
192 signals_states[i] = handles[i].QuerySignalsState();
193 }
194 }
195 }
196
197 return ready_result;
198 }
199
200 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698