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

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

Powered by Google App Engine
This is Rietveld 408576698