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

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

Issue 9290040: Revert 119198 - First pass at implementing the MessageLoop interface. This includes a simple (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: 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) 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
174 // on.
175 loop_.reset();
176
177 // Cancel out the AddRef in AttachToCurrentThread().
178 Release();
179 // DANGER: may delete this.
180 }
181
182 bool MessageLoopResource::IsCurrent() const {
183 if (!tls_slot.initialized())
184 return false; // Can't be current if there's nothing in the slot.
185 return static_cast<const void*>(tls_slot.Get()) ==
186 static_cast<const void*>(this);
187 }
188
189 void MessageLoopResource::PostClosure(
190 const tracked_objects::Location& from_here,
191 const base::Closure& closure,
192 int64 delay_ms) {
193 if (loop_.get()) {
194 loop_->PostDelayedTask(from_here, closure, delay_ms);
195 } else {
196 TaskInfo info;
197 info.from_here = FROM_HERE;
198 info.closure = closure;
199 info.delay_ms = delay_ms;
200 pending_tasks_.push_back(info);
201 }
202 }
203
204 // static
205 void MessageLoopResource::ReleaseMessageLoop(void* value) {
206 static_cast<MessageLoopResource*>(value)->DetachFromThread();
207 }
208
209 // -----------------------------------------------------------------------------
210
211 PP_Resource Create(PP_Instance instance) {
212 // Validate the instance.
213 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
214 if (!dispatcher)
215 return 0;
216 return (new MessageLoopResource(instance))->GetReference();
217 }
218
219 PP_Resource GetForMainThread() {
220 // TODO(brettw).
221 return 0;
222 }
223
224 PP_Resource GetCurrent() {
225 if (!tls_slot.initialized())
226 return 0;
227 MessageLoopResource* loop = reinterpret_cast<MessageLoopResource*>(
228 tls_slot.Get());
229 return loop->GetReference();
230 }
231
232 int32_t AttachToCurrentThread(PP_Resource message_loop) {
233 EnterMessageLoop enter(message_loop, true);
234 if (enter.succeeded())
235 return enter.object()->AttachToCurrentThread();
236 return PP_ERROR_BADRESOURCE;
237 }
238
239 int32_t Run(PP_Resource message_loop) {
240 EnterMessageLoop enter(message_loop, true);
241 if (enter.succeeded())
242 return enter.object()->Run();
243 return PP_ERROR_BADRESOURCE;
244 }
245
246 int32_t PostWork(PP_Resource message_loop,
247 PP_CompletionCallback callback,
248 int64_t delay_ms) {
249 EnterMessageLoop enter(message_loop, true);
250 if (enter.succeeded())
251 return enter.object()->PostWork(callback, delay_ms);
252 return PP_ERROR_BADRESOURCE;
253 }
254
255 int32_t PostQuit(PP_Resource message_loop, PP_Bool should_destroy) {
256 EnterMessageLoop enter(message_loop, true);
257 if (enter.succeeded())
258 return enter.object()->PostQuit(should_destroy);
259 return PP_ERROR_BADRESOURCE;
260 }
261
262 const PPB_MessageLoop_Dev_0_1 ppb_message_loop_interface = {
263 &Create,
264 &GetForMainThread,
265 &GetCurrent,
266 &AttachToCurrentThread,
267 &Run,
268 &PostWork,
269 &PostQuit
270 };
271
272 } // namespace
273
274 PPB_MessageLoop_Proxy::PPB_MessageLoop_Proxy(Dispatcher* dispatcher)
275 : InterfaceProxy(dispatcher) {
276 }
277
278 PPB_MessageLoop_Proxy::~PPB_MessageLoop_Proxy() {
279 }
280
281 // static
282 const PPB_MessageLoop_Dev_0_1* PPB_MessageLoop_Proxy::GetInterface() {
283 return &ppb_message_loop_interface;
284 }
285
286 } // namespace proxy
287 } // 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