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/memory/scoped_vector.h" | |
9 #include "base/message_loop/message_loop.h" | |
10 #include "base/threading/thread.h" | |
11 #include "base/time/time.h" | |
12 #include "examples/indirect_service/indirect_service_demo.mojom.h" | |
13 #include "mojo/application/application_runner_chromium.h" | |
14 #include "mojo/common/message_pump_mojo.h" | |
15 #include "mojo/public/c/system/main.h" | |
16 #include "mojo/public/cpp/application/application_delegate.h" | |
17 #include "mojo/public/cpp/application/application_impl.h" | |
18 | |
19 namespace mojo { | |
20 namespace examples { | |
21 | |
22 class DemoTask; | |
23 | |
24 typedef typename base::Callback<void(DemoTask*, const std::vector<int32_t>&)> | |
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 | |
yzshen1
2014/11/20 22:01:44
unnecessary empty line.
| |
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() { | |
50 integer_service_.Bind(proxy_handle_.Pass()); | |
51 base::Callback<void(int32_t)> callback = | |
52 base::Bind(&DemoTask::SaveResultAndFinish, base::Unretained(this)); | |
53 for(int unsigned i = 0; i < iteration_count_; i++) { | |
54 integer_service_->Increment(callback); | |
55 // To ensure that the DemoTask threads' execution overlaps, sleep. | |
56 if (i < iteration_count_ - 1) | |
57 base::PlatformThread::Sleep( | |
58 base::TimeDelta::FromMilliseconds(rand() % 10)); | |
59 } | |
60 } | |
61 | |
62 private: | |
63 void SaveResultAndFinish(int32_t result) { | |
64 results_.push_back(result); | |
65 if (results_.size() == iteration_count_) { | |
66 finished_callback_.Run(this, results_); | |
67 integer_service_.reset(); // Must be done on thread_. | |
yzshen1
2014/11/20 22:01:44
It seems better to do the reset before running the
hansmuller
2014/11/20 22:35:38
Good point.
| |
68 } | |
69 } | |
70 | |
71 ScopedMessagePipeHandle proxy_handle_; | |
72 base::Thread thread_; | |
73 IntegerServicePtr integer_service_; | |
74 DemoTaskFinishedCallback finished_callback_; | |
75 unsigned iteration_count_; | |
76 std::vector<int32_t> results_; | |
77 }; | |
78 | |
79 // Connect to the IntegerService and give its proxy to the | |
80 // IndirectIntegerService. Start kTaskCount DemoTask threads all of | |
81 // which will use the IndirectIntegerService to get their own connection | |
82 // to the (one) IntegerService. Each DemoTask will call the IntegerService's | |
83 // Increment() method kTaskIterationCount times, collect the results in | |
84 // a vector and return them to FinishDemoTask. | |
85 // | |
86 // The IntegerService, whose value is initially 0, will be called a total of | |
87 // N = |kTaskCount * kTaskIterationCount| times. Each DemoTask's results | |
88 // are displayed in array of length N. Digits appear in positions that | |
89 // correspond to the results obtained by the DemoTask thread. The results | |
90 // show that the DemoTask threads are accessing the Integer in parallel. | |
91 // The fact that only one digit appears in each column shows that things | |
92 // are working correctly. | |
93 class IndirectServiceDemoAppDelegate : public ApplicationDelegate { | |
94 public: | |
95 virtual void Initialize(ApplicationImpl* app) override { | |
yzshen1
2014/11/20 22:01:44
nit: no need to have virtual
hansmuller
2014/11/20 22:35:38
Sorry, I missed that one.
| |
96 IntegerServicePtr indirect_service_delegate; | |
97 app->ConnectToService("mojo:indirect_integer_service", | |
98 &indirect_integer_service_); | |
99 app->ConnectToService("mojo:integer_service", &indirect_service_delegate); | |
100 indirect_integer_service_->Set(indirect_service_delegate.Pass()); | |
101 | |
102 for (unsigned i = 0; i < kTaskCount; i++) { | |
103 IntegerServicePtr integer_service; | |
104 indirect_integer_service_->Get(GetProxy(&integer_service)); | |
105 DemoTaskFinishedCallback finished_callback = base::Bind( | |
106 &IndirectServiceDemoAppDelegate::FinishDemoTask, | |
107 base::Unretained(this), | |
108 base::Unretained(base::MessageLoop::current())); | |
109 // We're passing the integer_service_ proxy to another thread, so | |
110 // use its MessagePipe. | |
111 scoped_ptr<DemoTask> task(new DemoTask(integer_service.PassMessagePipe(), | |
112 finished_callback, | |
113 kTaskIterationCount)); | |
114 tasks_.push_back(task.Pass()); | |
115 } | |
116 } | |
117 | |
118 private: | |
119 static const unsigned kTaskCount = 10; | |
120 static const unsigned kTaskIterationCount = 6; | |
121 | |
122 // This method is called on a DemoTask thread. It just calls DoFinishDemoTask | |
123 // on the application's run loop. Doing so serializes the DoFinishDemoTask | |
124 // calls. | |
125 void FinishDemoTask(base::MessageLoop *run_loop, | |
126 DemoTask* task, | |
127 const std::vector<int32_t>& results) { | |
128 run_loop->PostTask(FROM_HERE, base::Bind( | |
129 &IndirectServiceDemoAppDelegate::DoFinishDemoTask, | |
130 base::Unretained(this), | |
131 base::Unretained(task), | |
132 results)); | |
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 if (tasks_.empty()) | |
142 ApplicationImpl::Terminate(); | |
143 } | |
144 | |
145 IndirectIntegerServicePtr indirect_integer_service_; | |
146 std::vector<scoped_ptr<DemoTask>> tasks_; | |
yzshen1
2014/11/20 22:01:44
This is a library feature of C++11 (move-only obje
hansmuller
2014/11/20 22:35:38
OK.
| |
147 }; | |
148 | |
149 | |
150 } // namespace examples | |
151 } // namespace mojo | |
152 | |
153 MojoResult MojoMain(MojoHandle shell_handle) { | |
154 mojo::ApplicationRunnerChromium runner( | |
155 new mojo::examples::IndirectServiceDemoAppDelegate); | |
156 return runner.Run(shell_handle); | |
157 } | |
OLD | NEW |