[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 1 | // Copyright (c) 2012 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/ppb_message_loop_proxy.h" |
| 6 | |
avi | e029c413 | 2015-12-23 06:45:22 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
Peter Boström | fb60ea0 | 2021-04-05 21:06:12 | [diff] [blame] | 9 | #include <memory> |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 10 | #include <vector> |
| 11 | |
| 12 | #include "base/bind.h" |
danakj | db9ae794 | 2020-11-11 16:01:35 | [diff] [blame] | 13 | #include "base/callback_helpers.h" |
Hans Wennborg | 708fa82 | 2020-04-27 17:23:15 | [diff] [blame] | 14 | #include "base/check.h" |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 15 | #include "base/compiler_specific.h" |
gab | b19326e | 2016-05-11 18:10:31 | [diff] [blame] | 16 | #include "base/threading/thread_task_runner_handle.h" |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 17 | #include "ppapi/c/pp_errors.h" |
[email protected] | d4ab9471 | 2012-11-15 21:01:23 | [diff] [blame] | 18 | #include "ppapi/c/ppb_message_loop.h" |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 19 | #include "ppapi/proxy/plugin_dispatcher.h" |
[email protected] | 9d11bb46 | 2012-02-05 03:07:39 | [diff] [blame] | 20 | #include "ppapi/proxy/plugin_globals.h" |
[email protected] | aed9653 | 2012-06-23 14:27:42 | [diff] [blame] | 21 | #include "ppapi/shared_impl/proxy_lock.h" |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 22 | #include "ppapi/thunk/enter.h" |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 23 | |
| 24 | using ppapi::thunk::PPB_MessageLoop_API; |
| 25 | |
| 26 | namespace ppapi { |
| 27 | namespace proxy { |
| 28 | |
| 29 | namespace { |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 30 | typedef thunk::EnterResource<PPB_MessageLoop_API> EnterMessageLoop; |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 31 | } |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 32 | |
| 33 | MessageLoopResource::MessageLoopResource(PP_Instance instance) |
[email protected] | 77c3417 | 2012-11-08 18:55:16 | [diff] [blame] | 34 | : MessageLoopShared(instance), |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 35 | nested_invocations_(0), |
| 36 | destroyed_(false), |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 37 | should_destroy_(false), |
dmichael | 44b96754 | 2014-09-24 15:41:14 | [diff] [blame] | 38 | is_main_thread_loop_(false), |
| 39 | currently_handling_blocking_message_(false) { |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 40 | } |
| 41 | |
[email protected] | 77c3417 | 2012-11-08 18:55:16 | [diff] [blame] | 42 | MessageLoopResource::MessageLoopResource(ForMainThread for_main_thread) |
| 43 | : MessageLoopShared(for_main_thread), |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 44 | nested_invocations_(0), |
| 45 | destroyed_(false), |
| 46 | should_destroy_(false), |
dmichael | 44b96754 | 2014-09-24 15:41:14 | [diff] [blame] | 47 | is_main_thread_loop_(true), |
| 48 | currently_handling_blocking_message_(false) { |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 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()); |
[email protected] | f137d06c | 2013-01-03 12:10:00 | [diff] [blame] | 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(); |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 58 | PluginGlobals::Get()->set_msg_loop_slot(slot); |
| 59 | |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 60 | slot->Set(this); |
| 61 | |
skyostil | 23490d4 | 2015-06-12 12:54:26 | [diff] [blame] | 62 | task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 66 | MessageLoopResource::~MessageLoopResource() { |
| 67 | } |
| 68 | |
| 69 | PPB_MessageLoop_API* MessageLoopResource::AsPPB_MessageLoop_API() { |
| 70 | return this; |
| 71 | } |
| 72 | |
| 73 | int32_t MessageLoopResource::AttachToCurrentThread() { |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 74 | if (is_main_thread_loop_) |
| 75 | return PP_ERROR_INPROGRESS; |
| 76 | |
[email protected] | 9d11bb46 | 2012-02-05 03:07:39 | [diff] [blame] | 77 | PluginGlobals* globals = PluginGlobals::Get(); |
| 78 | |
| 79 | base::ThreadLocalStorage::Slot* slot = globals->msg_loop_slot(); |
| 80 | if (!slot) { |
| 81 | slot = new base::ThreadLocalStorage::Slot(&ReleaseMessageLoop); |
| 82 | globals->set_msg_loop_slot(slot); |
| 83 | } else { |
| 84 | if (slot->Get()) |
| 85 | return PP_ERROR_INPROGRESS; |
| 86 | } |
Alex Clarke | f7fb8a8 | 2019-06-06 15:41:53 | [diff] [blame] | 87 | // TODO(dmichael) check that the current thread can support a task executor. |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 88 | |
| 89 | // Take a ref to the MessageLoop on behalf of the TLS. Note that this is an |
| 90 | // internal ref and not a plugin ref so the plugin can't accidentally |
| 91 | // release it. This is released by ReleaseMessageLoop(). |
| 92 | AddRef(); |
[email protected] | 9d11bb46 | 2012-02-05 03:07:39 | [diff] [blame] | 93 | slot->Set(this); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 94 | |
Peter Boström | fb60ea0 | 2021-04-05 21:06:12 | [diff] [blame] | 95 | single_thread_task_executor_ = |
| 96 | std::make_unique<base::SingleThreadTaskExecutor>(); |
skyostil | 23490d4 | 2015-06-12 12:54:26 | [diff] [blame] | 97 | task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 98 | |
Alex Clarke | f7fb8a8 | 2019-06-06 15:41:53 | [diff] [blame] | 99 | // Post all pending work to the task executor. |
Jan Wilken Dörrie | 1d33fc6 | 2020-01-23 10:20:47 | [diff] [blame] | 100 | for (auto& info : pending_tasks_) { |
| 101 | PostClosure(info.from_here, std::move(info.closure), info.delay_ms); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 102 | } |
| 103 | pending_tasks_.clear(); |
| 104 | |
| 105 | return PP_OK; |
| 106 | } |
| 107 | |
| 108 | int32_t MessageLoopResource::Run() { |
| 109 | if (!IsCurrent()) |
| 110 | return PP_ERROR_WRONG_THREAD; |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 111 | if (is_main_thread_loop_) |
| 112 | return PP_ERROR_INPROGRESS; |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 113 | |
fdoray | 2df4a9e | 2016-07-18 23:47:16 | [diff] [blame] | 114 | base::RunLoop* previous_run_loop = run_loop_; |
| 115 | base::RunLoop run_loop; |
| 116 | run_loop_ = &run_loop; |
| 117 | |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 118 | nested_invocations_++; |
danakj | e125e8d6 | 2021-01-21 22:06:31 | [diff] [blame] | 119 | CallWhileUnlocked(base::BindOnce(&base::RunLoop::Run, |
| 120 | base::Unretained(run_loop_), FROM_HERE)); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 121 | nested_invocations_--; |
| 122 | |
fdoray | 2df4a9e | 2016-07-18 23:47:16 | [diff] [blame] | 123 | run_loop_ = previous_run_loop; |
| 124 | |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 125 | if (should_destroy_ && nested_invocations_ == 0) { |
kylechar | 37594cb | 2019-11-15 16:41:17 | [diff] [blame] | 126 | task_runner_.reset(); |
Alex Clarke | 636e705 | 2019-05-30 10:49:37 | [diff] [blame] | 127 | single_thread_task_executor_.reset(); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 128 | destroyed_ = true; |
| 129 | } |
| 130 | return PP_OK; |
| 131 | } |
| 132 | |
| 133 | int32_t MessageLoopResource::PostWork(PP_CompletionCallback callback, |
| 134 | int64_t delay_ms) { |
| 135 | if (!callback.func) |
| 136 | return PP_ERROR_BADARGUMENT; |
| 137 | if (destroyed_) |
| 138 | return PP_ERROR_FAILED; |
| 139 | PostClosure(FROM_HERE, |
Jan Wilken Dörrie | 1564716 | 2020-04-20 10:09:58 | [diff] [blame] | 140 | base::BindOnce(callback.func, callback.user_data, |
| 141 | static_cast<int32_t>(PP_OK)), |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 142 | delay_ms); |
| 143 | return PP_OK; |
| 144 | } |
| 145 | |
| 146 | int32_t MessageLoopResource::PostQuit(PP_Bool should_destroy) { |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 147 | if (is_main_thread_loop_) |
| 148 | return PP_ERROR_WRONG_THREAD; |
| 149 | |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 150 | if (PP_ToBool(should_destroy)) |
| 151 | should_destroy_ = true; |
| 152 | |
fdoray | 2df4a9e | 2016-07-18 23:47:16 | [diff] [blame] | 153 | if (IsCurrent() && nested_invocations_ > 0) { |
| 154 | run_loop_->QuitWhenIdle(); |
| 155 | } else { |
Jan Wilken Dörrie | 1564716 | 2020-04-20 10:09:58 | [diff] [blame] | 156 | PostClosure(FROM_HERE, |
| 157 | base::BindOnce(&MessageLoopResource::QuitRunLoopWhenIdle, |
| 158 | Unretained(this)), |
fdoray | 2df4a9e | 2016-07-18 23:47:16 | [diff] [blame] | 159 | 0); |
| 160 | } |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 161 | return PP_OK; |
| 162 | } |
| 163 | |
[email protected] | 77c3417 | 2012-11-08 18:55:16 | [diff] [blame] | 164 | // static |
| 165 | MessageLoopResource* MessageLoopResource::GetCurrent() { |
| 166 | PluginGlobals* globals = PluginGlobals::Get(); |
| 167 | if (!globals->msg_loop_slot()) |
| 168 | return NULL; |
| 169 | return reinterpret_cast<MessageLoopResource*>( |
| 170 | globals->msg_loop_slot()->Get()); |
| 171 | } |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 172 | |
[email protected] | 77c3417 | 2012-11-08 18:55:16 | [diff] [blame] | 173 | void MessageLoopResource::DetachFromThread() { |
Alex Clarke | f7fb8a8 | 2019-06-06 15:41:53 | [diff] [blame] | 174 | // Note that the task executor must be destroyed on the thread it was created |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 175 | // on. |
kylechar | 37594cb | 2019-11-15 16:41:17 | [diff] [blame] | 176 | task_runner_.reset(); |
Alex Clarke | 636e705 | 2019-05-30 10:49:37 | [diff] [blame] | 177 | single_thread_task_executor_.reset(); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 178 | |
| 179 | // Cancel out the AddRef in AttachToCurrentThread(). |
| 180 | Release(); |
| 181 | // DANGER: may delete this. |
| 182 | } |
| 183 | |
| 184 | bool MessageLoopResource::IsCurrent() const { |
[email protected] | 9d11bb46 | 2012-02-05 03:07:39 | [diff] [blame] | 185 | PluginGlobals* globals = PluginGlobals::Get(); |
| 186 | if (!globals->msg_loop_slot()) |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 187 | return false; // Can't be current if there's nothing in the slot. |
[email protected] | 9d11bb46 | 2012-02-05 03:07:39 | [diff] [blame] | 188 | return static_cast<const void*>(globals->msg_loop_slot()->Get()) == |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 189 | static_cast<const void*>(this); |
| 190 | } |
| 191 | |
Brett Wilson | 9c36199 | 2017-09-12 06:05:21 | [diff] [blame] | 192 | void MessageLoopResource::PostClosure(const base::Location& from_here, |
Jan Wilken Dörrie | 1d33fc6 | 2020-01-23 10:20:47 | [diff] [blame] | 193 | base::OnceClosure closure, |
Brett Wilson | 9c36199 | 2017-09-12 06:05:21 | [diff] [blame] | 194 | int64_t delay_ms) { |
skyostil | 23490d4 | 2015-06-12 12:54:26 | [diff] [blame] | 195 | if (task_runner_.get()) { |
Jan Wilken Dörrie | 1d33fc6 | 2020-01-23 10:20:47 | [diff] [blame] | 196 | task_runner_->PostDelayedTask(from_here, std::move(closure), |
Peter Kasting | e5a38ed | 2021-10-02 03:06:35 | [diff] [blame] | 197 | base::Milliseconds(delay_ms)); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 198 | } else { |
| 199 | TaskInfo info; |
| 200 | info.from_here = FROM_HERE; |
Jan Wilken Dörrie | 1d33fc6 | 2020-01-23 10:20:47 | [diff] [blame] | 201 | info.closure = std::move(closure); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 202 | info.delay_ms = delay_ms; |
Jan Wilken Dörrie | 1d33fc6 | 2020-01-23 10:20:47 | [diff] [blame] | 203 | pending_tasks_.push_back(std::move(info)); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 204 | } |
| 205 | } |
| 206 | |
skyostil | 23490d4 | 2015-06-12 12:54:26 | [diff] [blame] | 207 | base::SingleThreadTaskRunner* MessageLoopResource::GetTaskRunner() { |
| 208 | return task_runner_.get(); |
[email protected] | 511c58e | 2013-12-12 12:25:33 | [diff] [blame] | 209 | } |
| 210 | |
dmichael | 44b96754 | 2014-09-24 15:41:14 | [diff] [blame] | 211 | bool MessageLoopResource::CurrentlyHandlingBlockingMessage() { |
| 212 | return currently_handling_blocking_message_; |
| 213 | } |
| 214 | |
fdoray | 2df4a9e | 2016-07-18 23:47:16 | [diff] [blame] | 215 | void MessageLoopResource::QuitRunLoopWhenIdle() { |
| 216 | DCHECK(IsCurrent()); |
| 217 | DCHECK(run_loop_); |
| 218 | run_loop_->QuitWhenIdle(); |
| 219 | } |
| 220 | |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 221 | // static |
| 222 | void MessageLoopResource::ReleaseMessageLoop(void* value) { |
| 223 | static_cast<MessageLoopResource*>(value)->DetachFromThread(); |
| 224 | } |
| 225 | |
| 226 | // ----------------------------------------------------------------------------- |
| 227 | |
| 228 | PP_Resource Create(PP_Instance instance) { |
[email protected] | 64cbf81 | 2013-01-26 00:52:51 | [diff] [blame] | 229 | ProxyAutoLock lock; |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 230 | // Validate the instance. |
| 231 | PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); |
| 232 | if (!dispatcher) |
| 233 | return 0; |
| 234 | return (new MessageLoopResource(instance))->GetReference(); |
| 235 | } |
| 236 | |
| 237 | PP_Resource GetForMainThread() { |
[email protected] | 64cbf81 | 2013-01-26 00:52:51 | [diff] [blame] | 238 | ProxyAutoLock lock; |
[email protected] | 6de743a | 2012-08-30 20:03:22 | [diff] [blame] | 239 | return PluginGlobals::Get()->loop_for_main_thread()->GetReference(); |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | PP_Resource GetCurrent() { |
[email protected] | 64cbf81 | 2013-01-26 00:52:51 | [diff] [blame] | 243 | ProxyAutoLock lock; |
[email protected] | 77c3417 | 2012-11-08 18:55:16 | [diff] [blame] | 244 | Resource* resource = MessageLoopResource::GetCurrent(); |
| 245 | if (resource) |
| 246 | return resource->GetReference(); |
| 247 | return 0; |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 248 | } |
| 249 | |
| 250 | int32_t AttachToCurrentThread(PP_Resource message_loop) { |
| 251 | EnterMessageLoop enter(message_loop, true); |
| 252 | if (enter.succeeded()) |
| 253 | return enter.object()->AttachToCurrentThread(); |
| 254 | return PP_ERROR_BADRESOURCE; |
| 255 | } |
| 256 | |
| 257 | int32_t Run(PP_Resource message_loop) { |
| 258 | EnterMessageLoop enter(message_loop, true); |
| 259 | if (enter.succeeded()) |
| 260 | return enter.object()->Run(); |
| 261 | return PP_ERROR_BADRESOURCE; |
| 262 | } |
| 263 | |
| 264 | int32_t PostWork(PP_Resource message_loop, |
| 265 | PP_CompletionCallback callback, |
| 266 | int64_t delay_ms) { |
| 267 | EnterMessageLoop enter(message_loop, true); |
| 268 | if (enter.succeeded()) |
| 269 | return enter.object()->PostWork(callback, delay_ms); |
| 270 | return PP_ERROR_BADRESOURCE; |
| 271 | } |
| 272 | |
| 273 | int32_t PostQuit(PP_Resource message_loop, PP_Bool should_destroy) { |
| 274 | EnterMessageLoop enter(message_loop, true); |
| 275 | if (enter.succeeded()) |
| 276 | return enter.object()->PostQuit(should_destroy); |
| 277 | return PP_ERROR_BADRESOURCE; |
| 278 | } |
| 279 | |
[email protected] | d4ab9471 | 2012-11-15 21:01:23 | [diff] [blame] | 280 | const PPB_MessageLoop_1_0 ppb_message_loop_interface = { |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 281 | &Create, |
| 282 | &GetForMainThread, |
| 283 | &GetCurrent, |
| 284 | &AttachToCurrentThread, |
| 285 | &Run, |
| 286 | &PostWork, |
| 287 | &PostQuit |
| 288 | }; |
| 289 | |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 290 | PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher) |
| 291 | : InterfaceProxy(dispatcher) { |
| 292 | } |
| 293 | |
| 294 | PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() { |
| 295 | } |
| 296 | |
| 297 | // static |
[email protected] | d4ab9471 | 2012-11-15 21:01:23 | [diff] [blame] | 298 | const PPB_MessageLoop_1_0* PPB_MessageLoop_Proxy::GetInterface() { |
[email protected] | 15b1224 | 2012-01-26 19:28:47 | [diff] [blame] | 299 | return &ppb_message_loop_interface; |
| 300 | } |
| 301 | |
| 302 | } // namespace proxy |
| 303 | } // namespace ppapi |