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 "mojo/system/core_impl.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/logging.h" | |
10 #include "mojo/system/dispatcher.h" | |
11 #include "mojo/system/limits.h" | |
12 #include "mojo/system/memory.h" | |
13 #include "mojo/system/message_pipe.h" | |
14 #include "mojo/system/message_pipe_dispatcher.h" | |
15 #include "mojo/system/waiter.h" | |
16 | |
17 namespace mojo { | |
18 namespace system { | |
19 | |
20 // Implementation notes | |
21 // | |
22 // Mojo primitives are implemented by the singleton |CoreImpl| object. Most | |
23 // calls are for a "primary" handle (the first argument). | |
24 // |CoreImpl::GetDispatcher()| is used to look up a |Dispatcher| object for a | |
25 // given handle. That object implements most primitives for that object. The | |
26 // wait primitives are not attached to objects and are implemented by |CoreImpl| | |
27 // itself. | |
28 // | |
29 // Some objects have multiple handles associated to them, e.g., message pipes | |
30 // (which have two). In such a case, there is still a |Dispatcher| (e.g., | |
31 // |MessagePipeDispatcher|) for each handle, with each handle having a strong | |
32 // reference to the common "secondary" object (e.g., |MessagePipe|). This | |
33 // secondary object does NOT have any references to the |Dispatcher|s (even if | |
34 // it did, it wouldn't be able to do anything with them due to lock order | |
35 // requirements -- see below). | |
36 // | |
37 // Waiting is implemented by having the thread that wants to wait call the | |
38 // |Dispatcher|s for the handles that it wants to wait on with a |Waiter| | |
39 // object; this |Waiter| object may be created on the stack of that thread or be | |
40 // kept in thread local storage for that thread (TODO(vtl): future improvement). | |
41 // The |Dispatcher| then adds the |Waiter| to a |WaiterList| that's either owned | |
42 // by that |Dispatcher| (see |SimpleDispatcher|) or by a secondary object (e.g., | |
43 // |MessagePipe|). To signal/wake a |Waiter|, the object in question -- either a | |
44 // |SimpleDispatcher| or a secondary object -- talks to its |WaiterList|. | |
45 | |
46 // Thread-safety notes | |
47 // | |
48 // Mojo primitives calls are thread-safe. We achieve this with relatively | |
49 // fine-grained locking. There is a global handle table lock. This lock should | |
50 // be held as briefly as possible (TODO(vtl): a future improvement would be to | |
51 // switch it to a reader-writer lock). Each |Dispatcher| object then has a lock | |
52 // (which subclasses can use to protect their data). | |
53 // | |
54 // The lock ordering is as follows: | |
55 // 1. global handle table lock | |
56 // 2. |Dispatcher| locks | |
57 // 3. secondary object locks | |
58 // ... | |
59 // INF. |Waiter| locks | |
60 // | |
61 // Notes: | |
62 // - While holding a |Dispatcher| lock, you may not unconditionally attempt | |
63 // to take another |Dispatcher| lock. (This has consequences on the | |
64 // concurrency semantics of |MojoWriteMessage()| when passing handles.) | |
65 // Doing so would lead to deadlock. | |
66 // - Locks at the "INF" level may not have any locks taken while they are | |
67 // held. | |
68 | |
69 // static | |
70 CoreImpl* CoreImpl::mojo_system_singleton_ = NULL; | |
71 | |
72 // static | |
73 void CoreImpl::Init() { | |
74 CHECK(!mojo_system_singleton_); | |
75 mojo_system_singleton_ = new CoreImpl(); | |
76 } | |
77 | |
78 MojoResult CoreImpl::Close(MojoHandle handle) { | |
79 if (handle == MOJO_HANDLE_INVALID) | |
80 return MOJO_RESULT_INVALID_ARGUMENT; | |
darin (slow to review)
2013/09/25 06:06:07
nit: consider a more specific error code of MOJO_R
| |
81 | |
82 scoped_refptr<Dispatcher> dispatcher; | |
83 { | |
84 base::AutoLock locker(handle_table_lock_); | |
85 HandleTableMap::iterator it = handle_table_.find(handle); | |
86 if (it == handle_table_.end()) | |
87 return MOJO_RESULT_INVALID_ARGUMENT; | |
88 dispatcher = it->second; | |
89 handle_table_.erase(it); | |
90 } | |
91 | |
92 // The dispatcher doesn't have a say in being closed, but gets notified of it. | |
93 // Note: This is done outside of |handle_table_lock_|. As a result, there's a | |
94 // race condition that the dispatcher must handle; see the comment in | |
95 // |Dispatcher| in dispatcher.h. | |
96 return dispatcher->Close(); | |
97 } | |
98 | |
99 MojoResult CoreImpl::Wait(MojoHandle handle, | |
100 MojoWaitFlags flags, | |
101 MojoDeadline deadline) { | |
102 return WaitManyInternal(&handle, &flags, 1, deadline); | |
103 } | |
104 | |
105 MojoResult CoreImpl::WaitMany(const MojoHandle* handles, | |
106 const MojoWaitFlags* flags, | |
107 uint32_t num_handles, | |
108 MojoDeadline deadline) { | |
109 if (!VerifyUserPointer(handles, num_handles, sizeof(handles[0]))) | |
110 return MOJO_RESULT_INVALID_ARGUMENT; | |
111 if (!VerifyUserPointer(flags, num_handles, sizeof(flags[0]))) | |
112 return MOJO_RESULT_INVALID_ARGUMENT; | |
113 if (num_handles < 1) | |
114 return MOJO_RESULT_INVALID_ARGUMENT; | |
115 if (num_handles > kMaxWaitManyNumHandles) | |
116 return MOJO_RESULT_OUT_OF_RANGE; | |
117 return WaitManyInternal(handles, flags, num_handles, deadline); | |
118 } | |
119 | |
120 MojoResult CoreImpl::CreateMessagePipe(MojoHandle* handle_0, | |
121 MojoHandle* handle_1) { | |
122 scoped_refptr<MessagePipeDispatcher> dispatcher_0( | |
123 new MessagePipeDispatcher()); | |
124 scoped_refptr<MessagePipeDispatcher> dispatcher_1( | |
125 new MessagePipeDispatcher()); | |
126 | |
127 MojoHandle h0, h1; | |
128 { | |
129 base::AutoLock locker(handle_table_lock_); | |
130 | |
131 h0 = AddDispatcherNoLock(dispatcher_0); | |
132 if (h0 == MOJO_HANDLE_INVALID) | |
133 return MOJO_RESULT_RESOURCE_EXHAUSTED; | |
134 | |
135 h1 = AddDispatcherNoLock(dispatcher_1); | |
136 if (h1 == MOJO_HANDLE_INVALID) { | |
137 handle_table_.erase(h0); | |
138 return MOJO_RESULT_RESOURCE_EXHAUSTED; | |
139 } | |
140 } | |
141 | |
142 scoped_refptr<MessagePipe> message_pipe(new MessagePipe()); | |
143 dispatcher_0->Init(message_pipe, 0); | |
144 dispatcher_1->Init(message_pipe, 1); | |
145 | |
146 *handle_0 = h0; | |
147 *handle_1 = h1; | |
148 return MOJO_RESULT_OK; | |
149 } | |
150 | |
151 MojoResult CoreImpl::WriteMessage( | |
152 MojoHandle handle, | |
153 const void* bytes, uint32_t num_bytes, | |
154 const MojoHandle* handles, uint32_t num_handles, | |
155 MojoWriteMessageFlags flags) { | |
156 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(handle)); | |
157 if (!dispatcher.get()) | |
158 return MOJO_RESULT_INVALID_ARGUMENT; | |
159 | |
160 return dispatcher->WriteMessage(bytes, num_bytes, | |
161 handles, num_handles, | |
162 flags); | |
163 } | |
164 | |
165 MojoResult CoreImpl::ReadMessage( | |
166 MojoHandle handle, | |
167 void* bytes, uint32_t* num_bytes, | |
168 MojoHandle* handles, uint32_t* num_handles, | |
169 MojoReadMessageFlags flags) { | |
170 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(handle)); | |
171 if (!dispatcher.get()) | |
172 return MOJO_RESULT_INVALID_ARGUMENT; | |
173 | |
174 return dispatcher->ReadMessage(bytes, num_bytes, | |
175 handles, num_handles, | |
176 flags); | |
177 } | |
178 | |
179 CoreImpl::CoreImpl() | |
180 : next_handle_(MOJO_HANDLE_INVALID + 1) { | |
181 } | |
182 | |
183 CoreImpl::~CoreImpl() { | |
184 // This should usually not be reached (the singleton lives forever), except | |
185 // in tests. | |
186 } | |
187 | |
188 scoped_refptr<Dispatcher> CoreImpl::GetDispatcher(MojoHandle handle) { | |
189 if (handle == MOJO_HANDLE_INVALID) | |
190 return NULL; | |
191 | |
192 base::AutoLock locker(handle_table_lock_); | |
193 HandleTableMap::iterator it = handle_table_.find(handle); | |
194 if (it == handle_table_.end()) | |
195 return NULL; | |
196 | |
197 return it->second; | |
198 } | |
199 | |
200 MojoHandle CoreImpl::AddDispatcherNoLock(scoped_refptr<Dispatcher> dispatcher) { | |
201 DCHECK(dispatcher.get()); | |
202 handle_table_lock_.AssertAcquired(); | |
203 DCHECK_NE(next_handle_, MOJO_HANDLE_INVALID); | |
204 | |
205 if (handle_table_.size() >= kMaxHandleTableSize) | |
206 return MOJO_HANDLE_INVALID; | |
207 | |
208 // TODO(vtl): Maybe we want to do something different/smarter. (Or maybe try | |
209 // assigning randomly?) | |
210 while (handle_table_.find(next_handle_) != handle_table_.end()) { | |
211 next_handle_++; | |
212 if (next_handle_ == MOJO_HANDLE_INVALID) | |
darin (slow to review)
2013/09/25 06:06:07
it seems like there are some good test cases to wr
| |
213 next_handle_++; | |
214 } | |
215 | |
216 MojoHandle new_handle = next_handle_; | |
217 handle_table_[new_handle] = dispatcher; | |
218 | |
219 next_handle_++; | |
220 if (next_handle_ == MOJO_HANDLE_INVALID) | |
221 next_handle_++; | |
222 | |
223 return new_handle; | |
224 } | |
225 | |
226 MojoResult CoreImpl::WaitManyInternal(const MojoHandle* handles, | |
227 const MojoWaitFlags* flags, | |
228 uint32_t num_handles, | |
229 MojoDeadline deadline) { | |
230 DCHECK_GT(num_handles, 0u); | |
231 | |
232 std::vector<scoped_refptr<Dispatcher> > dispatchers; | |
233 dispatchers.reserve(num_handles); | |
234 for (uint32_t i = 0; i < num_handles; i++) { | |
235 scoped_refptr<Dispatcher> d = GetDispatcher(handles[i]); | |
236 if (!d.get()) | |
237 return MOJO_RESULT_INVALID_ARGUMENT; | |
238 dispatchers.push_back(d); | |
239 } | |
240 | |
241 // TODO(vtl): Should make the waiter live (permanently) in TLS. | |
242 Waiter waiter; | |
243 waiter.Init(); | |
244 | |
245 uint32_t i; | |
246 MojoResult rv = MOJO_RESULT_OK; | |
247 for (i = 0; i < num_handles; i++) { | |
248 rv = dispatchers[i]->AddWaiter(&waiter, | |
249 flags[i], | |
250 static_cast<MojoResult>(i)); | |
251 if (rv != MOJO_RESULT_OK) | |
252 break; | |
253 } | |
254 uint32_t num_added = i; | |
255 | |
256 if (rv == 1) | |
257 rv = static_cast<MojoResult>(i); | |
258 else if (rv == MOJO_RESULT_OK) | |
259 rv = waiter.Wait(deadline); | |
260 | |
261 for (i = 0; i < num_added; i++) | |
262 dispatchers[i]->RemoveWaiter(&waiter); | |
263 | |
264 return rv; | |
265 } | |
266 | |
267 } // namespace system | |
268 } // namespace mojo | |
OLD | NEW |