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

Side by Side Diff: ppapi/proxy/udp_socket_filter.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: Remove obsolete comment and proxy_lock change 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
« no previous file with comments | « ppapi/proxy/udp_socket_filter.h ('k') | ppapi/proxy/udp_socket_resource_base.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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 "ppapi/proxy/udp_socket_filter.h"
6
7 #include <algorithm>
8 #include <cstring>
9
10 #include "base/logging.h"
11 #include "ppapi/c/pp_errors.h"
12 #include "ppapi/proxy/error_conversion.h"
13 #include "ppapi/proxy/plugin_globals.h"
14 #include "ppapi/proxy/ppapi_messages.h"
15 #include "ppapi/thunk/enter.h"
16 #include "ppapi/thunk/resource_creation_api.h"
17
18 namespace ppapi {
19 namespace proxy {
20
21 const int32_t UDPSocketFilter::kMaxReadSize = 128 * 1024;
22 const int32_t UDPSocketFilter::kMaxReceiveBufferSize =
23 1024 * UDPSocketFilter::kMaxReadSize;
24 const size_t UDPSocketFilter::kPluginReceiveBufferSlots = 32u;
25
26 namespace {
27
28 int32_t SetRecvFromOutput(PP_Instance pp_instance,
29 const scoped_ptr<std::string>& data,
30 const PP_NetAddress_Private& addr,
31 char* output_buffer,
32 int32_t num_bytes,
33 PP_Resource* output_addr,
34 int32_t browser_result) {
35 ProxyLock::AssertAcquired();
36 DCHECK_GE(num_bytes, static_cast<int32_t>(data->size()));
37
38 int32_t result = browser_result;
39 if (result == PP_OK && output_addr) {
40 thunk::EnterResourceCreationNoLock enter(pp_instance);
41 if (enter.succeeded()) {
42 *output_addr = enter.functions()->CreateNetAddressFromNetAddressPrivate(
43 pp_instance, addr);
44 } else {
45 result = PP_ERROR_FAILED;
46 }
47 }
48
49 if (result == PP_OK && !data->empty())
50 memcpy(output_buffer, data->c_str(), data->size());
51
52 result = result == PP_OK ? static_cast<int32_t>(data->size()) : result;
53 return result;
raymes 2015/03/26 06:30:51 nit: is it clearer to keep this the same as before
dmichael (off chromium) 2015/03/26 18:19:43 Wow, not sure what I was smoking when I changed th
54 }
55
56 } // namespace
57
58 UDPSocketFilter::UDPSocketFilter() {
59 }
60
61 UDPSocketFilter::~UDPSocketFilter() {
62 }
63
64 void UDPSocketFilter::AddUDPResource(
65 PP_Instance instance,
66 PP_Resource resource,
67 bool private_api,
68 const base::Closure& slot_available_callback) {
69 ProxyLock::AssertAcquired();
70 base::AutoLock acquire(lock_);
71 DCHECK(!queues_.contains(resource));
72 queues_.add(resource, scoped_ptr<RecvQueue>(new RecvQueue(
73 instance, private_api, slot_available_callback)));
74 }
75
76 void UDPSocketFilter::RemoveUDPResource(PP_Resource resource) {
77 ProxyLock::AssertAcquired();
78 base::AutoLock acquire(lock_);
79 DCHECK(queues_.contains(resource));
80 queues_.erase(resource);
81 }
82
83 int32_t UDPSocketFilter::RequestData(
84 PP_Resource resource,
85 int32_t num_bytes,
86 char* buffer,
87 PP_Resource* addr,
88 const scoped_refptr<TrackedCallback>& callback) {
89 ProxyLock::AssertAcquired();
90 base::AutoLock acquire(lock_);
91 RecvQueue* queue_ptr = queues_.get(resource);
92 if (!queue_ptr) {
93 NOTREACHED();
94 return PP_ERROR_FAILED;
95 }
96 return queue_ptr->RequestData(num_bytes, buffer, addr, callback);
97 }
98
99 bool UDPSocketFilter::OnResourceReplyReceived(
100 const ResourceMessageReplyParams& params,
101 const IPC::Message& nested_msg) {
102 bool handled = true;
103 PPAPI_BEGIN_MESSAGE_MAP(UDPSocketFilter, nested_msg)
104 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(PpapiPluginMsg_UDPSocket_PushRecvResult,
105 OnPluginMsgPushRecvResult)
106 PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(handled = false)
107 PPAPI_END_MESSAGE_MAP()
108 return handled;
109 }
110
111 PP_NetAddress_Private UDPSocketFilter::GetLastAddrPrivate(
112 PP_Resource resource) const {
113 base::AutoLock acquire(lock_);
114 return queues_.get(resource)->GetLastAddrPrivate();
115 }
116
117 void UDPSocketFilter::OnPluginMsgPushRecvResult(
118 const ResourceMessageReplyParams& params,
119 int32_t result,
120 const std::string& data,
121 const PP_NetAddress_Private& addr) {
122 DCHECK(PluginGlobals::Get()->ipc_task_runner()->RunsTasksOnCurrentThread());
123 base::AutoLock acquire(lock_);
124 RecvQueue* queue_ptr = queues_.get(params.pp_resource());
125 // The RecvQueue might be gone if there were messages in-flight for a
126 // resource that has been destroyed.
127 if (queue_ptr) {
128 // TODO(yzshen): Support passing in a non-const string ref, so that we can
129 // eliminate one copy when storing the data in the buffer.
130 queue_ptr->DataReceivedOnIOThread(result, data, addr);
131 }
132 }
133
134 UDPSocketFilter::RecvQueue::RecvQueue(
135 PP_Instance pp_instance,
136 bool private_api,
137 const base::Closure& slot_available_callback)
138 : pp_instance_(pp_instance),
139 read_buffer_(nullptr),
140 bytes_to_read_(0),
141 recvfrom_addr_resource_(nullptr),
142 last_recvfrom_addr_(),
143 private_api_(private_api),
144 slot_available_callback_(slot_available_callback) {
145 }
146
147 UDPSocketFilter::RecvQueue::~RecvQueue() {
148 if (TrackedCallback::IsPending(recvfrom_callback_))
149 recvfrom_callback_->PostAbort();
150 }
151
152 void UDPSocketFilter::RecvQueue::DataReceivedOnIOThread(
153 int32_t result,
154 const std::string& data,
155 const PP_NetAddress_Private& addr) {
156 DCHECK(PluginGlobals::Get()->ipc_task_runner()->RunsTasksOnCurrentThread());
157 DCHECK_LT(recv_buffers_.size(), UDPSocketFilter::kPluginReceiveBufferSlots);
158
159 if (!TrackedCallback::IsPending(recvfrom_callback_) || !read_buffer_) {
160 recv_buffers_.push(RecvBuffer());
161 RecvBuffer& back = recv_buffers_.back();
162 back.result = result;
163 back.data = data;
164 back.addr = addr;
165 return;
166 }
167 DCHECK_EQ(recv_buffers_.size(), 0u);
168
169 if (bytes_to_read_ < static_cast<int32_t>(data.size())) {
170 recv_buffers_.push(RecvBuffer());
171 RecvBuffer& back = recv_buffers_.back();
172 back.result = result;
173 back.data = data;
174 back.addr = addr;
175
176 result = PP_ERROR_MESSAGE_TOO_BIG;
177 } else {
178 // Instead of calling SetRecvFromOutput directly, post it as a completion
179 // task, so that:
180 // 1) It can run with the ProxyLock (we can't lock it on the IO thread.)
181 // 2) So that we only write to the output params in the case of success.
182 // (Since the callback will complete on another thread, it's possible
183 // that the resource will be deleted and abort the callback before it
184 // is actually run.)
185 scoped_ptr<std::string> data_to_pass(new std::string(data));
186 recvfrom_callback_->set_completion_task(base::Bind(
187 &SetRecvFromOutput, pp_instance_, base::Passed(data_to_pass.Pass()),
188 addr, base::Unretained(read_buffer_), bytes_to_read_,
189 base::Unretained(recvfrom_addr_resource_)));
190 last_recvfrom_addr_ = addr;
191 slot_available_callback_.Run();
192 }
193
194 read_buffer_ = NULL;
195 bytes_to_read_ = -1;
196 recvfrom_addr_resource_ = NULL;
197
198 recvfrom_callback_->Run(
199 ConvertNetworkAPIErrorForCompatibility(result, private_api_));
200 }
201
202 int32_t UDPSocketFilter::RecvQueue::RequestData(
203 int32_t num_bytes,
204 char* buffer_out,
205 PP_Resource* addr_out,
206 const scoped_refptr<TrackedCallback>& callback) {
207 ProxyLock::AssertAcquired();
208 if (!buffer_out || num_bytes <= 0)
209 return PP_ERROR_BADARGUMENT;
raymes 2015/03/26 06:30:51 we used to bail if the thing wasn't bound here, sh
dmichael (off chromium) 2015/03/26 18:19:43 Good catch. I added that check back to UDPSocketRe
210 if (TrackedCallback::IsPending(recvfrom_callback_))
211 return PP_ERROR_INPROGRESS;
212
213 if (recv_buffers_.empty()) {
214 read_buffer_ = buffer_out;
215 bytes_to_read_ = std::min(num_bytes, UDPSocketFilter::kMaxReadSize);
216 recvfrom_addr_resource_ = addr_out;
217 recvfrom_callback_ = callback;
218 return PP_OK_COMPLETIONPENDING;
219 } else {
220 RecvBuffer& front = recv_buffers_.front();
221
222 if (num_bytes < static_cast<int32_t>(front.data.size()))
223 return PP_ERROR_MESSAGE_TOO_BIG;
224
225 int32_t result = front.data.size();
226 scoped_ptr<std::string> data_to_pass(new std::string);
227 data_to_pass->swap(front.data);
228 SetRecvFromOutput(pp_instance_, data_to_pass.Pass(), front.addr, buffer_out,
229 num_bytes, addr_out, PP_OK);
230 last_recvfrom_addr_ = front.addr;
231 recv_buffers_.pop();
232 slot_available_callback_.Run();
233
234 return result;
235 }
236 }
237
238 PP_NetAddress_Private UDPSocketFilter::RecvQueue::GetLastAddrPrivate() const {
239 CHECK(private_api_);
240 return last_recvfrom_addr_;
241 }
242
243 } // namespace proxy
244 } // namespace ppapi
OLDNEW
« no previous file with comments | « ppapi/proxy/udp_socket_filter.h ('k') | ppapi/proxy/udp_socket_resource_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698