| Index: mojo/public/cpp/application/lib/run_application.cc
|
| diff --git a/mojo/public/cpp/application/lib/run_application.cc b/mojo/public/cpp/application/lib/run_application.cc
|
| index 82d3089fef359221aa17680e909d2c8587ee45f7..03373ef4902c9508ae5ed8f14f33af61570156a7 100644
|
| --- a/mojo/public/cpp/application/lib/run_application.cc
|
| +++ b/mojo/public/cpp/application/lib/run_application.cc
|
| @@ -4,17 +4,66 @@
|
|
|
| #include "mojo/public/cpp/application/run_application.h"
|
|
|
| +#include <assert.h>
|
| +#include <pthread.h>
|
| +
|
| #include "mojo/public/cpp/application/application_impl_base.h"
|
| +#include "mojo/public/cpp/system/macros.h"
|
| #include "mojo/public/cpp/system/message_pipe.h"
|
| #include "mojo/public/cpp/utility/run_loop.h"
|
| #include "mojo/public/interfaces/application/application.mojom.h"
|
|
|
| namespace mojo {
|
|
|
| -void RunApplication(MojoHandle application_request_handle,
|
| - ApplicationImplBase* application_impl) {
|
| - // TODO(vtl): Possibly we should have an assertion that we're not running, but
|
| - // that requires TLS.
|
| +namespace {
|
| +
|
| +// We store a pointer to a |ResultHolder|, which just stores a |MojoResult|, in
|
| +// TLS so that |TerminateApplication()| can provide the result that
|
| +// |RunApplication()| will return. (The |ResultHolder| is just on
|
| +// |RunApplication()|'s stack.)
|
| +struct ResultHolder {
|
| +#ifndef NDEBUG
|
| + bool is_set = false;
|
| +#endif
|
| + MojoResult result = MOJO_RESULT_UNKNOWN;
|
| +};
|
| +
|
| +pthread_key_t g_current_result_holder_key;
|
| +
|
| +// Ensures that we have a TLS slot to store the current result in.
|
| +void InitializeCurrentResultHolderIfNecessary() {
|
| + static pthread_once_t current_result_holder_key_once = PTHREAD_ONCE_INIT;
|
| + int error = pthread_once(¤t_result_holder_key_once, []() {
|
| + int error = pthread_key_create(&g_current_result_holder_key, nullptr);
|
| + MOJO_ALLOW_UNUSED_LOCAL(error);
|
| + assert(!error);
|
| + });
|
| + MOJO_ALLOW_UNUSED_LOCAL(error);
|
| + assert(!error);
|
| +}
|
| +
|
| +ResultHolder* GetCurrentResultHolder() {
|
| + InitializeCurrentResultHolderIfNecessary();
|
| + return static_cast<ResultHolder*>(
|
| + pthread_getspecific(g_current_result_holder_key));
|
| +}
|
| +
|
| +void SetCurrentResultHolder(ResultHolder* result_holder) {
|
| + InitializeCurrentResultHolderIfNecessary();
|
| +
|
| + int error = pthread_setspecific(g_current_result_holder_key, result_holder);
|
| + MOJO_ALLOW_UNUSED_LOCAL(error);
|
| + assert(!error);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +MojoResult RunApplication(MojoHandle application_request_handle,
|
| + ApplicationImplBase* application_impl) {
|
| + assert(!GetCurrentResultHolder());
|
| +
|
| + ResultHolder result_holder;
|
| + SetCurrentResultHolder(&result_holder);
|
|
|
| RunLoop loop;
|
| application_impl->Bind(InterfaceRequest<Application>(
|
| @@ -23,10 +72,26 @@ void RunApplication(MojoHandle application_request_handle,
|
|
|
| // TODO(vtl): Should we unbind stuff here? (Should there be "will start"/"did
|
| // stop" notifications to the |ApplicationImplBase|?)
|
| +
|
| + SetCurrentResultHolder(nullptr);
|
| +
|
| + // TODO(vtl): We'd like to enable the following assertion, but we do things
|
| + // like |RunLoop::current()->Quit()| in various places.
|
| + // assert(result_holder.is_set);
|
| +
|
| + return result_holder.result;
|
| }
|
|
|
| -void TerminateApplication() {
|
| +void TerminateApplication(MojoResult result) {
|
| RunLoop::current()->Quit();
|
| +
|
| + ResultHolder* result_holder = GetCurrentResultHolder();
|
| + assert(result_holder);
|
| + assert(!result_holder->is_set);
|
| + result_holder->result = result;
|
| +#ifndef NDEBUG
|
| + result_holder->is_set = true;
|
| +#endif
|
| }
|
|
|
| } // namespace mojo
|
|
|