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

Side by Side Diff: ppapi/proxy/ppb_message_loop_proxy.cc

Issue 10790078: PPAPI: Make PPB_MessageLoop_Dev::GetForMainThread work (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: review comments Created 8 years, 3 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/ppb_message_loop_proxy.h ('k') | ppapi/shared_impl/resource.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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_message_loop_proxy.h" 5 #include "ppapi/proxy/ppb_message_loop_proxy.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/message_loop_proxy.h"
12 #include "ppapi/c/dev/ppb_message_loop_dev.h" 13 #include "ppapi/c/dev/ppb_message_loop_dev.h"
13 #include "ppapi/c/pp_errors.h" 14 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/proxy/plugin_dispatcher.h" 15 #include "ppapi/proxy/plugin_dispatcher.h"
15 #include "ppapi/proxy/plugin_globals.h" 16 #include "ppapi/proxy/plugin_globals.h"
16 #include "ppapi/shared_impl/proxy_lock.h" 17 #include "ppapi/shared_impl/proxy_lock.h"
17 #include "ppapi/shared_impl/resource.h"
18 #include "ppapi/thunk/enter.h" 18 #include "ppapi/thunk/enter.h"
19 #include "ppapi/thunk/ppb_message_loop_api.h"
20 19
21 using ppapi::thunk::PPB_MessageLoop_API; 20 using ppapi::thunk::PPB_MessageLoop_API;
22 21
23 namespace ppapi { 22 namespace ppapi {
24 namespace proxy { 23 namespace proxy {
25 24
26 namespace { 25 namespace {
27
28 typedef thunk::EnterResource<PPB_MessageLoop_API> EnterMessageLoop; 26 typedef thunk::EnterResource<PPB_MessageLoop_API> EnterMessageLoop;
29 27 }
30 class MessageLoopResource : public Resource, public PPB_MessageLoop_API {
31 public:
32 MessageLoopResource(PP_Instance instance);
33 virtual ~MessageLoopResource();
34
35 // Resource overrides.
36 virtual PPB_MessageLoop_API* AsPPB_MessageLoop_API() OVERRIDE;
37
38 // PPB_MessageLoop_API implementation.
39 virtual int32_t AttachToCurrentThread() OVERRIDE;
40 virtual int32_t Run() OVERRIDE;
41 virtual int32_t PostWork(PP_CompletionCallback callback,
42 int64_t delay_ms) OVERRIDE;
43 virtual int32_t PostQuit(PP_Bool should_destroy) OVERRIDE;
44
45 void DetachFromThread();
46
47 private:
48 struct TaskInfo {
49 tracked_objects::Location from_here;
50 base::Closure closure;
51 int64 delay_ms;
52 };
53
54 // Returns true if the object is associated with the current thread.
55 bool IsCurrent() const;
56
57 // Handles posting to the message loop if there is one, or the pending queue
58 // if there isn't.
59 // NOTE: The given closure will be run *WITHOUT* acquiring the Proxy lock.
60 // This only makes sense for user code and completely thread-safe
61 // proxy operations (e.g., MessageLoop::QuitClosure).
62 void PostClosure(const tracked_objects::Location& from_here,
63 const base::Closure& closure,
64 int64 delay_ms);
65
66 // TLS destructor function.
67 static void ReleaseMessageLoop(void* value);
68
69 // Created when we attach to the current thread, since MessageLoop assumes
70 // that it's created on the thread it will run on.
71 scoped_ptr<MessageLoop> loop_;
72
73 // Number of invocations of Run currently on the stack.
74 int nested_invocations_;
75
76 // Set to true when the message loop is destroyed to prevent forther
77 // posting of work.
78 bool destroyed_;
79
80 // Set to true if all message loop invocations should exit and that the
81 // loop should be destroyed once it reaches the outermost Run invocation.
82 bool should_destroy_;
83
84 // Since we allow tasks to be posted before the message loop is actually
85 // created (when it's associated with a thread), we keep tasks posted here
86 // until that happens. Once the loop_ is created, this is unused.
87 std::vector<TaskInfo> pending_tasks_;
88
89 DISALLOW_COPY_AND_ASSIGN(MessageLoopResource);
90 };
91 28
92 MessageLoopResource::MessageLoopResource(PP_Instance instance) 29 MessageLoopResource::MessageLoopResource(PP_Instance instance)
93 : Resource(OBJECT_IS_PROXY, instance), 30 : Resource(OBJECT_IS_PROXY, instance),
94 nested_invocations_(0), 31 nested_invocations_(0),
95 destroyed_(false), 32 destroyed_(false),
96 should_destroy_(false) { 33 should_destroy_(false),
34 is_main_thread_loop_(false) {
97 } 35 }
98 36
37 MessageLoopResource::MessageLoopResource(ForMainThread)
38 : Resource(Resource::Untracked()),
39 nested_invocations_(0),
40 destroyed_(false),
41 should_destroy_(false),
42 is_main_thread_loop_(true) {
43 // We attach the main thread immediately. We can't use AttachToCurrentThread,
44 // because the MessageLoop already exists.
45
46 // This must be called only once, so the slot must be empty.
47 CHECK(!PluginGlobals::Get()->msg_loop_slot());
48 base::ThreadLocalStorage::Slot* slot =
49 new base::ThreadLocalStorage::Slot(&ReleaseMessageLoop);
50 PluginGlobals::Get()->set_msg_loop_slot(slot);
51
52 // Take a ref to the MessageLoop on behalf of the TLS. Note that this is an
53 // internal ref and not a plugin ref so the plugin can't accidentally
54 // release it. This is released by ReleaseMessageLoop().
55 AddRef();
56 slot->Set(this);
57
58 loop_proxy_ = base::MessageLoopProxy::current();
59 }
60
61
99 MessageLoopResource::~MessageLoopResource() { 62 MessageLoopResource::~MessageLoopResource() {
100 } 63 }
101 64
102 PPB_MessageLoop_API* MessageLoopResource::AsPPB_MessageLoop_API() { 65 PPB_MessageLoop_API* MessageLoopResource::AsPPB_MessageLoop_API() {
103 return this; 66 return this;
104 } 67 }
105 68
106 int32_t MessageLoopResource::AttachToCurrentThread() { 69 int32_t MessageLoopResource::AttachToCurrentThread() {
70 if (is_main_thread_loop_)
71 return PP_ERROR_INPROGRESS;
72
107 PluginGlobals* globals = PluginGlobals::Get(); 73 PluginGlobals* globals = PluginGlobals::Get();
108 74
109 base::ThreadLocalStorage::Slot* slot = globals->msg_loop_slot(); 75 base::ThreadLocalStorage::Slot* slot = globals->msg_loop_slot();
110 if (!slot) { 76 if (!slot) {
111 slot = new base::ThreadLocalStorage::Slot(&ReleaseMessageLoop); 77 slot = new base::ThreadLocalStorage::Slot(&ReleaseMessageLoop);
112 globals->set_msg_loop_slot(slot); 78 globals->set_msg_loop_slot(slot);
113 } else { 79 } else {
114 if (slot->Get()) 80 if (slot->Get())
115 return PP_ERROR_INPROGRESS; 81 return PP_ERROR_INPROGRESS;
116 } 82 }
117 // TODO(brettw) check that the current thread can support a message loop. 83 // TODO(brettw) check that the current thread can support a message loop.
118 84
119 // Take a ref to the MessageLoop on behalf of the TLS. Note that this is an 85 // Take a ref to the MessageLoop on behalf of the TLS. Note that this is an
120 // internal ref and not a plugin ref so the plugin can't accidentally 86 // internal ref and not a plugin ref so the plugin can't accidentally
121 // release it. This is released by ReleaseMessageLoop(). 87 // release it. This is released by ReleaseMessageLoop().
122 AddRef(); 88 AddRef();
123 slot->Set(this); 89 slot->Set(this);
124 90
125 loop_.reset(new MessageLoop(MessageLoop::TYPE_DEFAULT)); 91 loop_.reset(new MessageLoop(MessageLoop::TYPE_DEFAULT));
92 loop_proxy_ = base::MessageLoopProxy::current();
126 93
127 // Post all pending work to the message loop. 94 // Post all pending work to the message loop.
128 for (size_t i = 0; i < pending_tasks_.size(); i++) { 95 for (size_t i = 0; i < pending_tasks_.size(); i++) {
129 const TaskInfo& info = pending_tasks_[i]; 96 const TaskInfo& info = pending_tasks_[i];
130 PostClosure(info.from_here, info.closure, info.delay_ms); 97 PostClosure(info.from_here, info.closure, info.delay_ms);
131 } 98 }
132 pending_tasks_.clear(); 99 pending_tasks_.clear();
133 100
134 return PP_OK; 101 return PP_OK;
135 } 102 }
136 103
137 int32_t MessageLoopResource::Run() { 104 int32_t MessageLoopResource::Run() {
138 if (!IsCurrent()) 105 if (!IsCurrent())
139 return PP_ERROR_WRONG_THREAD; 106 return PP_ERROR_WRONG_THREAD;
140 // TODO(brettw) prevent this from happening on the main thread & return 107 if (is_main_thread_loop_)
141 // PP_ERROR_BLOCKS_MAIN_THREAD. Maybe have a special constructor for that 108 return PP_ERROR_INPROGRESS;
142 // one?
143 109
144 nested_invocations_++; 110 nested_invocations_++;
145 CallWhileUnlocked(base::Bind(&MessageLoop::Run, 111 CallWhileUnlocked(base::Bind(&MessageLoop::Run,
146 base::Unretained(loop_.get()))); 112 base::Unretained(loop_.get())));
147 nested_invocations_--; 113 nested_invocations_--;
148 114
149 if (should_destroy_ && nested_invocations_ == 0) { 115 if (should_destroy_ && nested_invocations_ == 0) {
116 loop_proxy_ = NULL;
150 loop_.reset(); 117 loop_.reset();
151 destroyed_ = true; 118 destroyed_ = true;
152 } 119 }
153 return PP_OK; 120 return PP_OK;
154 } 121 }
155 122
156 int32_t MessageLoopResource::PostWork(PP_CompletionCallback callback, 123 int32_t MessageLoopResource::PostWork(PP_CompletionCallback callback,
157 int64_t delay_ms) { 124 int64_t delay_ms) {
158 if (!callback.func) 125 if (!callback.func)
159 return PP_ERROR_BADARGUMENT; 126 return PP_ERROR_BADARGUMENT;
160 if (destroyed_) 127 if (destroyed_)
161 return PP_ERROR_FAILED; 128 return PP_ERROR_FAILED;
162 PostClosure(FROM_HERE, 129 PostClosure(FROM_HERE,
163 base::Bind(callback.func, callback.user_data, 130 base::Bind(callback.func, callback.user_data,
164 static_cast<int32_t>(PP_OK)), 131 static_cast<int32_t>(PP_OK)),
165 delay_ms); 132 delay_ms);
166 return PP_OK; 133 return PP_OK;
167 } 134 }
168 135
169 int32_t MessageLoopResource::PostQuit(PP_Bool should_destroy) { 136 int32_t MessageLoopResource::PostQuit(PP_Bool should_destroy) {
137 if (is_main_thread_loop_)
138 return PP_ERROR_WRONG_THREAD;
139
170 if (PP_ToBool(should_destroy)) 140 if (PP_ToBool(should_destroy))
171 should_destroy_ = true; 141 should_destroy_ = true;
172 142
173 if (IsCurrent()) 143 if (IsCurrent())
174 loop_->Quit(); 144 loop_->Quit();
175 else 145 else
176 PostClosure(FROM_HERE, MessageLoop::QuitClosure(), 0); 146 PostClosure(FROM_HERE, MessageLoop::QuitClosure(), 0);
177 return PP_OK; 147 return PP_OK;
178 } 148 }
179 149
180 void MessageLoopResource::DetachFromThread() { 150 void MessageLoopResource::DetachFromThread() {
151 // Never detach the main thread from its loop resource. Other plugin instances
152 // might need it.
153 if (is_main_thread_loop_)
154 return;
155
181 // Note that the message loop must be destroyed on the thread is was created 156 // Note that the message loop must be destroyed on the thread is was created
182 // on. 157 // on.
158 loop_proxy_ = NULL;
183 loop_.reset(); 159 loop_.reset();
184 160
185 // Cancel out the AddRef in AttachToCurrentThread(). 161 // Cancel out the AddRef in AttachToCurrentThread().
186 Release(); 162 Release();
187 // DANGER: may delete this. 163 // DANGER: may delete this.
188 } 164 }
189 165
190 bool MessageLoopResource::IsCurrent() const { 166 bool MessageLoopResource::IsCurrent() const {
191 PluginGlobals* globals = PluginGlobals::Get(); 167 PluginGlobals* globals = PluginGlobals::Get();
192 if (!globals->msg_loop_slot()) 168 if (!globals->msg_loop_slot())
193 return false; // Can't be current if there's nothing in the slot. 169 return false; // Can't be current if there's nothing in the slot.
194 return static_cast<const void*>(globals->msg_loop_slot()->Get()) == 170 return static_cast<const void*>(globals->msg_loop_slot()->Get()) ==
195 static_cast<const void*>(this); 171 static_cast<const void*>(this);
196 } 172 }
197 173
198 void MessageLoopResource::PostClosure( 174 void MessageLoopResource::PostClosure(
199 const tracked_objects::Location& from_here, 175 const tracked_objects::Location& from_here,
200 const base::Closure& closure, 176 const base::Closure& closure,
201 int64 delay_ms) { 177 int64 delay_ms) {
202 if (loop_.get()) { 178 if (loop_proxy_) {
203 loop_->PostDelayedTask(from_here, 179 loop_proxy_->PostDelayedTask(from_here,
204 closure, 180 closure,
205 base::TimeDelta::FromMilliseconds(delay_ms)); 181 base::TimeDelta::FromMilliseconds(delay_ms));
206 } else { 182 } else {
207 TaskInfo info; 183 TaskInfo info;
208 info.from_here = FROM_HERE; 184 info.from_here = FROM_HERE;
209 info.closure = closure; 185 info.closure = closure;
210 info.delay_ms = delay_ms; 186 info.delay_ms = delay_ms;
211 pending_tasks_.push_back(info); 187 pending_tasks_.push_back(info);
212 } 188 }
213 } 189 }
214 190
215 // static 191 // static
216 void MessageLoopResource::ReleaseMessageLoop(void* value) { 192 void MessageLoopResource::ReleaseMessageLoop(void* value) {
217 static_cast<MessageLoopResource*>(value)->DetachFromThread(); 193 static_cast<MessageLoopResource*>(value)->DetachFromThread();
218 } 194 }
219 195
220 // ----------------------------------------------------------------------------- 196 // -----------------------------------------------------------------------------
221 197
222 PP_Resource Create(PP_Instance instance) { 198 PP_Resource Create(PP_Instance instance) {
223 // Validate the instance. 199 // Validate the instance.
224 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 200 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
225 if (!dispatcher) 201 if (!dispatcher)
226 return 0; 202 return 0;
227 return (new MessageLoopResource(instance))->GetReference(); 203 return (new MessageLoopResource(instance))->GetReference();
228 } 204 }
229 205
230 PP_Resource GetForMainThread() { 206 PP_Resource GetForMainThread() {
231 // TODO(brettw). 207 return PluginGlobals::Get()->loop_for_main_thread()->GetReference();
232 return 0;
233 } 208 }
234 209
235 PP_Resource GetCurrent() { 210 PP_Resource GetCurrent() {
236 PluginGlobals* globals = PluginGlobals::Get(); 211 PluginGlobals* globals = PluginGlobals::Get();
237 if (!globals->msg_loop_slot()) 212 if (!globals->msg_loop_slot())
238 return 0; 213 return 0;
239 MessageLoopResource* loop = reinterpret_cast<MessageLoopResource*>( 214 MessageLoopResource* loop = reinterpret_cast<MessageLoopResource*>(
240 globals->msg_loop_slot()->Get()); 215 globals->msg_loop_slot()->Get());
241 return loop->GetReference(); 216 return loop->GetReference();
242 } 217 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 const PPB_MessageLoop_Dev_0_1 ppb_message_loop_interface = { 249 const PPB_MessageLoop_Dev_0_1 ppb_message_loop_interface = {
275 &Create, 250 &Create,
276 &GetForMainThread, 251 &GetForMainThread,
277 &GetCurrent, 252 &GetCurrent,
278 &AttachToCurrentThread, 253 &AttachToCurrentThread,
279 &Run, 254 &Run,
280 &PostWork, 255 &PostWork,
281 &PostQuit 256 &PostQuit
282 }; 257 };
283 258
284 } // namespace
285
286 PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher) 259 PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher)
287 : InterfaceProxy(dispatcher) { 260 : InterfaceProxy(dispatcher) {
288 } 261 }
289 262
290 PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() { 263 PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() {
291 } 264 }
292 265
293 // static 266 // static
294 const PPB_MessageLoop_Dev_0_1* PPB_MessageLoop_Proxy::GetInterface() { 267 const PPB_MessageLoop_Dev_0_1* PPB_MessageLoop_Proxy::GetInterface() {
295 return &ppb_message_loop_interface; 268 return &ppb_message_loop_interface;
296 } 269 }
297 270
298 } // namespace proxy 271 } // namespace proxy
299 } // namespace ppapi 272 } // namespace ppapi
OLDNEW
« no previous file with comments | « ppapi/proxy/ppb_message_loop_proxy.h ('k') | ppapi/shared_impl/resource.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698