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

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

Issue 9097006: First pass at implementing the MessageLoop interface. This includes a simple (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review comments Created 8 years, 11 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/compiler_specific.h"
11 #include "base/message_loop.h"
12 #include "base/threading/thread_local_storage.h"
13 #include "ppapi/c/dev/ppb_message_loop_dev.h"
14 #include "ppapi/c/pp_errors.h"
15 #include "ppapi/proxy/plugin_dispatcher.h"
16 #include "ppapi/shared_impl/resource.h"
17 #include "ppapi/thunk/enter.h"
18 #include "ppapi/thunk/ppb_message_loop_api.h"
19
20 using ppapi::thunk::PPB_MessageLoop_API;
21
22 namespace ppapi {
23 namespace proxy {
24
25 namespace {
26
27 typedef thunk::EnterResource<PPB_MessageLoop_API> EnterMessageLoop;
28
29 static base::ThreadLocalStorage::Slot tls_slot(base::LINKER_INITIALIZED);
30
31 class MessageLoopResource : public Resource, public PPB_MessageLoop_API {
32 public:
33 MessageLoopResource(PP_Instance instance);
34 virtual ~MessageLoopResource();
35
36 // Resource overrides.
37 virtual PPB_MessageLoop_API* AsPPB_MessageLoop_API() OVERRIDE;
38
39 // PPB_MessageLoop_API implementation.
40 virtual int32_t AttachToCurrentThread() OVERRIDE;
41 virtual int32_t Run() OVERRIDE;
42 virtual int32_t PostWork(PP_CompletionCallback callback,
43 int64_t delay_ms) OVERRIDE;
44 virtual int32_t PostQuit(PP_Bool should_destroy) OVERRIDE;
45
46 void DetachFromThread();
47
48 private:
49 struct TaskInfo {
50 tracked_objects::Location from_here;
51 base::Closure closure;
52 int64 delay_ms;
53 };
54
55 // Returns true if the object is associated with the current thread.
56 bool IsCurrent() const;
57
58 // Handles posting to the message loop if there is one, or the pending queue
59 // if there isn't.
60 void PostClosure(const tracked_objects::Location& from_here,
61 const base::Closure& closure,
62 int64 delay_ms);
63
64 // TLS destructor function.
65 static void ReleaseMessageLoop(void* value);
66
67 // Created when we attach to the current thread, since MessageLoop assumes
68 // that it's created on the thread it will run on.
69 scoped_ptr<MessageLoop> loop_;
70
71 // Number of invocations of Run currently on the stack.
72 int nested_invocations_;
73
74 // Set to true when the message loop is destroyed to prevent forther
75 // posting of work.
76 bool destroyed_;
77
78 // Set to true if all message loop invocations should exit and that the
79 // loop should be destroyed once it reaches the outermost Run invocation.
80 bool should_destroy_;
81
82 // Since we allow tasks to be posted before the message loop is actually
83 // created (when it's associated with a thread), we keep tasks posted here
84 // until that happens. Once the loop_ is created, this is unused.
85 std::vector<TaskInfo> pending_tasks_;
86
87 DISALLOW_COPY_AND_ASSIGN(MessageLoopResource);
88 };
89
90 MessageLoopResource::MessageLoopResource(PP_Instance instance)
91 : Resource(HostResource::MakeInstanceOnly(instance)),
92 nested_invocations_(0),
93 destroyed_(false),
94 should_destroy_(false) {
95 }
96
97 MessageLoopResource::~MessageLoopResource() {
98 }
99
100 PPB_MessageLoop_API* MessageLoopResource::AsPPB_MessageLoop_API() {
101 return this;
102 }
103
104 int32_t MessageLoopResource::AttachToCurrentThread() {
105 if (tls_slot.initialized())
106 return PP_ERROR_INPROGRESS;
107 // TODO(brettw) check that the current thread can support a message loop.
108
109 // Take a ref to the MessageLoop on behalf of the TLS. Note that this is an
110 // internal ref and not a plugin ref so the plugin can't accidentally
111 // release it. This is released by ReleaseMessageLoop().
112 AddRef();
113 tls_slot.Initialize(&ReleaseMessageLoop);
114 tls_slot.Set(this);
115
116 loop_.reset(new MessageLoop(MessageLoop::TYPE_DEFAULT));
117
118 // Post all pending work to the message loop.
119 for (size_t i = 0; i < pending_tasks_.size(); i++) {
120 const TaskInfo& info = pending_tasks_[i];
121 PostClosure(info.from_here, info.closure, info.delay_ms);
122 }
123 pending_tasks_.clear();
124
125 return PP_OK;
126 }
127
128 int32_t MessageLoopResource::Run() {
129 if (!IsCurrent())
130 return PP_ERROR_WRONG_THREAD;
131 // TODO(brettw) prevent this from happening on the main thread & return
132 // PP_ERROR_BLOCKS_MAIN_THREAD. Maybe have a special constructor for that
133 // one?
134
135 // TODO(brettw) figure out how to release the lock. Can't run the message
136 // loop while holding the lock.
137 nested_invocations_++;
138 loop_->Run();
139 nested_invocations_--;
140
141 if (should_destroy_ && nested_invocations_ == 0) {
142 loop_.reset();
143 destroyed_ = true;
144 }
145 return PP_OK;
146 }
147
148 int32_t MessageLoopResource::PostWork(PP_CompletionCallback callback,
149 int64_t delay_ms) {
150 if (!callback.func)
151 return PP_ERROR_BADARGUMENT;
152 if (destroyed_)
153 return PP_ERROR_FAILED;
154 PostClosure(FROM_HERE,
155 base::Bind(callback.func, callback.user_data,
156 static_cast<int32_t>(PP_OK)),
157 delay_ms);
158 return PP_OK;
159 }
160
161 int32_t MessageLoopResource::PostQuit(PP_Bool should_destroy) {
162 if (PP_ToBool(should_destroy))
163 should_destroy_ = true;
164
165 if (IsCurrent())
166 loop_->Quit();
167 else
168 PostClosure(FROM_HERE, MessageLoop::QuitClosure(), 0);
169 return PP_OK;
170 }
171
172 void MessageLoopResource::DetachFromThread() {
173 // Note that the message loop must be destroyed on the thread is was created.
bbudge 2012/01/25 00:35:26 is -> it, created -> created on
174 loop_.reset();
175
176 // Cancel out the AddRef in AttachToCurrentThread().
177 Release();
178 // DANGER: may delete this.
179 }
180
181 bool MessageLoopResource::IsCurrent() const {
182 if (!tls_slot.initialized())
183 return false; // Can't be current if there's nothing in the slot.
184 return static_cast<const void*>(tls_slot.Get()) ==
185 static_cast<const void*>(this);
186 }
187
188 void MessageLoopResource::PostClosure(
189 const tracked_objects::Location& from_here,
190 const base::Closure& closure,
191 int64 delay_ms) {
192 if (loop_.get()) {
193 loop_->PostDelayedTask(from_here, closure, delay_ms);
194 } else {
195 TaskInfo info;
196 info.from_here = FROM_HERE;
197 info.closure = closure;
198 info.delay_ms = delay_ms;
199 pending_tasks_.push_back(info);
200 }
201 }
202
203 // static
204 void MessageLoopResource::ReleaseMessageLoop(void* value) {
205 static_cast<MessageLoopResource*>(value)->DetachFromThread();
206 }
207
208 // -----------------------------------------------------------------------------
209
210 PP_Resource Create(PP_Instance instance) {
211 // Validate the instance.
212 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
213 if (!dispatcher)
214 return 0;
215 return (new MessageLoopResource(instance))->GetReference();
216 }
217
218 PP_Resource GetForMainThread() {
219 // TODO(brettw).
220 return 0;
221 }
222
223 PP_Resource GetCurrent() {
224 if (!tls_slot.initialized())
225 return 0;
226 MessageLoopResource* loop = reinterpret_cast<MessageLoopResource*>(
227 tls_slot.Get());
228 return loop->GetReference();
229 }
230
231 int32_t AttachToCurrentThread(PP_Resource message_loop) {
232 EnterMessageLoop enter(message_loop, true);
233 if (enter.succeeded())
234 return enter.object()->AttachToCurrentThread();
235 return PP_ERROR_BADRESOURCE;
236 }
237
238 int32_t Run(PP_Resource message_loop) {
239 EnterMessageLoop enter(message_loop, true);
240 if (enter.succeeded())
241 return enter.object()->Run();
242 return PP_ERROR_BADRESOURCE;
243 }
244
245 int32_t PostWork(PP_Resource message_loop,
246 PP_CompletionCallback callback,
247 int64_t delay_ms) {
248 EnterMessageLoop enter(message_loop, true);
249 if (enter.succeeded())
250 return enter.object()->PostWork(callback, delay_ms);
251 return PP_ERROR_BADRESOURCE;
252 }
253
254 int32_t PostQuit(PP_Resource message_loop, PP_Bool should_destroy) {
255 EnterMessageLoop enter(message_loop, true);
256 if (enter.succeeded())
257 return enter.object()->PostQuit(should_destroy);
258 return PP_ERROR_BADRESOURCE;
259 }
260
261 const PPB_MessageLoop_Dev_0_1 ppb_message_loop_interface = {
262 &Create,
263 &GetForMainThread,
264 &GetCurrent,
265 &AttachToCurrentThread,
266 &Run,
267 &PostWork,
268 &PostQuit
269 };
270
271 } // namespace
272
273 PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher)
274 : InterfaceProxy(dispatcher) {
275 }
276
277 PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() {
278 }
279
280 // static
281 const PPB_MessageLoop_Dev_0_1* PPB_MessageLoop_Proxy::GetInterface() {
282 return &ppb_message_loop_interface;
283 }
284
285 } // namespace proxy
286 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698