[M108 Aura Migration][NaCl][PPFwk] Add error logs + SVACE/DLOG/Static analysis fix
[platform/framework/web/chromium-efl.git] / ppapi / proxy / ppb_message_loop_proxy.cc
1 // Copyright 2012 The Chromium Authors
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/ppb_message_loop_proxy.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/callback_helpers.h"
14 #include "base/check.h"
15 #include "base/compiler_specific.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "ppapi/c/pp_errors.h"
18 #include "ppapi/c/ppb_message_loop.h"
19 #include "ppapi/proxy/plugin_dispatcher.h"
20 #include "ppapi/proxy/plugin_globals.h"
21 #include "ppapi/shared_impl/proxy_lock.h"
22 #include "ppapi/thunk/enter.h"
23
24 using ppapi::thunk::PPB_MessageLoop_API;
25
26 namespace ppapi {
27 namespace proxy {
28
29 namespace {
30 typedef thunk::EnterResource<PPB_MessageLoop_API> EnterMessageLoop;
31 }
32
33 MessageLoopResource::MessageLoopResource(PP_Instance instance)
34     : MessageLoopShared(instance),
35       nested_invocations_(0),
36       destroyed_(false),
37       should_destroy_(false),
38       is_main_thread_loop_(false),
39       currently_handling_blocking_message_(false) {
40 }
41
42 MessageLoopResource::MessageLoopResource(ForMainThread for_main_thread)
43     : MessageLoopShared(for_main_thread),
44       nested_invocations_(0),
45       destroyed_(false),
46       should_destroy_(false),
47       is_main_thread_loop_(true),
48       currently_handling_blocking_message_(false) {
49   // We attach the main thread immediately. We can't use AttachToCurrentThread,
50   // because the MessageLoop already exists.
51
52   // This must be called only once, so the slot must be empty.
53   CHECK(!PluginGlobals::Get()->msg_loop_slot());
54   // We don't add a reference for TLS here, so we don't release it. Instead,
55   // this loop is owned by PluginGlobals. Contrast with AttachToCurrentThread
56   // where we register ReleaseMessageLoop with TLS and call AddRef.
57   base::ThreadLocalStorage::Slot* slot = new base::ThreadLocalStorage::Slot();
58   PluginGlobals::Get()->set_msg_loop_slot(slot);
59
60   slot->Set(this);
61
62   task_runner_ = base::ThreadTaskRunnerHandle::Get();
63 }
64
65
66 MessageLoopResource::~MessageLoopResource() {
67 }
68
69 PPB_MessageLoop_API* MessageLoopResource::AsPPB_MessageLoop_API() {
70   return this;
71 }
72
73 int32_t MessageLoopResource::AttachToCurrentThread() {
74   if (is_main_thread_loop_) {
75     LOG(ERROR) << "Cannot attach to current thread if it is main thread loop";
76     return PP_ERROR_INPROGRESS;
77   }
78
79   PluginGlobals* globals = PluginGlobals::Get();
80
81   base::ThreadLocalStorage::Slot* slot = globals->msg_loop_slot();
82   if (!slot) {
83     slot = new base::ThreadLocalStorage::Slot(&ReleaseMessageLoop);
84     globals->set_msg_loop_slot(slot);
85   } else {
86     if (slot->Get()) {
87       LOG(ERROR) << "Message loop slot already in use";
88       return PP_ERROR_INPROGRESS;
89     }
90   }
91   // TODO(dmichael) check that the current thread can support a task executor.
92
93   // Take a ref to the MessageLoop on behalf of the TLS. Note that this is an
94   // internal ref and not a plugin ref so the plugin can't accidentally
95   // release it. This is released by ReleaseMessageLoop().
96   AddRef();
97   slot->Set(this);
98
99   single_thread_task_executor_ =
100       std::make_unique<base::SingleThreadTaskExecutor>();
101   task_runner_ = base::ThreadTaskRunnerHandle::Get();
102
103   // Post all pending work to the task executor.
104   for (auto& info : pending_tasks_) {
105     PostClosure(info.from_here, std::move(info.closure), info.delay_ms);
106   }
107   pending_tasks_.clear();
108
109   return PP_OK;
110 }
111
112 int32_t MessageLoopResource::Run() {
113   if (!IsCurrent()) {
114     LOG(ERROR) << "Run called not on current thread";
115     return PP_ERROR_WRONG_THREAD;
116   }
117   if (is_main_thread_loop_) {
118     LOG(ERROR) << "Run called on the main thread";
119     return PP_ERROR_INPROGRESS;
120   }
121
122   base::RunLoop* previous_run_loop = run_loop_;
123   base::RunLoop run_loop;
124   run_loop_ = &run_loop;
125
126   nested_invocations_++;
127   CallWhileUnlocked(base::BindOnce(&base::RunLoop::Run,
128                                    base::Unretained(run_loop_), FROM_HERE));
129   nested_invocations_--;
130
131   run_loop_ = previous_run_loop;
132
133   if (should_destroy_ && nested_invocations_ == 0) {
134     task_runner_.reset();
135     {
136       // Message Loop dtor may try to aquire lock.
137       ProxyAutoUnlock lock;
138       single_thread_task_executor_.reset();
139     }
140     destroyed_ = true;
141   }
142   return PP_OK;
143 }
144
145 int32_t MessageLoopResource::PostWork(PP_CompletionCallback callback,
146                                       int64_t delay_ms) {
147   if (!callback.func) {
148     LOG(ERROR);
149     return PP_ERROR_BADARGUMENT;
150   }
151   if (destroyed_) {
152     LOG(ERROR) << "Message loop already destroyed";
153     return PP_ERROR_FAILED;
154   }
155   PostClosure(FROM_HERE,
156               base::BindOnce(callback.func, callback.user_data,
157                              static_cast<int32_t>(PP_OK)),
158               delay_ms);
159   return PP_OK;
160 }
161
162 int32_t MessageLoopResource::PostQuit(PP_Bool should_destroy) {
163   if (is_main_thread_loop_) {
164     LOG(ERROR) << "Post Quit in main thread loop";
165     return PP_ERROR_WRONG_THREAD;
166   }
167
168   if (PP_ToBool(should_destroy))
169     should_destroy_ = true;
170
171   if (IsCurrent() && nested_invocations_ > 0) {
172     run_loop_->QuitWhenIdle();
173   } else {
174     PostClosure(FROM_HERE,
175                 base::BindOnce(&MessageLoopResource::QuitRunLoopWhenIdle,
176                                Unretained(this)),
177                 0);
178   }
179   return PP_OK;
180 }
181
182 // static
183 MessageLoopResource* MessageLoopResource::GetCurrent() {
184   PluginGlobals* globals = PluginGlobals::Get();
185   if (!globals->msg_loop_slot())
186     return NULL;
187   return reinterpret_cast<MessageLoopResource*>(
188       globals->msg_loop_slot()->Get());
189 }
190
191 void MessageLoopResource::DetachFromThread() {
192   // Note that the task executor must be destroyed on the thread it was created
193   // on.
194   task_runner_.reset();
195   single_thread_task_executor_.reset();
196
197   // Cancel out the AddRef in AttachToCurrentThread().
198   Release();
199   // DANGER: may delete this.
200 }
201
202 bool MessageLoopResource::IsCurrent() const {
203   PluginGlobals* globals = PluginGlobals::Get();
204   if (!globals->msg_loop_slot())
205     return false;  // Can't be current if there's nothing in the slot.
206   return static_cast<const void*>(globals->msg_loop_slot()->Get()) ==
207          static_cast<const void*>(this);
208 }
209
210 void MessageLoopResource::PostClosure(const base::Location& from_here,
211                                       base::OnceClosure closure,
212                                       int64_t delay_ms) {
213   if (task_runner_.get()) {
214     task_runner_->PostDelayedTask(from_here, std::move(closure),
215                                   base::Milliseconds(delay_ms));
216   } else {
217     TaskInfo info;
218     info.from_here = FROM_HERE;
219     info.closure = std::move(closure);
220     info.delay_ms = delay_ms;
221     pending_tasks_.push_back(std::move(info));
222   }
223 }
224
225 base::SingleThreadTaskRunner* MessageLoopResource::GetTaskRunner() {
226   return task_runner_.get();
227 }
228
229 bool MessageLoopResource::CurrentlyHandlingBlockingMessage() {
230   return currently_handling_blocking_message_;
231 }
232
233 void MessageLoopResource::QuitRunLoopWhenIdle() {
234   DCHECK(IsCurrent());
235   DCHECK(run_loop_);
236   run_loop_->QuitWhenIdle();
237 }
238
239 // static
240 void MessageLoopResource::ReleaseMessageLoop(void* value) {
241   static_cast<MessageLoopResource*>(value)->DetachFromThread();
242 }
243
244 // -----------------------------------------------------------------------------
245
246 PP_Resource Create(PP_Instance instance) {
247   ProxyAutoLock lock;
248   // Validate the instance.
249   PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
250   if (!dispatcher)
251     return 0;
252   return (new MessageLoopResource(instance))->GetReference();
253 }
254
255 PP_Resource GetForMainThread() {
256   ProxyAutoLock lock;
257   return PluginGlobals::Get()->loop_for_main_thread()->GetReference();
258 }
259
260 PP_Resource GetCurrent() {
261   ProxyAutoLock lock;
262   Resource* resource = MessageLoopResource::GetCurrent();
263   if (resource)
264     return resource->GetReference();
265   return 0;
266 }
267
268 int32_t AttachToCurrentThread(PP_Resource message_loop) {
269   EnterMessageLoop enter(message_loop, true);
270   if (enter.succeeded())
271     return enter.object()->AttachToCurrentThread();
272   LOG(ERROR);
273   return PP_ERROR_BADRESOURCE;
274 }
275
276 int32_t Run(PP_Resource message_loop) {
277   EnterMessageLoop enter(message_loop, true);
278   if (enter.succeeded())
279     return enter.object()->Run();
280   LOG(ERROR) << "Cannot enter message loop";
281   return PP_ERROR_BADRESOURCE;
282 }
283
284 int32_t PostWork(PP_Resource message_loop,
285                  PP_CompletionCallback callback,
286                  int64_t delay_ms) {
287   EnterMessageLoop enter(message_loop, true);
288   if (enter.succeeded())
289     return enter.object()->PostWork(callback, delay_ms);
290   LOG(ERROR) << "Cannot enter message loop";
291   return PP_ERROR_BADRESOURCE;
292 }
293
294 int32_t PostQuit(PP_Resource message_loop, PP_Bool should_destroy) {
295   EnterMessageLoop enter(message_loop, true);
296   if (enter.succeeded())
297     return enter.object()->PostQuit(should_destroy);
298   LOG(ERROR) << "Cannot enter message loop";
299   return PP_ERROR_BADRESOURCE;
300 }
301
302 const PPB_MessageLoop_1_0 ppb_message_loop_interface = {
303   &Create,
304   &GetForMainThread,
305   &GetCurrent,
306   &AttachToCurrentThread,
307   &Run,
308   &PostWork,
309   &PostQuit
310 };
311
312 PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher)
313     : InterfaceProxy(dispatcher) {
314 }
315
316 PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() {
317 }
318
319 // static
320 const PPB_MessageLoop_1_0* PPB_MessageLoop_Proxy::GetInterface() {
321   return &ppb_message_loop_interface;
322 }
323
324 }  // namespace proxy
325 }  // namespace ppapi