blob: ad4770170bb91ca41400170fc1284337007a9365 [file] [log] [blame]
Hans Muller3f2b6462014-11-21 09:54:34 -08001// 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 Luu911b5de2016-05-31 12:19:19 -070012#include "mojo/environment/scoped_chromium_init.h"
James Robinson94ade6b2015-08-25 13:02:06 -070013#include "mojo/message_pump/message_pump_mojo.h"
Hans Muller3f2b6462014-11-21 09:54:34 -080014#include "mojo/public/c/system/main.h"
Viet-Trung Luuc1038792016-05-27 11:05:20 -070015#include "mojo/public/cpp/application/application_impl_base.h"
Viet-Trung Luu8972b622016-04-25 18:06:17 -070016#include "mojo/public/cpp/application/connect.h"
Viet-Trung Luuc1038792016-05-27 11:05:20 -070017#include "mojo/public/cpp/application/run_application.h"
Hans Muller3f2b6462014-11-21 09:54:34 -080018
19namespace mojo {
20namespace examples {
21
22class DemoTask;
23
Hans Muller1cad63f2014-11-21 11:14:47 -080024typedef base::Callback<void(DemoTask*, const std::vector<int32_t>&)>
Hans Muller3f2b6462014-11-21 09:54:34 -080025 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.
30class 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() {
yzshen5bae2232015-05-04 14:47:01 -070050 integer_service_.Bind(
Vardhan Mudunurudac048a2016-02-03 17:16:52 -080051 InterfaceHandle<IntegerService>(proxy_handle_.Pass(), 0u));
Hans Muller3f2b6462014-11-21 09:54:34 -080052 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 Luuc1038792016-05-27 11:05:20 -070094class IndirectServiceDemoApp : public ApplicationImplBase {
Hans Muller3f2b6462014-11-21 09:54:34 -080095 public:
Viet-Trung Luuc1038792016-05-27 11:05:20 -070096 void OnInitialize() override {
Hans Muller3f2b6462014-11-21 09:54:34 -080097 IntegerServicePtr indirect_service_delegate;
Viet-Trung Luuc1038792016-05-27 11:05:20 -070098 ConnectToService(shell(), "mojo:indirect_integer_service",
Viet-Trung Luu8972b622016-04-25 18:06:17 -070099 GetProxy(&indirect_integer_service_));
Viet-Trung Luuc1038792016-05-27 11:05:20 -0700100 ConnectToService(shell(), "mojo:integer_service",
Viet-Trung Luu8972b622016-04-25 18:06:17 -0700101 GetProxy(&indirect_service_delegate));
Vardhan Mudunuruc3575c42016-02-11 15:08:21 -0800102 indirect_integer_service_->Set(
103 indirect_service_delegate.PassInterfaceHandle());
Hans Muller3f2b6462014-11-21 09:54:34 -0800104
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 Luuc1038792016-05-27 11:05:20 -0700109 &IndirectServiceDemoApp::FinishDemoTask, base::Unretained(this),
Hans Muller3f2b6462014-11-21 09:54:34 -0800110 base::Unretained(base::MessageLoop::current()));
111 // We're passing the integer_service_ proxy to another thread, so
112 // use its MessagePipe.
yzshen5bae2232015-05-04 14:47:01 -0700113 tasks_.push_back(
Vardhan Mudunurua8bfcc82016-02-05 14:55:01 -0800114 new DemoTask(integer_service.PassInterfaceHandle().PassHandle(),
yzshen5bae2232015-05-04 14:47:01 -0700115 finished_callback, kTaskIterationCount));
Hans Muller3f2b6462014-11-21 09:54:34 -0800116 }
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 Luuc1038792016-05-27 11:05:20 -0700129 run_loop->PostTask(
130 FROM_HERE,
131 base::Bind(&IndirectServiceDemoApp::DoFinishDemoTask,
132 base::Unretained(this), base::Unretained(task), results));
Hans Muller3f2b6462014-11-21 09:54:34 -0800133 }
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 Luu911b5de2016-05-31 12:19:19 -0700143 TerminateApplication(MOJO_RESULT_OK);
Hans Muller3f2b6462014-11-21 09:54:34 -0800144 }
145
146 IndirectIntegerServicePtr indirect_integer_service_;
147 std::vector<DemoTask*> tasks_;
148};
149
Hans Muller3f2b6462014-11-21 09:54:34 -0800150} // namespace examples
151} // namespace mojo
152
Mitch Rudominer963aa772015-04-03 08:22:46 -0700153MojoResult MojoMain(MojoHandle application_request) {
Viet-Trung Luu911b5de2016-05-31 12:19:19 -0700154 mojo::ScopedChromiumInit init;
Viet-Trung Luuc1038792016-05-27 11:05:20 -0700155 mojo::examples::IndirectServiceDemoApp indirect_service_demo_app;
Viet-Trung Luu911b5de2016-05-31 12:19:19 -0700156 return mojo::RunApplication(application_request, &indirect_service_demo_app);
Hans Muller3f2b6462014-11-21 09:54:34 -0800157}