OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/ppb_file_ref_proxy.h" | 5 #include "ppapi/proxy/ppb_file_ref_proxy.h" |
6 | 6 |
| 7 #include <map> |
| 8 |
| 9 #include "base/bind.h" |
7 #include "ppapi/c/pp_errors.h" | 10 #include "ppapi/c/pp_errors.h" |
8 #include "ppapi/c/ppb_file_ref.h" | 11 #include "ppapi/c/ppb_file_ref.h" |
9 #include "ppapi/c/private/ppb_proxy_private.h" | 12 #include "ppapi/c/private/ppb_proxy_private.h" |
10 #include "ppapi/proxy/enter_proxy.h" | 13 #include "ppapi/proxy/enter_proxy.h" |
11 #include "ppapi/proxy/host_dispatcher.h" | 14 #include "ppapi/proxy/host_dispatcher.h" |
12 #include "ppapi/proxy/plugin_dispatcher.h" | 15 #include "ppapi/proxy/plugin_dispatcher.h" |
13 #include "ppapi/proxy/ppapi_messages.h" | 16 #include "ppapi/proxy/ppapi_messages.h" |
14 #include "ppapi/proxy/serialized_var.h" | 17 #include "ppapi/proxy/serialized_var.h" |
15 #include "ppapi/shared_impl/file_ref_impl.h" | 18 #include "ppapi/shared_impl/file_ref_impl.h" |
16 #include "ppapi/thunk/resource_creation_api.h" | 19 #include "ppapi/thunk/resource_creation_api.h" |
(...skipping 16 matching lines...) Expand all Loading... |
33 virtual PP_Resource GetParent() OVERRIDE; | 36 virtual PP_Resource GetParent() OVERRIDE; |
34 virtual int32_t MakeDirectory(PP_Bool make_ancestors, | 37 virtual int32_t MakeDirectory(PP_Bool make_ancestors, |
35 PP_CompletionCallback callback) OVERRIDE; | 38 PP_CompletionCallback callback) OVERRIDE; |
36 virtual int32_t Touch(PP_Time last_access_time, | 39 virtual int32_t Touch(PP_Time last_access_time, |
37 PP_Time last_modified_time, | 40 PP_Time last_modified_time, |
38 PP_CompletionCallback callback) OVERRIDE; | 41 PP_CompletionCallback callback) OVERRIDE; |
39 virtual int32_t Delete(PP_CompletionCallback callback) OVERRIDE; | 42 virtual int32_t Delete(PP_CompletionCallback callback) OVERRIDE; |
40 virtual int32_t Rename(PP_Resource new_file_ref, | 43 virtual int32_t Rename(PP_Resource new_file_ref, |
41 PP_CompletionCallback callback) OVERRIDE; | 44 PP_CompletionCallback callback) OVERRIDE; |
42 | 45 |
| 46 // Executes the pending callback with the given ID. See pending_callbacks_. |
| 47 void ExecuteCallback(int callback_id, int32_t result); |
| 48 |
43 private: | 49 private: |
44 PluginDispatcher* GetDispatcher() const { | 50 PluginDispatcher* GetDispatcher() const { |
45 return PluginDispatcher::GetForResource(this); | 51 return PluginDispatcher::GetForResource(this); |
46 } | 52 } |
47 | 53 |
| 54 // Adds a callback to the list and returns its ID. Returns 0 if the callback |
| 55 // is invalid. |
| 56 int SendCallback(PP_CompletionCallback callback); |
| 57 |
| 58 // This class can have any number of out-standing requests with completion |
| 59 // callbacks, in contrast to most resources which have one possible pending |
| 60 // callback pending (like a Flush callback). |
| 61 // |
| 62 // To keep track of them, assign integer IDs to the callbacks, which is how |
| 63 // the callback will be identified when it's passed to the host and then |
| 64 // back here. |
| 65 int next_callback_id_; |
| 66 typedef std::map<int, PP_CompletionCallback> PendingCallbackMap; |
| 67 PendingCallbackMap pending_callbacks_; |
| 68 |
48 DISALLOW_IMPLICIT_CONSTRUCTORS(FileRef); | 69 DISALLOW_IMPLICIT_CONSTRUCTORS(FileRef); |
49 }; | 70 }; |
50 | 71 |
51 FileRef::FileRef(const PPB_FileRef_CreateInfo& info) | 72 FileRef::FileRef(const PPB_FileRef_CreateInfo& info) |
52 : FileRefImpl(FileRefImpl::InitAsProxy(), info) { | 73 : FileRefImpl(FileRefImpl::InitAsProxy(), info), |
| 74 next_callback_id_(0) { |
53 } | 75 } |
54 | 76 |
55 FileRef::~FileRef() { | 77 FileRef::~FileRef() { |
| 78 // Abort all pending callbacks. Do this by posting a task to avoid reentering |
| 79 // the plugin's Release() call that probably deleted this object. |
| 80 for (PendingCallbackMap::iterator i = pending_callbacks_.begin(); |
| 81 i != pending_callbacks_.end(); ++i) { |
| 82 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 83 i->second.func, i->second.user_data, |
| 84 static_cast<int32_t>(PP_ERROR_ABORTED))); |
| 85 } |
56 } | 86 } |
57 | 87 |
58 PP_Resource FileRef::GetParent() { | 88 PP_Resource FileRef::GetParent() { |
59 PPB_FileRef_CreateInfo create_info; | 89 PPB_FileRef_CreateInfo create_info; |
60 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_GetParent( | 90 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_GetParent( |
61 API_ID_PPB_FILE_REF, host_resource(), &create_info)); | 91 API_ID_PPB_FILE_REF, host_resource(), &create_info)); |
62 return PPB_FileRef_Proxy::DeserializeFileRef(create_info); | 92 return PPB_FileRef_Proxy::DeserializeFileRef(create_info); |
63 } | 93 } |
64 | 94 |
65 int32_t FileRef::MakeDirectory(PP_Bool make_ancestors, | 95 int32_t FileRef::MakeDirectory(PP_Bool make_ancestors, |
66 PP_CompletionCallback callback) { | 96 PP_CompletionCallback callback) { |
| 97 int callback_id = SendCallback(callback); |
| 98 if (!callback_id) |
| 99 return PP_ERROR_BADARGUMENT; |
| 100 |
67 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_MakeDirectory( | 101 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_MakeDirectory( |
68 API_ID_PPB_FILE_REF, host_resource(), make_ancestors, | 102 API_ID_PPB_FILE_REF, host_resource(), make_ancestors, callback_id)); |
69 GetDispatcher()->callback_tracker().SendCallback(callback))); | |
70 return PP_OK_COMPLETIONPENDING; | 103 return PP_OK_COMPLETIONPENDING; |
71 } | 104 } |
72 | 105 |
73 int32_t FileRef::Touch(PP_Time last_access_time, | 106 int32_t FileRef::Touch(PP_Time last_access_time, |
74 PP_Time last_modified_time, | 107 PP_Time last_modified_time, |
75 PP_CompletionCallback callback) { | 108 PP_CompletionCallback callback) { |
| 109 int callback_id = SendCallback(callback); |
| 110 if (!callback_id) |
| 111 return PP_ERROR_BADARGUMENT; |
| 112 |
76 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Touch( | 113 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Touch( |
77 API_ID_PPB_FILE_REF, host_resource(), | 114 API_ID_PPB_FILE_REF, host_resource(), |
78 last_access_time, last_modified_time, | 115 last_access_time, last_modified_time, callback_id)); |
79 GetDispatcher()->callback_tracker().SendCallback(callback))); | |
80 return PP_OK_COMPLETIONPENDING; | 116 return PP_OK_COMPLETIONPENDING; |
81 } | 117 } |
82 | 118 |
83 int32_t FileRef::Delete(PP_CompletionCallback callback) { | 119 int32_t FileRef::Delete(PP_CompletionCallback callback) { |
| 120 int callback_id = SendCallback(callback); |
| 121 if (!callback_id) |
| 122 return PP_ERROR_BADARGUMENT; |
| 123 |
84 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Delete( | 124 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Delete( |
85 API_ID_PPB_FILE_REF, host_resource(), | 125 API_ID_PPB_FILE_REF, host_resource(), callback_id)); |
86 GetDispatcher()->callback_tracker().SendCallback(callback))); | |
87 return PP_OK_COMPLETIONPENDING; | 126 return PP_OK_COMPLETIONPENDING; |
88 } | 127 } |
89 | 128 |
90 int32_t FileRef::Rename(PP_Resource new_file_ref, | 129 int32_t FileRef::Rename(PP_Resource new_file_ref, |
91 PP_CompletionCallback callback) { | 130 PP_CompletionCallback callback) { |
| 131 int callback_id = SendCallback(callback); |
| 132 if (!callback_id) |
| 133 return PP_ERROR_BADARGUMENT; |
| 134 |
92 Resource* new_file_ref_object = | 135 Resource* new_file_ref_object = |
93 PpapiGlobals::Get()->GetResourceTracker()->GetResource(new_file_ref); | 136 PpapiGlobals::Get()->GetResourceTracker()->GetResource(new_file_ref); |
94 if (!new_file_ref_object || | 137 if (!new_file_ref_object || |
95 new_file_ref_object->host_resource().instance() != pp_instance()) | 138 new_file_ref_object->host_resource().instance() != pp_instance()) |
96 return PP_ERROR_BADRESOURCE; | 139 return PP_ERROR_BADRESOURCE; |
97 | 140 |
98 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Rename( | 141 GetDispatcher()->Send(new PpapiHostMsg_PPBFileRef_Rename( |
99 API_ID_PPB_FILE_REF, host_resource(), | 142 API_ID_PPB_FILE_REF, host_resource(), |
100 new_file_ref_object->host_resource(), | 143 new_file_ref_object->host_resource(), callback_id)); |
101 GetDispatcher()->callback_tracker().SendCallback(callback))); | |
102 return PP_OK_COMPLETIONPENDING; | 144 return PP_OK_COMPLETIONPENDING; |
103 } | 145 } |
104 | 146 |
| 147 void FileRef::ExecuteCallback(int callback_id, int32_t result) { |
| 148 PendingCallbackMap::iterator found = pending_callbacks_.find(callback_id); |
| 149 if (found == pending_callbacks_.end()) { |
| 150 // This will happen when the plugin deletes its resource with a pending |
| 151 // callback. The callback will be locally issued with an ABORTED call while |
| 152 // the operation may still be pending in the renderer. |
| 153 return; |
| 154 } |
| 155 |
| 156 // Executing the callback may mutate the callback list. |
| 157 PP_CompletionCallback callback = found->second; |
| 158 pending_callbacks_.erase(found); |
| 159 PP_RunCompletionCallback(&callback, result); |
| 160 } |
| 161 |
| 162 int FileRef::SendCallback(PP_CompletionCallback callback) { |
| 163 if (!callback.func) |
| 164 return 0; |
| 165 |
| 166 // In extreme cases the IDs may wrap around, so avoid duplicates. |
| 167 while (pending_callbacks_.find(next_callback_id_) != pending_callbacks_.end()) |
| 168 next_callback_id_++; |
| 169 |
| 170 pending_callbacks_[next_callback_id_] = callback; |
| 171 return next_callback_id_++; |
| 172 } |
| 173 |
105 PPB_FileRef_Proxy::PPB_FileRef_Proxy(Dispatcher* dispatcher) | 174 PPB_FileRef_Proxy::PPB_FileRef_Proxy(Dispatcher* dispatcher) |
106 : InterfaceProxy(dispatcher) { | 175 : InterfaceProxy(dispatcher), |
| 176 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
107 } | 177 } |
108 | 178 |
109 PPB_FileRef_Proxy::~PPB_FileRef_Proxy() { | 179 PPB_FileRef_Proxy::~PPB_FileRef_Proxy() { |
110 } | 180 } |
111 | 181 |
112 // static | 182 // static |
113 PP_Resource PPB_FileRef_Proxy::CreateProxyResource(PP_Resource file_system, | 183 PP_Resource PPB_FileRef_Proxy::CreateProxyResource(PP_Resource file_system, |
114 const char* path) { | 184 const char* path) { |
115 Resource* file_system_object = | 185 Resource* file_system_object = |
116 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_system); | 186 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_system); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 | 240 |
171 void PPB_FileRef_Proxy::OnMsgGetParent(const HostResource& host_resource, | 241 void PPB_FileRef_Proxy::OnMsgGetParent(const HostResource& host_resource, |
172 PPB_FileRef_CreateInfo* result) { | 242 PPB_FileRef_CreateInfo* result) { |
173 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); | 243 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); |
174 if (enter.succeeded()) | 244 if (enter.succeeded()) |
175 SerializeFileRef(enter.object()->GetParent(), result); | 245 SerializeFileRef(enter.object()->GetParent(), result); |
176 } | 246 } |
177 | 247 |
178 void PPB_FileRef_Proxy::OnMsgMakeDirectory(const HostResource& host_resource, | 248 void PPB_FileRef_Proxy::OnMsgMakeDirectory(const HostResource& host_resource, |
179 PP_Bool make_ancestors, | 249 PP_Bool make_ancestors, |
180 uint32_t serialized_callback) { | 250 int callback_id) { |
181 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); | 251 EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( |
182 if (enter.failed()) | 252 host_resource, callback_factory_, |
183 return; | 253 &PPB_FileRef_Proxy::OnCallbackCompleteInHost, host_resource, callback_id); |
184 PP_CompletionCallback callback = ReceiveCallback(serialized_callback); | 254 if (enter.succeeded()) { |
185 int32_t result = enter.object()->MakeDirectory(make_ancestors, callback); | 255 enter.SetResult(enter.object()->MakeDirectory(make_ancestors, |
186 if (result != PP_OK_COMPLETIONPENDING) | 256 enter.callback())); |
187 PP_RunCompletionCallback(&callback, result); | 257 } |
188 } | 258 } |
189 | 259 |
190 void PPB_FileRef_Proxy::OnMsgTouch(const HostResource& host_resource, | 260 void PPB_FileRef_Proxy::OnMsgTouch(const HostResource& host_resource, |
191 PP_Time last_access, | 261 PP_Time last_access, |
192 PP_Time last_modified, | 262 PP_Time last_modified, |
193 uint32_t serialized_callback) { | 263 int callback_id) { |
194 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); | 264 EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( |
195 if (enter.failed()) | 265 host_resource, callback_factory_, |
196 return; | 266 &PPB_FileRef_Proxy::OnCallbackCompleteInHost, host_resource, callback_id); |
197 PP_CompletionCallback callback = ReceiveCallback(serialized_callback); | 267 if (enter.succeeded()) { |
198 int32_t result = enter.object()->Touch(last_access, last_modified, callback); | 268 enter.SetResult(enter.object()->Touch(last_access, last_modified, |
199 if (result != PP_OK_COMPLETIONPENDING) | 269 enter.callback())); |
200 PP_RunCompletionCallback(&callback, result); | 270 } |
201 } | 271 } |
202 | 272 |
203 void PPB_FileRef_Proxy::OnMsgDelete(const HostResource& host_resource, | 273 void PPB_FileRef_Proxy::OnMsgDelete(const HostResource& host_resource, |
204 uint32_t serialized_callback) { | 274 int callback_id) { |
205 EnterHostFromHostResource<PPB_FileRef_API> enter(host_resource); | 275 EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( |
206 if (enter.failed()) | 276 host_resource, callback_factory_, |
207 return; | 277 &PPB_FileRef_Proxy::OnCallbackCompleteInHost, host_resource, callback_id); |
208 PP_CompletionCallback callback = ReceiveCallback(serialized_callback); | 278 if (enter.succeeded()) |
209 int32_t result = enter.object()->Delete(callback); | 279 enter.SetResult(enter.object()->Delete(enter.callback())); |
210 if (result != PP_OK_COMPLETIONPENDING) | |
211 PP_RunCompletionCallback(&callback, result); | |
212 } | 280 } |
213 | 281 |
214 void PPB_FileRef_Proxy::OnMsgRename(const HostResource& file_ref, | 282 void PPB_FileRef_Proxy::OnMsgRename(const HostResource& file_ref, |
215 const HostResource& new_file_ref, | 283 const HostResource& new_file_ref, |
216 uint32_t serialized_callback) { | 284 int callback_id) { |
217 EnterHostFromHostResource<PPB_FileRef_API> enter(file_ref); | 285 EnterHostFromHostResourceForceCallback<PPB_FileRef_API> enter( |
218 if (enter.failed()) | 286 file_ref, callback_factory_, |
219 return; | 287 &PPB_FileRef_Proxy::OnCallbackCompleteInHost, file_ref, callback_id); |
220 PP_CompletionCallback callback = ReceiveCallback(serialized_callback); | 288 if (enter.succeeded()) { |
221 int32_t result = enter.object()->Rename(new_file_ref.host_resource(), | 289 enter.SetResult(enter.object()->Rename(new_file_ref.host_resource(), |
222 callback); | 290 enter.callback())); |
223 if (result != PP_OK_COMPLETIONPENDING) | 291 } |
224 PP_RunCompletionCallback(&callback, result); | 292 } |
| 293 |
| 294 void PPB_FileRef_Proxy::OnMsgCallbackComplete( |
| 295 const HostResource& host_resource, |
| 296 int callback_id, |
| 297 int32_t result) { |
| 298 // Forward the callback info to the plugin resource. |
| 299 EnterPluginFromHostResource<PPB_FileRef_API> enter(host_resource); |
| 300 if (enter.succeeded()) |
| 301 static_cast<FileRef*>(enter.object())->ExecuteCallback(callback_id, result); |
| 302 } |
| 303 |
| 304 void PPB_FileRef_Proxy::OnCallbackCompleteInHost( |
| 305 int32_t result, |
| 306 const HostResource& host_resource, |
| 307 int callback_id) { |
| 308 // Execute OnMsgCallbackComplete in the plugin process. |
| 309 Send(new PpapiMsg_PPBFileRef_CallbackComplete( |
| 310 API_ID_PPB_FILE_REF, host_resource, callback_id, result)); |
225 } | 311 } |
226 | 312 |
227 } // namespace proxy | 313 } // namespace proxy |
228 } // namespace ppapi | 314 } // namespace ppapi |
OLD | NEW |