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

Side by Side Diff: chrome/test/data/nacl/manifest_file/pm_manifest_file_test.cc

Issue 418423002: Pepper: Stop using SRPC for irt_open_resource(). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
Mark Seaborn 2014/08/28 23:40:22 BTW, since this is a big change, it would be nice
teravest 2014/09/04 22:13:29 Done.
2 * Copyright 2014 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 //
8 // Post-message based test for simple rpc based access to name services.
9 //
10
11 #include <string>
12
13 #include <assert.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <inttypes.h>
17 #include <sys/fcntl.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <pthread.h>
21
22 #include "native_client/src/include/nacl_base.h"
23 #include "native_client/src/public/imc_syscalls.h"
24 #include "native_client/src/public/name_service.h"
25 #include "native_client/src/shared/platform/nacl_sync.h"
26 #include "native_client/src/shared/platform/nacl_sync_checked.h"
27 #include "native_client/src/shared/platform/nacl_sync_raii.h"
28 #include "native_client/src/shared/srpc/nacl_srpc.h"
29
30 // TODO(bsy): move weak_ref module to the shared directory
31 #include "native_client/src/trusted/weak_ref/weak_ref.h"
32
33 #include "ppapi/cpp/instance.h"
34 #include "ppapi/cpp/module.h"
35 #include "ppapi/cpp/var.h"
36
37 #include "ppapi/native_client/src/trusted/weak_ref/call_on_main_thread.h"
38 #include "ppapi/native_client/src/untrusted/nacl_ppapi_util/nacl_ppapi_util.h"
39 #include "ppapi/native_client/src/untrusted/nacl_ppapi_util/string_buffer.h"
40
41 class PostStringMessageWrapper
42 : public nacl_ppapi::EventThreadWorkStateWrapper<nacl_ppapi::VoidResult> {
43 public:
44 PostStringMessageWrapper(nacl_ppapi::EventThreadWorkState<
45 nacl_ppapi::VoidResult>
46 *state,
47 const std::string &msg)
48 : nacl_ppapi::EventThreadWorkStateWrapper<nacl_ppapi::VoidResult>(
49 state),
50 msg_(msg) {}
51 ~PostStringMessageWrapper();
52 const std::string &msg() const { return msg_; }
53 private:
54 std::string msg_;
55
56 DISALLOW_COPY_AND_ASSIGN(PostStringMessageWrapper);
57 };
58
59 // ---------------------------------------------------------------------------
60
61 class MyInstance;
62
63 struct WorkRequest {
64 explicit WorkRequest(const std::string &message)
65 : msg(message),
66 next(reinterpret_cast<WorkRequest *>(NULL)) {}
67 std::string msg; // copied from HandleMessage
68 WorkRequest *next;
69 private:
70 DISALLOW_COPY_AND_ASSIGN(WorkRequest);
71 };
72
73 // A Worker object is associated with a single worker thread and a
74 // plugin instance (which may be associated with multiple Worker
75 // objects/threads). It is created by a plugin instance (on the event
76 // handler thread) with a refcount of 2, with the expectation that one
77 // reference will be immediately handed off to its associated worker
78 // thread. When the plugin instance is about to be destroyed in the
79 // event handler thread, the event handler should invoke the
80 // ShouldExit member function, which automatically decrements the
81 // reference associated with the event handler thread (i.e., the event
82 // handler thread should no longer use the Worker*).
83 class Worker {
84 public:
85 explicit Worker(MyInstance *instance);
86
87 // RunToCompletion should be invoked in the worker thread. It
88 // returns when the plugin instance went away, and will
89 // automatically unref the Worker object, so the worker thread
90 // should no longer use the Worker object pointer after invoking
91 // RunToCompletion().
92 void RunToCompletion();
93
94 WorkRequest *Dequeue();
95 void Enqueue(WorkRequest *req);
96
97 void Initialize(nacl::StringBuffer *sb);
98 void ManifestListTest(nacl::StringBuffer *sb);
99 void ManifestOpenTest(nacl::StringBuffer *sb);
100
101 // Called on the event thread as part of the instance shutdown.
102 // Automatically unreferences the Worker object, so the event thread
103 // should stop using the Worker pointer after invoking ShouldExit.
104 void ShouldExit();
105
106 void Unref(); // used only for error cleanup, e.g., when the worker
107 // thread did not launch.
108
109 bool InitializeChannel(nacl::StringBuffer *sb);
110
111 protected:
112 // Event thread operation(s):
113 //
114 // In order for a test method to send reply messages, it should use
115 // this PostStringMessage method, since (currently) the PostMessage
116 // interface is event thread-only and not thread-safe. Returns true
117 // if successful and the thread should continue to do work, false
118 // otherwise (anchor has been abandoned).
119 bool PostStringMessage(const std::string &msg);
120 // ... more Event thread operations here.
121
122 private:
123 MyInstance *instance_; // cannot use directly from test worker thread!
124 nacl::WeakRefAnchor *anchor_;
125 // must copy out and Ref in ctor, since instance_ might go bad at any time.
126
127 NaClMutex mu_;
128 NaClCondVar cv_; // queue not empty or should_exit_
129
130 int ref_count_;
131 WorkRequest *queue_head_;
132 WorkRequest **queue_insert_;
133
134 bool should_exit_;
135
136 ~Worker();
137
138 WorkRequest *Dequeue_mu();
139 void Enqueue_mu(WorkRequest *req);
140
141 struct DispatchTable {
142 char const *op_name;
143 void (Worker::*mfunc)(nacl::StringBuffer *sb);
144 };
145
146 bool ns_channel_initialized_;
147 NaClSrpcChannel ns_channel_;
148
149 static DispatchTable const kDispatch[]; // null terminated
150
151 DISALLOW_COPY_AND_ASSIGN(Worker);
152 };
153
154 // This object represents one time the page says <embed>.
155 class MyInstance : public nacl_ppapi::NaClPpapiPluginInstance {
156 public:
157 explicit MyInstance(PP_Instance instance);
158 virtual ~MyInstance();
159 virtual void HandleMessage(const pp::Var& message_data);
160
161 Worker *worker() { return worker_; }
162
163 // used with plugin::WeakRefCompletionCallback
164 void PostStringMessage_EventThread(PostStringMessageWrapper *msg_wrapper,
165 int32_t err);
166 private:
167 Worker *worker_;
168
169 DISALLOW_COPY_AND_ASSIGN(MyInstance);
170 };
171
172 // ---------------------------------------------------------------------------
173
174 PostStringMessageWrapper::~PostStringMessageWrapper() {}
175
176 // ---------------------------------------------------------------------------
177
178 MyInstance::MyInstance(PP_Instance instance)
179 : nacl_ppapi::NaClPpapiPluginInstance(instance),
180 worker_(new Worker(this)) {
181 }
182
183 MyInstance::~MyInstance() {
184 worker_->ShouldExit();
185 }
186
187 void MyInstance::PostStringMessage_EventThread(
188 PostStringMessageWrapper *msg_wrapper,
189 int32_t err) {
190 PostMessage(msg_wrapper->msg());
191 msg_wrapper->SetResult(nacl_ppapi::g_void_result);
192 }
193
194 // ---------------------------------------------------------------------------
195
196 Worker::Worker(MyInstance *instance)
197 : instance_(instance),
198 anchor_(instance->anchor()->Ref()),
199 ref_count_(2), // one for the master and one for the dame...
200 queue_head_(NULL),
201 queue_insert_(&queue_head_),
202 should_exit_(false),
203 ns_channel_initialized_(false) {
204 NaClXMutexCtor(&mu_);
205 NaClXCondVarCtor(&cv_);
206 }
207
208 void Worker::Unref() {
209 bool do_delete;
210 do {
211 nacl::MutexLocker take(&mu_);
212 do_delete = (--ref_count_ == 0);
213 } while (0);
214 // dropped lock before invoking dtor
215 if (do_delete) {
216 delete this;
217 }
218 }
219
220 Worker::~Worker() {
221 anchor_->Unref();
222
223 WorkRequest *req;
224 while ((req = Dequeue_mu()) != NULL) {
225 delete req;
226 }
227
228 NaClMutexDtor(&mu_);
229 NaClCondVarDtor(&cv_);
230 }
231
232 void Worker::ShouldExit() {
233 do {
234 nacl::MutexLocker take(&mu_);
235 should_exit_ = true;
236 NaClXCondVarBroadcast(&cv_);
237 } while (0);
238 Unref();
239 }
240
241 WorkRequest *Worker::Dequeue_mu() {
242 WorkRequest *head = queue_head_;
243
244 if (head != NULL) {
245 queue_head_ = head->next;
246 if (queue_head_ == NULL) {
247 queue_insert_ = &queue_head_;
248 }
249 }
250 return head;
251 }
252
253 void Worker::Enqueue_mu(WorkRequest *req) {
254 req->next = NULL;
255 *queue_insert_ = req;
256 queue_insert_ = &req->next;
257 }
258
259 WorkRequest *Worker::Dequeue() {
260 nacl::MutexLocker take(&mu_);
261 return Dequeue_mu();
262 }
263
264 void Worker::Enqueue(WorkRequest *req) {
265 nacl::MutexLocker take(&mu_);
266 Enqueue_mu(req);
267 NaClXCondVarBroadcast(&cv_);
268 }
269
270 Worker::DispatchTable const Worker::kDispatch[] = {
271 { "init", &Worker::Initialize },
272 { "manifest_open", &Worker::ManifestOpenTest },
273 { reinterpret_cast<char const *>(NULL), NULL }
274 };
275
276 bool Worker::PostStringMessage(const std::string &msg) {
277 nacl_ppapi::EventThreadWorkState<nacl_ppapi::VoidResult> state;
278 plugin::WeakRefCallOnMainThread(anchor_,
279 0 /* mS */,
280 instance_,
281 &MyInstance::PostStringMessage_EventThread,
282 new PostStringMessageWrapper(&state, msg));
283 if (NULL == state.WaitForCompletion()) {
284 // anchor_ has been abandoned, so the plugin instance went away.
285 // we should drop our ref to the anchor, then shut down the worker
286 // thread.
287 nacl::MutexLocker take(&mu_);
288 should_exit_ = true;
289 // There's no need to condvar broadcast, since it is the worker
290 // thread that will look at the work queue and the should_exit_ to
291 // act on this. Unfortunately every worker thread must test the
292 // return value of PostStringMessage to determine if it should do
293 // early exit (if the worker needs to do multiple event-thread
294 // operations).
295 return false;
296 }
297 return true;
298 }
299
300 void Worker::RunToCompletion() {
301 for (;;) {
302 WorkRequest *req;
303 do {
304 nacl::MutexLocker take(&mu_);
305 for (;;) {
306 if (should_exit_) {
307 // drop the lock and drop the reference count to this
308 goto break_x3;
309 }
310 fprintf(stderr, "RunToCompletion: Dequeuing...\n");
311 if ((req = Dequeue_mu()) != NULL) {
312 fprintf(stderr, "RunToCompletion: found work %p\n",
313 reinterpret_cast<void *>(req));
314 break;
315 }
316 fprintf(stderr, "RunToCompletion: waiting\n");
317 NaClXCondVarWait(&cv_, &mu_);
318 fprintf(stderr, "RunToCompletion: woke up\n");
319 }
320 } while (0);
321
322 // Do the work, without holding the lock. The work function
323 // should reacquire mu_ as needed.
324
325 nacl::StringBuffer sb;
326
327 // scan dispatch table for op_name
328 fprintf(stderr, "RunToCompletion: scanning for %s\n", req->msg.c_str());
329 for (size_t ix = 0; kDispatch[ix].op_name != NULL; ++ix) {
330 fprintf(stderr,
331 "RunToCompletion: comparing against %s\n", kDispatch[ix].op_name);
332 if (req->msg == kDispatch[ix].op_name) {
333 if (InitializeChannel(&sb)) {
334 fprintf(stderr, "RunToCompletion: invoking table entry %u\n", ix);
335 (this->*(kDispatch[ix].mfunc))(&sb);
336 }
337 break;
338 }
339 }
340 // always post a reply, even if it is the empty string
341 fprintf(stderr,
342 "RunToCompletion: posting reply %s\n", sb.ToString().c_str());
343 if (!PostStringMessage(sb.ToString())) {
344 break;
345 }
346 }
347 break_x3:
348 fprintf(stderr, "RunToCompletion: exiting\n");
349 Unref();
350 }
351
352 bool Worker::InitializeChannel(nacl::StringBuffer *sb) {
353 if (ns_channel_initialized_) {
354 return true;
355 }
356 int ns = -1;
357 nacl_nameservice(&ns);
358 printf("ns = %d\n", ns);
359 assert(-1 != ns);
360 int connected_socket = imc_connect(ns);
361 assert(-1 != connected_socket);
362 if (!NaClSrpcClientCtor(&ns_channel_, connected_socket)) {
363 sb->Printf("Srpc client channel ctor failed\n");
364 close(ns);
365 return false;
366 }
367 sb->Printf("NaClSrpcClientCtor succeeded\n");
368 close(ns);
369 ns_channel_initialized_ = true;
370 return true;
371 }
372
373 void Worker::Initialize(nacl::StringBuffer *sb) {
374 // we just want the log output from the InitializeChannel
375 return;
376 }
377
378 void Worker::ManifestOpenTest(nacl::StringBuffer *sb) {
379 int status = -1;
380 int manifest;
381 struct NaClSrpcChannel manifest_channel;
382
383 // name service lookup for the manifest service descriptor
384 if (NACL_SRPC_RESULT_OK !=
385 NaClSrpcInvokeBySignature(&ns_channel_, NACL_NAME_SERVICE_LOOKUP,
386 "ManifestNameService", O_RDWR,
387 &status, &manifest) ||
388 NACL_NAME_SERVICE_SUCCESS != status) {
389 sb->Printf("nameservice lookup failed, status %d\n", status);
390 return;
391 }
392 sb->Printf("Got manifest descriptor %d\n", manifest);
393 if (-1 == manifest) {
394 return;
395 }
396
397 // connect to manifest name server
398 int manifest_conn = imc_connect(manifest);
399 close(manifest);
400 sb->Printf("got manifest connection %d\n", manifest_conn);
401 if (-1 == manifest_conn) {
402 sb->Printf("could not connect\n");
403 return;
404 }
405
406 // build the SRPC connection (do service discovery)
407 if (!NaClSrpcClientCtor(&manifest_channel, manifest_conn)) {
408 sb->Printf("could not build srpc client\n");
409 return;
410 }
411
412 int desc;
413
414 sb->Printf("Invoking name service lookup\n");
415 if (NACL_SRPC_RESULT_OK !=
416 NaClSrpcInvokeBySignature(&manifest_channel,
417 NACL_NAME_SERVICE_LOOKUP,
418 "files/test_file", O_RDONLY,
419 &status, &desc)) {
420 sb->Printf("manifest lookup RPC failed\n");
421 NaClSrpcDtor(&manifest_channel);
422 return;
423 }
424
425 sb->DiscardOutput();
426 sb->Printf("File Contents:\n");
427
428 char buffer[4096];
429 int len;
430 while ((len = read(desc, buffer, sizeof buffer - 1)) > 0) {
431 // Null terminate.
432 buffer[len] = '\0';
433 sb->Printf("%s", buffer);
434 }
435 NaClSrpcDtor(&manifest_channel);
436 return;
437 }
438
439 // HandleMessage gets invoked when postMessage is called on the DOM
440 // element associated with this plugin instance. In this case, if we
441 // are given a string, we'll post a message back to JavaScript with a
442 // reply -- essentially treating this as a string-based RPC.
443 void MyInstance::HandleMessage(const pp::Var& message) {
444 if (message.is_string()) {
445 fprintf(stderr,
446 "HandleMessage: enqueuing %s\n", message.AsString().c_str());
447 fflush(NULL);
448 worker_->Enqueue(new WorkRequest(message.AsString()));
449 } else {
450 fprintf(stderr, "HandleMessage: message is not a string\n");
451 fflush(NULL);
452 }
453 }
454
455 void *worker_thread_start(void *arg) {
456 Worker *worker = reinterpret_cast<Worker *>(arg);
457
458 fprintf(stderr, "Sleeping...\n"); fflush(stderr);
459 sleep(1);
460 fprintf(stderr, "worker_thread_start: worker %p\n",
461 reinterpret_cast<void *>(worker));
462 fflush(NULL);
463 worker->RunToCompletion();
464 worker = NULL; // RunToCompletion automatically Unrefs
465 return reinterpret_cast<void *>(NULL);
466 }
467
468 // This object is the global object representing this plugin library as long
469 // as it is loaded.
470 class MyModule : public pp::Module {
471 public:
472 MyModule() : pp::Module() {}
473 virtual ~MyModule() {}
474
475 // Override CreateInstance to create your customized Instance object.
476 virtual pp::Instance *CreateInstance(PP_Instance instance);
477
478 DISALLOW_COPY_AND_ASSIGN(MyModule);
479 };
480
481 pp::Instance *MyModule::CreateInstance(PP_Instance pp_instance) {
482 MyInstance *instance = new MyInstance(pp_instance);
483 // spawn worker thread associated with this instance
484 pthread_t thread;
485
486 fprintf(stderr, "CreateInstance invoked\n"); fflush(NULL);
487 if (0 != pthread_create(&thread,
488 reinterpret_cast<pthread_attr_t *>(NULL),
489 worker_thread_start,
490 reinterpret_cast<void *>(instance->worker()))) {
491 // Remove the reference the ownership of which should have been
492 // passed to the worker thread.
493 instance->worker()->Unref();
494 delete instance;
495 instance = NULL;
496 fprintf(stderr, "pthread_create failed\n"); fflush(NULL);
497 } else {
498 fprintf(stderr, "CreateInstance: Worker thread started\n");
499 fprintf(stderr, "CreateInstance: worker thread object %p\n",
500 reinterpret_cast<void *>(instance->worker()));
501 (void) pthread_detach(thread);
502 }
503 fprintf(stderr, "CreateInstance: returning instance %p\n",
504 reinterpret_cast<void *>(instance));
505
506 return instance;
507 }
508
509 namespace pp {
510
511 // Factory function for your specialization of the Module object.
512 Module* CreateModule() {
513 fprintf(stderr, "CreateModule invoked\n"); fflush(NULL);
514 return new MyModule();
515 }
516
517 } // namespace pp
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698