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

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
« 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
(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);
bbudge 2012/01/23 18:15:12 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;
bbudge 2012/01/23 18:15:12 Need to check destroyed_ here.
152 PostClosure(FROM_HERE,
153 base::Bind(callback.func, callback.user_data,
154 static_cast<int32_t>(PP_OK)),
155 delay_ms);
156 return PP_OK;
157 }
158
159 int32_t MessageLoopResource::PostQuit(PP_Bool should_destroy) {
160 if (PP_ToBool(should_destroy))
161 should_destroy_ = true;
162
163 if (IsCurrent())
164 loop_->Quit();
165 else
166 PostClosure(FROM_HERE, MessageLoop::QuitClosure(), 0);
167 return PP_OK;
168 }
169
170 void MessageLoopResource::DetachFromThread() {
171 // Note that the message loop must be destroyed on the thread is was created.
172 loop_.reset();
173
174 // Cancel out the AddRef in AttachToCurrentThread().
175 Release();
176 // DANGER: may delete this.
177 }
178
179 bool MessageLoopResource::IsCurrent() const {
180 if (!tls_slot.initialized())
181 return false; // Can't be current if there's nothing in the slot.
182 return static_cast<const void*>(tls_slot.Get()) ==
183 static_cast<const void*>(this);
184 }
185
186 void MessageLoopResource::PostClosure(
187 const tracked_objects::Location& from_here,
188 const base::Closure& closure,
189 int64 delay_ms) {
190 if (loop_.get()) {
191 loop_->PostDelayedTask(from_here, closure, delay_ms);
192 } else {
193 TaskInfo info;
194 info.from_here = FROM_HERE;
195 info.closure = closure;
196 info.delay_ms = delay_ms;
197 pending_tasks_.push_back(info);
198 }
199 }
200
201 // static
202 void MessageLoopResource::ReleaseMessageLoop(void* value) {
203 static_cast<MessageLoopResource*>(value)->DetachFromThread();
204 }
205
206 // -----------------------------------------------------------------------------
207
208 PP_Resource Create(PP_Instance instance) {
209 // Validate the instance.
210 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
211 if (!dispatcher)
212 return 0;
213 return (new MessageLoopResource(instance))->GetReference();
214 }
215
216 PP_Resource GetForMainThread() {
217 // TODO(brettw).
218 return 0;
219 }
220
221 PP_Resource GetCurrent() {
222 if (!tls_slot.initialized())
223 return 0;
224 MessageLoopResource* loop = reinterpret_cast<MessageLoopResource*>(
225 tls_slot.Get());
226 return loop->GetReference();
227 }
228
229 int32_t AttachToCurrentThread(PP_Resource message_loop) {
230 EnterMessageLoop enter(message_loop, true);
231 if (enter.succeeded())
232 return enter.object()->AttachToCurrentThread();
233 return PP_ERROR_BADRESOURCE;
234 }
235
236 int32_t Run(PP_Resource message_loop) {
237 EnterMessageLoop enter(message_loop, true);
238 if (enter.succeeded())
239 return enter.object()->Run();
240 return PP_ERROR_BADRESOURCE;
241 }
242
243 int32_t PostWork(PP_Resource message_loop,
244 PP_CompletionCallback callback,
245 int64_t delay_ms) {
246 EnterMessageLoop enter(message_loop, true);
247 if (enter.succeeded())
248 return enter.object()->PostWork(callback, delay_ms);
249 return PP_ERROR_BADRESOURCE;
250 }
251
252 int32_t PostQuit(PP_Resource message_loop, PP_Bool should_destroy) {
253 EnterMessageLoop enter(message_loop, true);
254 if (enter.succeeded())
255 return enter.object()->PostQuit(should_destroy);
256 return PP_ERROR_BADRESOURCE;
257 }
258
259 const PPB_MessageLoop_Dev_0_1 ppb_message_loop_interface = {
260 &Create,
261 &GetForMainThread,
262 &GetCurrent,
263 &AttachToCurrentThread,
264 &Run,
265 &PostWork,
266 &PostQuit
267 };
268
269 } // namespace
270
271 PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher)
272 : InterfaceProxy(dispatcher) {
273 }
274
275 PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() {
276 }
277
278 // static
279 const PPB_MessageLoop_Dev_0_1* PPB_MessageLoop_Proxy::GetInterface() {
280 return &ppb_message_loop_interface;
281 }
282
283 } // namespace proxy
284 } // 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