Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 1 | // Copyright 2014 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 <cstdlib> |
| 6 | |
| 7 | #include "base/bind.h" |
| 8 | #include "base/message_loop/message_loop.h" |
| 9 | #include "base/threading/thread.h" |
| 10 | #include "base/time/time.h" |
| 11 | #include "examples/indirect_service/indirect_service_demo.mojom.h" |
Viet-Trung Luu | 911b5de | 2016-05-31 12:19:19 -0700 | [diff] [blame^] | 12 | #include "mojo/environment/scoped_chromium_init.h" |
James Robinson | 94ade6b | 2015-08-25 13:02:06 -0700 | [diff] [blame] | 13 | #include "mojo/message_pump/message_pump_mojo.h" |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 14 | #include "mojo/public/c/system/main.h" |
Viet-Trung Luu | c103879 | 2016-05-27 11:05:20 -0700 | [diff] [blame] | 15 | #include "mojo/public/cpp/application/application_impl_base.h" |
Viet-Trung Luu | 8972b62 | 2016-04-25 18:06:17 -0700 | [diff] [blame] | 16 | #include "mojo/public/cpp/application/connect.h" |
Viet-Trung Luu | c103879 | 2016-05-27 11:05:20 -0700 | [diff] [blame] | 17 | #include "mojo/public/cpp/application/run_application.h" |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 18 | |
| 19 | namespace mojo { |
| 20 | namespace examples { |
| 21 | |
| 22 | class DemoTask; |
| 23 | |
Hans Muller | 1cad63f | 2014-11-21 11:14:47 -0800 | [diff] [blame] | 24 | typedef base::Callback<void(DemoTask*, const std::vector<int32_t>&)> |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 25 | DemoTaskFinishedCallback; |
| 26 | |
| 27 | // A thread that connects to the IndirectIntegerService, gets a connection |
| 28 | // to its IntegerService, and then calls Increment() iteration_count times. |
| 29 | // The results are saved and returned with the finished_callback. |
| 30 | class DemoTask { |
| 31 | public: |
| 32 | DemoTask(ScopedMessagePipeHandle proxy_handle, |
| 33 | const DemoTaskFinishedCallback& finished_callback, |
| 34 | unsigned iteration_count) |
| 35 | : proxy_handle_(proxy_handle.Pass()), |
| 36 | thread_("DemoTask"), |
| 37 | finished_callback_(finished_callback), |
| 38 | iteration_count_(iteration_count) { |
| 39 | |
| 40 | base::Thread::Options options; |
| 41 | options.message_loop_type = base::MessageLoop::TYPE_CUSTOM; |
| 42 | options.message_pump_factory = base::Bind(&common::MessagePumpMojo::Create); |
| 43 | CHECK(thread_.StartWithOptions(options)); |
| 44 | |
| 45 | thread_.message_loop()->PostTask( |
| 46 | FROM_HERE, base::Bind(&DemoTask::Run, base::Unretained(this))); |
| 47 | } |
| 48 | |
| 49 | void Run() { |
yzshen | 5bae223 | 2015-05-04 14:47:01 -0700 | [diff] [blame] | 50 | integer_service_.Bind( |
Vardhan Mudunuru | dac048a | 2016-02-03 17:16:52 -0800 | [diff] [blame] | 51 | InterfaceHandle<IntegerService>(proxy_handle_.Pass(), 0u)); |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 52 | base::Callback<void(int32_t)> callback = |
| 53 | base::Bind(&DemoTask::SaveResultAndFinish, base::Unretained(this)); |
| 54 | for(int unsigned i = 0; i < iteration_count_; i++) { |
| 55 | integer_service_->Increment(callback); |
| 56 | // To ensure that the DemoTask threads' execution overlaps, sleep. |
| 57 | if (i < iteration_count_ - 1) |
| 58 | base::PlatformThread::Sleep( |
| 59 | base::TimeDelta::FromMilliseconds(rand() % 10)); |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | private: |
| 64 | void SaveResultAndFinish(int32_t result) { |
| 65 | results_.push_back(result); |
| 66 | if (results_.size() == iteration_count_) { |
| 67 | integer_service_.reset(); // Must be done on thread_. |
| 68 | finished_callback_.Run(this, results_); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | ScopedMessagePipeHandle proxy_handle_; |
| 73 | base::Thread thread_; |
| 74 | IntegerServicePtr integer_service_; |
| 75 | DemoTaskFinishedCallback finished_callback_; |
| 76 | unsigned iteration_count_; |
| 77 | std::vector<int32_t> results_; |
| 78 | }; |
| 79 | |
| 80 | // Connect to the IntegerService and give its proxy to the |
| 81 | // IndirectIntegerService. Start kTaskCount DemoTask threads all of |
| 82 | // which will use the IndirectIntegerService to get their own connection |
| 83 | // to the (one) IntegerService. Each DemoTask will call the IntegerService's |
| 84 | // Increment() method kTaskIterationCount times, collect the results in |
| 85 | // a vector and return them to FinishDemoTask. |
| 86 | // |
| 87 | // The IntegerService, whose value is initially 0, will be called a total of |
| 88 | // N = |kTaskCount * kTaskIterationCount| times. Each DemoTask's results |
| 89 | // are displayed in array of length N. Digits appear in positions that |
| 90 | // correspond to the results obtained by the DemoTask thread. The results |
| 91 | // show that the DemoTask threads are accessing the Integer in parallel. |
| 92 | // The fact that only one digit appears in each column shows that things |
| 93 | // are working correctly. |
Viet-Trung Luu | c103879 | 2016-05-27 11:05:20 -0700 | [diff] [blame] | 94 | class IndirectServiceDemoApp : public ApplicationImplBase { |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 95 | public: |
Viet-Trung Luu | c103879 | 2016-05-27 11:05:20 -0700 | [diff] [blame] | 96 | void OnInitialize() override { |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 97 | IntegerServicePtr indirect_service_delegate; |
Viet-Trung Luu | c103879 | 2016-05-27 11:05:20 -0700 | [diff] [blame] | 98 | ConnectToService(shell(), "mojo:indirect_integer_service", |
Viet-Trung Luu | 8972b62 | 2016-04-25 18:06:17 -0700 | [diff] [blame] | 99 | GetProxy(&indirect_integer_service_)); |
Viet-Trung Luu | c103879 | 2016-05-27 11:05:20 -0700 | [diff] [blame] | 100 | ConnectToService(shell(), "mojo:integer_service", |
Viet-Trung Luu | 8972b62 | 2016-04-25 18:06:17 -0700 | [diff] [blame] | 101 | GetProxy(&indirect_service_delegate)); |
Vardhan Mudunuru | c3575c4 | 2016-02-11 15:08:21 -0800 | [diff] [blame] | 102 | indirect_integer_service_->Set( |
| 103 | indirect_service_delegate.PassInterfaceHandle()); |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 104 | |
| 105 | for (unsigned i = 0; i < kTaskCount; i++) { |
| 106 | IntegerServicePtr integer_service; |
| 107 | indirect_integer_service_->Get(GetProxy(&integer_service)); |
| 108 | DemoTaskFinishedCallback finished_callback = base::Bind( |
Viet-Trung Luu | c103879 | 2016-05-27 11:05:20 -0700 | [diff] [blame] | 109 | &IndirectServiceDemoApp::FinishDemoTask, base::Unretained(this), |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 110 | base::Unretained(base::MessageLoop::current())); |
| 111 | // We're passing the integer_service_ proxy to another thread, so |
| 112 | // use its MessagePipe. |
yzshen | 5bae223 | 2015-05-04 14:47:01 -0700 | [diff] [blame] | 113 | tasks_.push_back( |
Vardhan Mudunuru | a8bfcc8 | 2016-02-05 14:55:01 -0800 | [diff] [blame] | 114 | new DemoTask(integer_service.PassInterfaceHandle().PassHandle(), |
yzshen | 5bae223 | 2015-05-04 14:47:01 -0700 | [diff] [blame] | 115 | finished_callback, kTaskIterationCount)); |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 116 | } |
| 117 | } |
| 118 | |
| 119 | private: |
| 120 | static const unsigned kTaskCount = 10; |
| 121 | static const unsigned kTaskIterationCount = 6; |
| 122 | |
| 123 | // This method is called on a DemoTask thread. It just calls DoFinishDemoTask |
| 124 | // on the application's run loop. Doing so serializes the DoFinishDemoTask |
| 125 | // calls. |
| 126 | void FinishDemoTask(base::MessageLoop *run_loop, |
| 127 | DemoTask* task, |
| 128 | const std::vector<int32_t>& results) { |
Viet-Trung Luu | c103879 | 2016-05-27 11:05:20 -0700 | [diff] [blame] | 129 | run_loop->PostTask( |
| 130 | FROM_HERE, |
| 131 | base::Bind(&IndirectServiceDemoApp::DoFinishDemoTask, |
| 132 | base::Unretained(this), base::Unretained(task), results)); |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | void DoFinishDemoTask(DemoTask* task, const std::vector<int32_t>& results) { |
| 136 | std::string display(kTaskCount * kTaskIterationCount, ' '); |
| 137 | for (unsigned i = 0; i < results.size(); i++) |
| 138 | display[results[i]] = '0' + (results[i] % 10); |
| 139 | printf("DemoTask Thread [%s]\n", display.c_str()); |
| 140 | tasks_.erase(std::remove(tasks_.begin(), tasks_.end(), task), tasks_.end()); |
| 141 | delete task; // Stop the DemoTask's thread etc. |
| 142 | if (tasks_.empty()) |
Viet-Trung Luu | 911b5de | 2016-05-31 12:19:19 -0700 | [diff] [blame^] | 143 | TerminateApplication(MOJO_RESULT_OK); |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 144 | } |
| 145 | |
| 146 | IndirectIntegerServicePtr indirect_integer_service_; |
| 147 | std::vector<DemoTask*> tasks_; |
| 148 | }; |
| 149 | |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 150 | } // namespace examples |
| 151 | } // namespace mojo |
| 152 | |
Mitch Rudominer | 963aa77 | 2015-04-03 08:22:46 -0700 | [diff] [blame] | 153 | MojoResult MojoMain(MojoHandle application_request) { |
Viet-Trung Luu | 911b5de | 2016-05-31 12:19:19 -0700 | [diff] [blame^] | 154 | mojo::ScopedChromiumInit init; |
Viet-Trung Luu | c103879 | 2016-05-27 11:05:20 -0700 | [diff] [blame] | 155 | mojo::examples::IndirectServiceDemoApp indirect_service_demo_app; |
Viet-Trung Luu | 911b5de | 2016-05-31 12:19:19 -0700 | [diff] [blame^] | 156 | return mojo::RunApplication(application_request, &indirect_service_demo_app); |
Hans Muller | 3f2b646 | 2014-11-21 09:54:34 -0800 | [diff] [blame] | 157 | } |