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

Side by Side Diff: ppapi/proxy/udp_socket_resource_base.cc

Issue 869883003: Never lock the Pepper proxy lock on the IO thread (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: oops, version without the TrackedCallback changes. Created 5 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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 "ppapi/proxy/udp_socket_resource_base.h" 5 #include "ppapi/proxy/udp_socket_resource_base.h"
6 6
7 #include <algorithm>
8 #include <cstring> 7 #include <cstring>
9 8
10 #include "base/logging.h" 9 #include "base/logging.h"
11 #include "ppapi/c/pp_bool.h" 10 #include "ppapi/c/pp_bool.h"
12 #include "ppapi/c/pp_completion_callback.h"
13 #include "ppapi/c/pp_errors.h" 11 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/proxy/error_conversion.h" 12 #include "ppapi/proxy/error_conversion.h"
15 #include "ppapi/proxy/plugin_globals.h" 13 #include "ppapi/proxy/plugin_globals.h"
16 #include "ppapi/proxy/ppapi_messages.h" 14 #include "ppapi/proxy/ppapi_messages.h"
17 #include "ppapi/shared_impl/socket_option_data.h" 15 #include "ppapi/shared_impl/socket_option_data.h"
18 #include "ppapi/thunk/enter.h" 16 #include "ppapi/thunk/enter.h"
19 #include "ppapi/thunk/resource_creation_api.h"
20 17
21 namespace ppapi { 18 namespace ppapi {
22 namespace proxy { 19 namespace proxy {
23 20
24 const int32_t UDPSocketResourceBase::kMaxReadSize = 128 * 1024;
25 const int32_t UDPSocketResourceBase::kMaxWriteSize = 128 * 1024; 21 const int32_t UDPSocketResourceBase::kMaxWriteSize = 128 * 1024;
26 const int32_t UDPSocketResourceBase::kMaxSendBufferSize = 22 const int32_t UDPSocketResourceBase::kMaxSendBufferSize =
27 1024 * UDPSocketResourceBase::kMaxWriteSize; 23 1024 * UDPSocketResourceBase::kMaxWriteSize;
28 const int32_t UDPSocketResourceBase::kMaxReceiveBufferSize =
29 1024 * UDPSocketResourceBase::kMaxReadSize;
30 const size_t UDPSocketResourceBase::kPluginReceiveBufferSlots = 32u;
31 const size_t UDPSocketResourceBase::kPluginSendBufferSlots = 8u; 24 const size_t UDPSocketResourceBase::kPluginSendBufferSlots = 8u;
32 25
26 namespace {
27
28 void RunCallback(scoped_refptr<TrackedCallback> callback,
29 int32_t pp_result,
30 bool private_api) {
31 callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result, private_api));
32 }
33
34 void PostAbortIfNecessary(const scoped_refptr<TrackedCallback>& callback) {
35 if (TrackedCallback::IsPending(callback))
36 callback->PostAbort();
37 }
38
39 } // namespace
40
33 UDPSocketResourceBase::UDPSocketResourceBase(Connection connection, 41 UDPSocketResourceBase::UDPSocketResourceBase(Connection connection,
34 PP_Instance instance, 42 PP_Instance instance,
35 bool private_api) 43 bool private_api)
36 : PluginResource(connection, instance), 44 : PluginResource(connection, instance),
37 private_api_(private_api), 45 private_api_(private_api),
38 bind_called_(false), 46 bind_called_(false),
39 bound_(false), 47 bound_(false),
40 closed_(false), 48 closed_(false),
41 read_buffer_(NULL), 49 recv_filter_(PluginGlobals::Get()->udp_socket_filter()),
42 bytes_to_read_(-1), 50 bound_addr_() {
43 recvfrom_addr_resource_(NULL) { 51 recv_filter_->AddUDPResource(
44 recvfrom_addr_.size = 0; 52 pp_instance(), pp_resource(), private_api,
45 memset(recvfrom_addr_.data, 0, 53 base::Bind(&UDPSocketResourceBase::SlotBecameAvailable, pp_resource()));
46 arraysize(recvfrom_addr_.data) * sizeof(*recvfrom_addr_.data));
47 bound_addr_.size = 0;
48 memset(bound_addr_.data, 0,
49 arraysize(bound_addr_.data) * sizeof(*bound_addr_.data));
50
51 if (private_api) 54 if (private_api)
52 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_CreatePrivate()); 55 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_CreatePrivate());
53 else 56 else
54 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_Create()); 57 SendCreate(BROWSER, PpapiHostMsg_UDPSocket_Create());
55
56 PluginGlobals::Get()->resource_reply_thread_registrar()->HandleOnIOThread(
57 PpapiPluginMsg_UDPSocket_PushRecvResult::ID);
58 } 58 }
59 59
60 UDPSocketResourceBase::~UDPSocketResourceBase() { 60 UDPSocketResourceBase::~UDPSocketResourceBase() {
61 CloseImpl();
61 } 62 }
62 63
63 int32_t UDPSocketResourceBase::SetOptionImpl( 64 int32_t UDPSocketResourceBase::SetOptionImpl(
64 PP_UDPSocket_Option name, 65 PP_UDPSocket_Option name,
65 const PP_Var& value, 66 const PP_Var& value,
66 bool check_bind_state, 67 bool check_bind_state,
67 scoped_refptr<TrackedCallback> callback) { 68 scoped_refptr<TrackedCallback> callback) {
68 if (closed_) 69 if (closed_)
69 return PP_ERROR_FAILED; 70 return PP_ERROR_FAILED;
70 71
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 PP_Bool UDPSocketResourceBase::GetBoundAddressImpl( 159 PP_Bool UDPSocketResourceBase::GetBoundAddressImpl(
159 PP_NetAddress_Private* addr) { 160 PP_NetAddress_Private* addr) {
160 if (!addr || !bound_ || closed_) 161 if (!addr || !bound_ || closed_)
161 return PP_FALSE; 162 return PP_FALSE;
162 163
163 *addr = bound_addr_; 164 *addr = bound_addr_;
164 return PP_TRUE; 165 return PP_TRUE;
165 } 166 }
166 167
167 int32_t UDPSocketResourceBase::RecvFromImpl( 168 int32_t UDPSocketResourceBase::RecvFromImpl(
168 char* buffer, 169 char* buffer_out,
169 int32_t num_bytes, 170 int32_t num_bytes,
170 PP_Resource* addr, 171 PP_Resource* addr,
171 scoped_refptr<TrackedCallback> callback) { 172 scoped_refptr<TrackedCallback> callback) {
172 if (!buffer || num_bytes <= 0) 173 return recv_filter_->RequestData(pp_resource(), num_bytes, buffer_out, addr,
173 return PP_ERROR_BADARGUMENT; 174 callback);
174 if (!bound_)
175 return PP_ERROR_FAILED;
176 if (TrackedCallback::IsPending(recvfrom_callback_))
177 return PP_ERROR_INPROGRESS;
178
179 if (recv_buffers_.empty()) {
180 read_buffer_ = buffer;
181 bytes_to_read_ = std::min(num_bytes, kMaxReadSize);
182 recvfrom_addr_resource_ = addr;
183 recvfrom_callback_ = callback;
184
185 return PP_OK_COMPLETIONPENDING;
186 } else {
187 RecvBuffer& front = recv_buffers_.front();
188
189 if (num_bytes < static_cast<int32_t>(front.data.size()))
190 return PP_ERROR_MESSAGE_TOO_BIG;
191
192 int32_t result = SetRecvFromOutput(front.result, front.data, front.addr,
193 buffer, num_bytes, addr);
194
195 recv_buffers_.pop();
196 Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable());
197
198 return result;
199 }
200 } 175 }
201 176
202 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl( 177 PP_Bool UDPSocketResourceBase::GetRecvFromAddressImpl(
203 PP_NetAddress_Private* addr) { 178 PP_NetAddress_Private* addr) {
204 if (!addr) 179 if (!addr)
205 return PP_FALSE; 180 return PP_FALSE;
206 *addr = recvfrom_addr_; 181 *addr = recv_filter_->GetLastAddrPrivate(pp_resource());
207 return PP_TRUE; 182 return PP_TRUE;
208 } 183 }
209 184
210 int32_t UDPSocketResourceBase::SendToImpl( 185 int32_t UDPSocketResourceBase::SendToImpl(
211 const char* buffer, 186 const char* buffer,
212 int32_t num_bytes, 187 int32_t num_bytes,
213 const PP_NetAddress_Private* addr, 188 const PP_NetAddress_Private* addr,
214 scoped_refptr<TrackedCallback> callback) { 189 scoped_refptr<TrackedCallback> callback) {
215 if (!buffer || num_bytes <= 0 || !addr) 190 if (!buffer || num_bytes <= 0 || !addr)
216 return PP_ERROR_BADARGUMENT; 191 return PP_ERROR_BADARGUMENT;
(...skipping 19 matching lines...) Expand all
236 211
237 void UDPSocketResourceBase::CloseImpl() { 212 void UDPSocketResourceBase::CloseImpl() {
238 if(closed_) 213 if(closed_)
239 return; 214 return;
240 215
241 bound_ = false; 216 bound_ = false;
242 closed_ = true; 217 closed_ = true;
243 218
244 Post(BROWSER, PpapiHostMsg_UDPSocket_Close()); 219 Post(BROWSER, PpapiHostMsg_UDPSocket_Close());
245 220
246 PostAbortIfNecessary(&bind_callback_); 221 PostAbortIfNecessary(bind_callback_);
247 PostAbortIfNecessary(&recvfrom_callback_);
248 while (!sendto_callbacks_.empty()) { 222 while (!sendto_callbacks_.empty()) {
249 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); 223 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front();
250 sendto_callbacks_.pop(); 224 sendto_callbacks_.pop();
251 PostAbortIfNecessary(&callback); 225 PostAbortIfNecessary(callback);
252 } 226 }
253 227 recv_filter_->RemoveUDPResource(pp_resource());
254 read_buffer_ = NULL;
255 bytes_to_read_ = -1;
256 } 228 }
257 229
258 int32_t UDPSocketResourceBase::JoinGroupImpl( 230 int32_t UDPSocketResourceBase::JoinGroupImpl(
259 const PP_NetAddress_Private *group, 231 const PP_NetAddress_Private *group,
260 scoped_refptr<TrackedCallback> callback) { 232 scoped_refptr<TrackedCallback> callback) {
261 DCHECK(group); 233 DCHECK(group);
262 234
263 Call<PpapiPluginMsg_UDPSocket_JoinGroupReply>( 235 Call<PpapiPluginMsg_UDPSocket_JoinGroupReply>(
264 BROWSER, 236 BROWSER,
265 PpapiHostMsg_UDPSocket_JoinGroup(*group), 237 PpapiHostMsg_UDPSocket_JoinGroup(*group),
(...skipping 12 matching lines...) Expand all
278 Call<PpapiPluginMsg_UDPSocket_LeaveGroupReply>( 250 Call<PpapiPluginMsg_UDPSocket_LeaveGroupReply>(
279 BROWSER, 251 BROWSER,
280 PpapiHostMsg_UDPSocket_LeaveGroup(*group), 252 PpapiHostMsg_UDPSocket_LeaveGroup(*group),
281 base::Bind(&UDPSocketResourceBase::OnPluginMsgGeneralReply, 253 base::Bind(&UDPSocketResourceBase::OnPluginMsgGeneralReply,
282 base::Unretained(this), 254 base::Unretained(this),
283 callback), 255 callback),
284 callback); 256 callback);
285 return PP_OK_COMPLETIONPENDING; 257 return PP_OK_COMPLETIONPENDING;
286 } 258 }
287 259
288 void UDPSocketResourceBase::OnReplyReceived(
289 const ResourceMessageReplyParams& params,
290 const IPC::Message& msg) {
291 PPAPI_BEGIN_MESSAGE_MAP(UDPSocketResourceBase, msg)
292 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
293 PpapiPluginMsg_UDPSocket_PushRecvResult,
294 OnPluginMsgPushRecvResult)
295 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
296 PluginResource::OnReplyReceived(params, msg))
297 PPAPI_END_MESSAGE_MAP()
298 }
299
300 void UDPSocketResourceBase::PostAbortIfNecessary(
301 scoped_refptr<TrackedCallback>* callback) {
302 if (TrackedCallback::IsPending(*callback))
303 (*callback)->PostAbort();
304 }
305
306 void UDPSocketResourceBase::OnPluginMsgGeneralReply( 260 void UDPSocketResourceBase::OnPluginMsgGeneralReply(
307 scoped_refptr<TrackedCallback> callback, 261 scoped_refptr<TrackedCallback> callback,
308 const ResourceMessageReplyParams& params) { 262 const ResourceMessageReplyParams& params) {
309 if (TrackedCallback::IsPending(callback)) 263 if (TrackedCallback::IsPending(callback))
310 RunCallback(callback, params.result()); 264 RunCallback(callback, params.result(), private_api_);
311 } 265 }
312 266
313 void UDPSocketResourceBase::OnPluginMsgBindReply( 267 void UDPSocketResourceBase::OnPluginMsgBindReply(
314 const ResourceMessageReplyParams& params, 268 const ResourceMessageReplyParams& params,
315 const PP_NetAddress_Private& bound_addr) { 269 const PP_NetAddress_Private& bound_addr) {
316 // It is possible that |bind_callback_| is pending while |closed_| is true: 270 // It is possible that |bind_callback_| is pending while |closed_| is true:
317 // CloseImpl() has been called, but a BindReply came earlier than the task to 271 // CloseImpl() has been called, but a BindReply came earlier than the task to
318 // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_| 272 // abort |bind_callback_|. We don't want to update |bound_| or |bound_addr_|
319 // in that case. 273 // in that case.
320 if (!TrackedCallback::IsPending(bind_callback_) || closed_) 274 if (!TrackedCallback::IsPending(bind_callback_) || closed_)
321 return; 275 return;
322 276
323 if (params.result() == PP_OK) 277 if (params.result() == PP_OK)
324 bound_ = true; 278 bound_ = true;
325 bound_addr_ = bound_addr; 279 bound_addr_ = bound_addr;
326 RunCallback(bind_callback_, params.result()); 280 RunCallback(bind_callback_, params.result(), private_api_);
327 }
328
329 void UDPSocketResourceBase::OnPluginMsgPushRecvResult(
330 const ResourceMessageReplyParams& params,
331 int32_t result,
332 const std::string& data,
333 const PP_NetAddress_Private& addr) {
334 // TODO(yzshen): Support passing in a non-const string ref, so that we can
335 // eliminate one copy when storing the data in the buffer.
336
337 DCHECK_LT(recv_buffers_.size(), kPluginReceiveBufferSlots);
338
339 if (!TrackedCallback::IsPending(recvfrom_callback_) || !read_buffer_) {
340 recv_buffers_.push(RecvBuffer());
341 RecvBuffer& back = recv_buffers_.back();
342 back.result = result;
343 back.data = data;
344 back.addr = addr;
345
346 return;
347 }
348
349 DCHECK_EQ(recv_buffers_.size(), 0u);
350
351 if (bytes_to_read_ < static_cast<int32_t>(data.size())) {
352 recv_buffers_.push(RecvBuffer());
353 RecvBuffer& back = recv_buffers_.back();
354 back.result = result;
355 back.data = data;
356 back.addr = addr;
357
358 result = PP_ERROR_MESSAGE_TOO_BIG;
359 } else {
360 result = SetRecvFromOutput(result, data, addr, read_buffer_, bytes_to_read_,
361 recvfrom_addr_resource_);
362 Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable());
363 }
364
365 read_buffer_ = NULL;
366 bytes_to_read_ = -1;
367 recvfrom_addr_resource_ = NULL;
368
369 RunCallback(recvfrom_callback_, result);
370 } 281 }
371 282
372 void UDPSocketResourceBase::OnPluginMsgSendToReply( 283 void UDPSocketResourceBase::OnPluginMsgSendToReply(
373 const ResourceMessageReplyParams& params, 284 const ResourceMessageReplyParams& params,
374 int32_t bytes_written) { 285 int32_t bytes_written) {
375 // This can be empty if the socket was closed, but there are still tasks 286 // This can be empty if the socket was closed, but there are still tasks
376 // to be posted for this resource. 287 // to be posted for this resource.
377 if (sendto_callbacks_.empty()) 288 if (sendto_callbacks_.empty())
378 return; 289 return;
379 290
380 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front(); 291 scoped_refptr<TrackedCallback> callback = sendto_callbacks_.front();
381 sendto_callbacks_.pop(); 292 sendto_callbacks_.pop();
382 if (!TrackedCallback::IsPending(callback)) 293 if (!TrackedCallback::IsPending(callback))
383 return; 294 return;
384 295
385 if (params.result() == PP_OK) 296 if (params.result() == PP_OK)
386 RunCallback(callback, bytes_written); 297 RunCallback(callback, bytes_written, private_api_);
387 else 298 else
388 RunCallback(callback, params.result()); 299 RunCallback(callback, params.result(), private_api_);
389 } 300 }
390 301
391 void UDPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback, 302 // static
392 int32_t pp_result) { 303 void UDPSocketResourceBase::SlotBecameAvailable(PP_Resource resource) {
393 callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result, 304 PluginGlobals* globals = PluginGlobals::Get();
394 private_api_)); 305 if (globals->ipc_task_runner()->RunsTasksOnCurrentThread()) {
306 // We were invoked on the IO thread, so we do *not* have the ProxyLock and
307 // we have to post over to the main thread in order to get the resource and
308 // send the message.
309 // TODO(dmichael): This is kind of stupid; we ought to be able to build up
310 // the right message and send it directly from the IO thread. Unfortunately,
311 // we need to get a sequence number, which right now requires the ProxyLock.
312 if (globals->GetMainThreadMessageLoop()) {
313 globals->GetMainThreadMessageLoop()->PostTask(FROM_HERE,
314 RunWhileLocked(base::Bind(
315 &UDPSocketResourceBase::SlotBecameAvailableWithLock, resource)));
316 }
317 } else {
318 SlotBecameAvailableWithLock(resource);
319 }
395 } 320 }
396 321
397 int32_t UDPSocketResourceBase::SetRecvFromOutput( 322 // static
398 int32_t browser_result, 323 void UDPSocketResourceBase::SlotBecameAvailableWithLock(PP_Resource resource) {
399 const std::string& data, 324 ProxyLock::AssertAcquired();
400 const PP_NetAddress_Private& addr, 325 // Note, we don't have the ProxyLock yet, so we use EnterResource to acquire
raymes 2015/03/25 01:43:59 If we don't have the proxylock why is AssertAcquir
dmichael (off chromium) 2015/03/25 17:35:04 Oops, sorry, that comment made sense before I fixe
401 char* output_buffer, 326 // it. (We couldn't use RunWhileLocked in SlotBecameAvailableOnIOThread
raymes 2015/03/25 01:43:59 SlotBecameAvailableOnIOThread isn't around anymore
dmichael (off chromium) 2015/03/25 17:35:04 Done.
402 int32_t num_bytes, 327 // because it requires the ProxyLock, which we can't acquire on the IO
403 PP_Resource* output_addr) { 328 // thread).
404 DCHECK_GE(num_bytes, static_cast<int32_t>(data.size())); 329 thunk::EnterResourceNoLock<thunk::PPB_UDPSocket_API> enter(resource, false);
330 if (enter.failed())
331 return;
332 auto thiz(static_cast<UDPSocketResourceBase*>(enter.resource()));
405 333
406 int32_t result = browser_result; 334 if (!thiz->closed_)
407 if (result == PP_OK && output_addr) { 335 thiz->Post(BROWSER, PpapiHostMsg_UDPSocket_RecvSlotAvailable());
408 thunk::EnterResourceCreationNoLock enter(pp_instance());
409 if (enter.succeeded()) {
410 *output_addr = enter.functions()->CreateNetAddressFromNetAddressPrivate(
411 pp_instance(), addr);
412 } else {
413 result = PP_ERROR_FAILED;
414 }
415 }
416
417 if (result == PP_OK && !data.empty())
418 memcpy(output_buffer, data.c_str(), data.size());
419
420 recvfrom_addr_ = addr;
421
422 return result == PP_OK ? static_cast<int32_t>(data.size()) : result;
423 } 336 }
424 337
425 } // namespace proxy 338 } // namespace proxy
426 } // namespace ppapi 339 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698