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