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

Side by Side Diff: ppapi/native_client/src/trusted/plugin/service_runtime.cc

Issue 338353008: NaCl: clean up nexe loading logic in trusted plugin. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase + resolve conflicts Created 6 years, 6 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/native_client/src/trusted/plugin/service_runtime.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be 3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file. 4 * found in the LICENSE file.
5 */ 5 */
6 6
7 #define NACL_LOG_MODULE_NAME "Plugin_ServiceRuntime" 7 #define NACL_LOG_MODULE_NAME "Plugin_ServiceRuntime"
8 8
9 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h" 9 #include "ppapi/native_client/src/trusted/plugin/service_runtime.h"
10 10
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 339
340 void PluginReverseInterface::ReportExitStatus(int exit_status) { 340 void PluginReverseInterface::ReportExitStatus(int exit_status) {
341 service_runtime_->set_exit_status(exit_status); 341 service_runtime_->set_exit_status(exit_status);
342 } 342 }
343 343
344 int64_t PluginReverseInterface::RequestQuotaForWrite( 344 int64_t PluginReverseInterface::RequestQuotaForWrite(
345 nacl::string file_id, int64_t offset, int64_t bytes_to_write) { 345 nacl::string file_id, int64_t offset, int64_t bytes_to_write) {
346 return bytes_to_write; 346 return bytes_to_write;
347 } 347 }
348 348
349 // Thin wrapper for the arguments of LoadNexeAndStart(), as WeakRefNewCallback
350 // can take only one argument. Also, this dtor has the responsibility to invoke
351 // callbacks on destruction.
352 struct ServiceRuntime::LoadNexeAndStartData {
353 explicit LoadNexeAndStartData(const pp::CompletionCallback& callback)
354 : callback(callback) {
355 }
356
357 ~LoadNexeAndStartData() {
358 // We must call the callbacks here if they are not yet called, otherwise
359 // the resource would be leaked.
360 if (callback.pp_completion_callback().func)
361 callback.RunAndClear(PP_ERROR_ABORTED);
362 }
363
364 // On success path, this must be invoked manually. Otherwise the dtor would
365 // invoke callbacks with error code unexpectedly.
366 void Clear() {
367 callback = pp::CompletionCallback();
368 }
369
370 pp::CompletionCallback callback;
371 };
372
373 ServiceRuntime::ServiceRuntime(Plugin* plugin, 349 ServiceRuntime::ServiceRuntime(Plugin* plugin,
374 bool main_service_runtime, 350 bool main_service_runtime,
375 bool uses_nonsfi_mode, 351 bool uses_nonsfi_mode,
376 pp::CompletionCallback init_done_cb, 352 pp::CompletionCallback init_done_cb,
377 pp::CompletionCallback crash_cb) 353 pp::CompletionCallback crash_cb)
378 : plugin_(plugin), 354 : plugin_(plugin),
379 main_service_runtime_(main_service_runtime), 355 main_service_runtime_(main_service_runtime),
380 uses_nonsfi_mode_(uses_nonsfi_mode), 356 uses_nonsfi_mode_(uses_nonsfi_mode),
381 reverse_service_(NULL), 357 reverse_service_(NULL),
382 anchor_(new nacl::WeakRefAnchor()), 358 anchor_(new nacl::WeakRefAnchor()),
383 rev_interface_(new PluginReverseInterface(anchor_, plugin, this, 359 rev_interface_(new PluginReverseInterface(anchor_, plugin, this,
384 init_done_cb, crash_cb)), 360 init_done_cb, crash_cb)),
385 start_sel_ldr_done_(false), 361 start_sel_ldr_done_(false),
386 nexe_started_(false) { 362 start_nexe_done_(false),
363 nexe_started_ok_(false) {
387 NaClSrpcChannelInitialize(&command_channel_); 364 NaClSrpcChannelInitialize(&command_channel_);
388 NaClXMutexCtor(&mu_); 365 NaClXMutexCtor(&mu_);
389 NaClXCondVarCtor(&cond_); 366 NaClXCondVarCtor(&cond_);
390 } 367 }
391 368
392 void ServiceRuntime::LoadNexeAndStartAfterLoadModule(
393 LoadNexeAndStartData* data, int32_t pp_error) {
394 if (pp_error != PP_OK) {
395 DidLoadNexeAndStart(data, pp_error);
396 return;
397 }
398
399 // Here, LoadModule is successfully done. So the remaining task is just
400 // calling StartModule(), here.
401 DidLoadNexeAndStart(data, StartModule() ? PP_OK : PP_ERROR_FAILED);
402 }
403
404 void ServiceRuntime::DidLoadNexeAndStart(
405 LoadNexeAndStartData* data, int32_t pp_error) {
406 if (pp_error == PP_OK) {
407 NaClLog(4, "ServiceRuntime::LoadNexeAndStart (success)\n");
408 } else {
409 // On a load failure the service runtime does not crash itself to
410 // avoid a race where the no-more-senders error on the reverse
411 // channel esrvice thread might cause the crash-detection logic to
412 // kick in before the start_module RPC reply has been received. So
413 // we induce a service runtime crash here. We do not release
414 // subprocess_ since it's needed to collect crash log output after
415 // the error is reported.
416 Log(LOG_FATAL, "reap logs");
417 if (NULL == reverse_service_) {
418 // No crash detector thread.
419 NaClLog(LOG_ERROR, "scheduling to get crash log\n");
420 // Invoking rev_interface's method is workaround to avoid crash_cb
421 // gets called twice or more. We should clean this up later.
422 rev_interface_->ReportCrash();
423 NaClLog(LOG_ERROR, "should fire soon\n");
424 } else {
425 NaClLog(LOG_ERROR, "Reverse service thread will pick up crash log\n");
426 }
427 }
428
429 pp::Module::Get()->core()->CallOnMainThread(0, data->callback, pp_error);
430
431 // Because the ownership of data is taken by caller, we must clear it
432 // manually here. Otherwise, its dtor invokes callbacks again.
433 data->Clear();
434 }
435
436 bool ServiceRuntime::SetupCommandChannel() { 369 bool ServiceRuntime::SetupCommandChannel() {
437 NaClLog(4, "ServiceRuntime::SetupCommand (this=%p, subprocess=%p)\n", 370 NaClLog(4, "ServiceRuntime::SetupCommand (this=%p, subprocess=%p)\n",
438 static_cast<void*>(this), 371 static_cast<void*>(this),
439 static_cast<void*>(subprocess_.get())); 372 static_cast<void*>(subprocess_.get()));
440 if (uses_nonsfi_mode_) { 373 if (uses_nonsfi_mode_) {
441 // In non-SFI mode, no SRPC is used. Just skips and returns success. 374 // In non-SFI mode, no SRPC is used. Just skips and returns success.
442 return true; 375 return true;
443 } 376 }
444 377
445 if (!subprocess_->SetupCommand(&command_channel_)) { 378 if (!subprocess_->SetupCommand(&command_channel_)) {
446 if (main_service_runtime_) { 379 if (main_service_runtime_) {
447 ErrorInfo error_info; 380 ErrorInfo error_info;
448 error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_CMD_CHANNEL, 381 error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_CMD_CHANNEL,
449 "ServiceRuntime: command channel creation failed"); 382 "ServiceRuntime: command channel creation failed");
450 plugin_->ReportLoadError(error_info); 383 plugin_->ReportLoadError(error_info);
451 } 384 }
452 return false; 385 return false;
453 } 386 }
454 return true; 387 return true;
455 } 388 }
456 389
457 void ServiceRuntime::LoadModule(PP_NaClFileInfo file_info,
458 pp::CompletionCallback callback) {
459 if (uses_nonsfi_mode_) {
460 // In non-SFI mode, loading is done a part of LaunchSelLdr.
461 DidLoadModule(callback, PP_OK);
462 return;
463 }
464
465 NaClFileInfo nacl_file_info;
466 nacl_file_info.desc = ConvertFileDescriptor(file_info.handle, true);
467 nacl_file_info.file_token.lo = file_info.token_lo;
468 nacl_file_info.file_token.hi = file_info.token_hi;
469 NaClDesc* desc = NaClDescIoFromFileInfo(nacl_file_info, O_RDONLY);
470 if (desc == NULL) {
471 DidLoadModule(callback, PP_ERROR_FAILED);
472 return;
473 }
474
475 // We don't use a scoped_ptr here since we would immediately release the
476 // DescWrapper to LoadModule().
477 nacl::DescWrapper* wrapper =
478 plugin_->wrapper_factory()->MakeGenericCleanup(desc);
479
480 // TODO(teravest, hidehiko): Replace this by Chrome IPC.
481 bool result = subprocess_->LoadModule(&command_channel_, wrapper);
482 DidLoadModule(callback, result ? PP_OK : PP_ERROR_FAILED);
483 }
484
485 void ServiceRuntime::DidLoadModule(pp::CompletionCallback callback,
486 int32_t pp_error) {
487 if (pp_error != PP_OK) {
488 ErrorInfo error_info;
489 error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_CMD_CHANNEL,
490 "ServiceRuntime: load module failed");
491 plugin_->ReportLoadError(error_info);
492 }
493 callback.Run(pp_error);
494 }
495
496 bool ServiceRuntime::InitReverseService() { 390 bool ServiceRuntime::InitReverseService() {
497 if (uses_nonsfi_mode_) { 391 if (uses_nonsfi_mode_) {
498 // In non-SFI mode, no reverse service is set up. Just returns success. 392 // In non-SFI mode, no reverse service is set up. Just returns success.
499 return true; 393 return true;
500 } 394 }
501 395
502 // Hook up the reverse service channel. We are the IMC client, but 396 // Hook up the reverse service channel. We are the IMC client, but
503 // provide SRPC service. 397 // provide SRPC service.
504 NaClDesc* out_conn_cap; 398 NaClDesc* out_conn_cap;
505 NaClSrpcResultCodes rpc_result = 399 NaClSrpcResultCodes rpc_result =
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 } 554 }
661 return start_sel_ldr_done_; 555 return start_sel_ldr_done_;
662 } 556 }
663 557
664 void ServiceRuntime::SignalStartSelLdrDone() { 558 void ServiceRuntime::SignalStartSelLdrDone() {
665 nacl::MutexLocker take(&mu_); 559 nacl::MutexLocker take(&mu_);
666 start_sel_ldr_done_ = true; 560 start_sel_ldr_done_ = true;
667 NaClXCondVarSignal(&cond_); 561 NaClXCondVarSignal(&cond_);
668 } 562 }
669 563
670 void ServiceRuntime::WaitForNexeStart() { 564 bool ServiceRuntime::WaitForNexeStart() {
671 nacl::MutexLocker take(&mu_); 565 nacl::MutexLocker take(&mu_);
672 while (!nexe_started_) 566 while (!start_nexe_done_)
673 NaClXCondVarWait(&cond_, &mu_); 567 NaClXCondVarWait(&cond_, &mu_);
674 // Reset nexe_started_ here in case we run again. 568 return nexe_started_ok_;
675 nexe_started_ = false;
676 } 569 }
677 570
678 void ServiceRuntime::SignalNexeStarted() { 571 void ServiceRuntime::SignalNexeStarted(bool ok) {
679 nacl::MutexLocker take(&mu_); 572 nacl::MutexLocker take(&mu_);
680 nexe_started_ = true; 573 start_nexe_done_ = true;
574 nexe_started_ok_ = ok;
681 NaClXCondVarSignal(&cond_); 575 NaClXCondVarSignal(&cond_);
682 } 576 }
683 577
684 void ServiceRuntime::LoadNexeAndStart(PP_NaClFileInfo file_info, 578 void ServiceRuntime::LoadNexeAndStart(PP_NaClFileInfo file_info) {
685 const pp::CompletionCallback& callback) {
686 NaClLog(4, "ServiceRuntime::LoadNexeAndStart (handle_valid=%d " 579 NaClLog(4, "ServiceRuntime::LoadNexeAndStart (handle_valid=%d "
687 "token_lo=%" NACL_PRIu64 " token_hi=%" NACL_PRIu64 ")\n", 580 "token_lo=%" NACL_PRIu64 " token_hi=%" NACL_PRIu64 ")\n",
688 file_info.handle != PP_kInvalidFileHandle, 581 file_info.handle != PP_kInvalidFileHandle,
689 file_info.token_lo, 582 file_info.token_lo,
690 file_info.token_hi); 583 file_info.token_hi);
691 584
692 nacl::scoped_ptr<LoadNexeAndStartData> data( 585 bool ok = LoadNexeAndStartInternal(file_info);
693 new LoadNexeAndStartData(callback)); 586 if (ok) {
694 if (!SetupCommandChannel() || !InitReverseService()) { 587 NaClLog(4, "ServiceRuntime::LoadNexeAndStart (success)\n");
695 DidLoadNexeAndStart(data.get(), PP_ERROR_FAILED); 588 } else {
696 return; 589 ReapLogs();
590 }
591 // This only matters if a background thread is waiting, but we signal in all
592 // cases to simplify the code.
593 SignalNexeStarted(ok);
594 }
595
596 bool ServiceRuntime::LoadNexeAndStartInternal(
597 const PP_NaClFileInfo& file_info) {
598 if(!SetupCommandChannel()) {
599 return false;
600 }
601 if (!InitReverseService()) {
602 return false;
603 }
604 if (!LoadModule(file_info)) {
605 ErrorInfo error_info;
606 error_info.SetReport(PP_NACL_ERROR_SEL_LDR_COMMUNICATION_CMD_CHANNEL,
607 "ServiceRuntime: load module failed");
608 plugin_->ReportLoadError(error_info);
609 return false;
610 }
611 if (!StartModule()) {
612 return false;
613 }
614 return true;
615 }
616
617 bool ServiceRuntime::LoadModule(const PP_NaClFileInfo& file_info) {
618 if (uses_nonsfi_mode_) {
619 // In non-SFI mode, loading is done a part of LaunchSelLdr.
620 return true;
697 } 621 }
698 622
699 LoadModule( 623 NaClFileInfo nacl_file_info;
700 file_info, 624 nacl_file_info.desc = ConvertFileDescriptor(file_info.handle, true);
701 WeakRefNewCallback(anchor_, 625 nacl_file_info.file_token.lo = file_info.token_lo;
702 this, 626 nacl_file_info.file_token.hi = file_info.token_hi;
703 &ServiceRuntime::LoadNexeAndStartAfterLoadModule, 627 NaClDesc* desc = NaClDescIoFromFileInfo(nacl_file_info, O_RDONLY);
704 data.release())); // Delegate the ownership. 628 if (desc == NULL) {
629 return false;
630 }
631 // We don't use a scoped_ptr here since we would immediately release the
632 // DescWrapper to LoadModule().
633 nacl::DescWrapper* wrapper =
634 plugin_->wrapper_factory()->MakeGenericCleanup(desc);
635 // TODO(teravest, hidehiko): Replace this by Chrome IPC.
636 return subprocess_->LoadModule(&command_channel_, wrapper);
637 }
638
639 void ServiceRuntime::ReapLogs() {
640 // On a load failure the service runtime does not crash itself to
641 // avoid a race where the no-more-senders error on the reverse
642 // channel service thread might cause the crash-detection logic to
643 // kick in before the start_module RPC reply has been received. So
644 // we induce a service runtime crash here. We do not release
645 // subprocess_ since it's needed to collect crash log output after
646 // the error is reported.
647 RemoteLog(LOG_FATAL, "reap logs\n");
648 if (NULL == reverse_service_) {
649 // No crash detector thread.
650 NaClLog(LOG_ERROR, "scheduling to get crash log\n");
651 // Invoking rev_interface's method is workaround to avoid crash_cb
652 // gets called twice or more. We should clean this up later.
653 rev_interface_->ReportCrash();
654 NaClLog(LOG_ERROR, "should fire soon\n");
655 } else {
656 NaClLog(LOG_ERROR, "Reverse service thread will pick up crash log\n");
657 }
705 } 658 }
706 659
707 SrpcClient* ServiceRuntime::SetupAppChannel() { 660 SrpcClient* ServiceRuntime::SetupAppChannel() {
708 NaClLog(4, "ServiceRuntime::SetupAppChannel (subprocess_=%p)\n", 661 NaClLog(4, "ServiceRuntime::SetupAppChannel (subprocess_=%p)\n",
709 reinterpret_cast<void*>(subprocess_.get())); 662 reinterpret_cast<void*>(subprocess_.get()));
710 nacl::DescWrapper* connect_desc = subprocess_->socket_addr()->Connect(); 663 nacl::DescWrapper* connect_desc = subprocess_->socket_addr()->Connect();
711 if (NULL == connect_desc) { 664 if (NULL == connect_desc) {
712 NaClLog(LOG_ERROR, "ServiceRuntime::SetupAppChannel (connect failed)\n"); 665 NaClLog(LOG_ERROR, "ServiceRuntime::SetupAppChannel (connect failed)\n");
713 return NULL; 666 return NULL;
714 } else { 667 } else {
715 NaClLog(4, "ServiceRuntime::SetupAppChannel (conect_desc=%p)\n", 668 NaClLog(4, "ServiceRuntime::SetupAppChannel (conect_desc=%p)\n",
716 static_cast<void*>(connect_desc)); 669 static_cast<void*>(connect_desc));
717 SrpcClient* srpc_client = SrpcClient::New(connect_desc); 670 SrpcClient* srpc_client = SrpcClient::New(connect_desc);
718 NaClLog(4, "ServiceRuntime::SetupAppChannel (srpc_client=%p)\n", 671 NaClLog(4, "ServiceRuntime::SetupAppChannel (srpc_client=%p)\n",
719 static_cast<void*>(srpc_client)); 672 static_cast<void*>(srpc_client));
720 delete connect_desc; 673 delete connect_desc;
721 return srpc_client; 674 return srpc_client;
722 } 675 }
723 } 676 }
724 677
725 bool ServiceRuntime::Log(int severity, const nacl::string& msg) { 678 bool ServiceRuntime::RemoteLog(int severity, const nacl::string& msg) {
726 NaClSrpcResultCodes rpc_result = 679 NaClSrpcResultCodes rpc_result =
727 NaClSrpcInvokeBySignature(&command_channel_, 680 NaClSrpcInvokeBySignature(&command_channel_,
728 "log:is:", 681 "log:is:",
729 severity, 682 severity,
730 strdup(msg.c_str())); 683 strdup(msg.c_str()));
731 return (NACL_SRPC_RESULT_OK == rpc_result); 684 return (NACL_SRPC_RESULT_OK == rpc_result);
732 } 685 }
733 686
734 void ServiceRuntime::Shutdown() { 687 void ServiceRuntime::Shutdown() {
735 rev_interface_->ShutDown(); 688 rev_interface_->ShutDown();
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 734
782 nacl::string ServiceRuntime::GetCrashLogOutput() { 735 nacl::string ServiceRuntime::GetCrashLogOutput() {
783 if (NULL != subprocess_.get()) { 736 if (NULL != subprocess_.get()) {
784 return subprocess_->GetCrashLogOutput(); 737 return subprocess_->GetCrashLogOutput();
785 } else { 738 } else {
786 return std::string(); 739 return std::string();
787 } 740 }
788 } 741 }
789 742
790 } // namespace plugin 743 } // namespace plugin
OLDNEW
« no previous file with comments | « ppapi/native_client/src/trusted/plugin/service_runtime.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698