• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "ipc/ipc_perftest_util.h"
11 
12 #include <tuple>
13 
14 #include "base/logging.h"
15 #include "base/run_loop.h"
16 #include "base/task/single_thread_task_runner.h"
17 #include "build/build_config.h"
18 #include "ipc/ipc_channel_proxy.h"
19 #include "ipc/ipc_perftest_messages.h"
20 #include "mojo/core/embedder/embedder.h"
21 #include "mojo/core/test/multiprocess_test_helper.h"
22 
23 namespace IPC {
24 
GetIOThreadTaskRunner()25 scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() {
26   scoped_refptr<base::TaskRunner> runner = mojo::core::GetIOTaskRunner();
27   return scoped_refptr<base::SingleThreadTaskRunner>(
28       static_cast<base::SingleThreadTaskRunner*>(runner.get()));
29 }
30 
ChannelReflectorListener()31 ChannelReflectorListener::ChannelReflectorListener() : channel_(nullptr) {
32   VLOG(1) << "Client listener up";
33 }
34 
~ChannelReflectorListener()35 ChannelReflectorListener::~ChannelReflectorListener() {
36   VLOG(1) << "Client listener down";
37 }
38 
Init(Sender * channel,base::OnceClosure quit_closure)39 void ChannelReflectorListener::Init(Sender* channel,
40                                     base::OnceClosure quit_closure) {
41   DCHECK(!channel_);
42   channel_ = channel;
43   quit_closure_ = std::move(quit_closure);
44 }
45 
OnMessageReceived(const Message & message)46 bool ChannelReflectorListener::OnMessageReceived(const Message& message) {
47   CHECK(channel_);
48   bool handled = true;
49   IPC_BEGIN_MESSAGE_MAP(ChannelReflectorListener, message)
50     IPC_MESSAGE_HANDLER(TestMsg_Hello, OnHello)
51     IPC_MESSAGE_HANDLER(TestMsg_Ping, OnPing)
52     IPC_MESSAGE_HANDLER(TestMsg_SyncPing, OnSyncPing)
53     IPC_MESSAGE_HANDLER(TestMsg_Quit, OnQuit)
54     IPC_MESSAGE_UNHANDLED(handled = false)
55   IPC_END_MESSAGE_MAP()
56   return handled;
57 }
58 
OnHello()59 void ChannelReflectorListener::OnHello() {
60   channel_->Send(new TestMsg_Hello);
61 }
62 
OnPing(const std::string & payload)63 void ChannelReflectorListener::OnPing(const std::string& payload) {
64   channel_->Send(new TestMsg_Ping(payload));
65 }
66 
OnSyncPing(const std::string & payload,std::string * response)67 void ChannelReflectorListener::OnSyncPing(const std::string& payload,
68                                           std::string* response) {
69   *response = payload;
70 }
71 
OnQuit()72 void ChannelReflectorListener::OnQuit() {
73   std::move(quit_closure_).Run();
74 }
75 
Send(IPC::Message * message)76 void ChannelReflectorListener::Send(IPC::Message* message) {
77   channel_->Send(message);
78 }
79 
LockThreadAffinity(int cpu_number)80 LockThreadAffinity::LockThreadAffinity(int cpu_number)
81     : affinity_set_ok_(false) {
82 #if BUILDFLAG(IS_WIN)
83   const DWORD_PTR thread_mask = static_cast<DWORD_PTR>(1) << cpu_number;
84   old_affinity_ = SetThreadAffinityMask(GetCurrentThread(), thread_mask);
85   affinity_set_ok_ = old_affinity_ != 0;
86 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
87   cpu_set_t cpuset;
88   CPU_ZERO(&cpuset);
89   CPU_SET(cpu_number, &cpuset);
90   auto get_result = sched_getaffinity(0, sizeof(old_cpuset_), &old_cpuset_);
91   DCHECK_EQ(0, get_result);
92   auto set_result = sched_setaffinity(0, sizeof(cpuset), &cpuset);
93   // Check for get_result failure, even though it should always succeed.
94   affinity_set_ok_ = (set_result == 0) && (get_result == 0);
95 #endif
96   if (!affinity_set_ok_)
97     LOG(WARNING) << "Failed to set thread affinity to CPU " << cpu_number;
98 }
99 
~LockThreadAffinity()100 LockThreadAffinity::~LockThreadAffinity() {
101   if (!affinity_set_ok_)
102     return;
103 #if BUILDFLAG(IS_WIN)
104   auto set_result = SetThreadAffinityMask(GetCurrentThread(), old_affinity_);
105   DCHECK_NE(0u, set_result);
106 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
107   auto set_result = sched_setaffinity(0, sizeof(old_cpuset_), &old_cpuset_);
108   DCHECK_EQ(0, set_result);
109 #endif
110 }
111 
MojoPerfTestClient()112 MojoPerfTestClient::MojoPerfTestClient()
113     : listener_(new ChannelReflectorListener()) {
114   mojo::core::test::MultiprocessTestHelper::ChildSetup();
115 }
116 
117 MojoPerfTestClient::~MojoPerfTestClient() = default;
118 
Run(MojoHandle handle)119 int MojoPerfTestClient::Run(MojoHandle handle) {
120   handle_ = mojo::MakeScopedHandle(mojo::MessagePipeHandle(handle));
121   LockThreadAffinity thread_locker(kSharedCore);
122 
123   base::RunLoop run_loop;
124   std::unique_ptr<ChannelProxy> channel = IPC::ChannelProxy::Create(
125       handle_.release(), Channel::MODE_CLIENT, listener_.get(),
126       GetIOThreadTaskRunner(),
127       base::SingleThreadTaskRunner::GetCurrentDefault());
128   listener_->Init(channel.get(), run_loop.QuitWhenIdleClosure());
129   run_loop.Run();
130   return 0;
131 }
132 
ReflectorImpl(mojo::ScopedMessagePipeHandle handle,base::OnceClosure quit_closure)133 ReflectorImpl::ReflectorImpl(mojo::ScopedMessagePipeHandle handle,
134                              base::OnceClosure quit_closure)
135     : quit_closure_(std::move(quit_closure)),
136       receiver_(
137           this,
138           mojo::PendingReceiver<IPC::mojom::Reflector>(std::move(handle))) {}
139 
~ReflectorImpl()140 ReflectorImpl::~ReflectorImpl() {
141   std::ignore = receiver_.Unbind().PassPipe().release();
142 }
143 
Ping(const std::string & value,PingCallback callback)144 void ReflectorImpl::Ping(const std::string& value, PingCallback callback) {
145   std::move(callback).Run(value);
146 }
147 
SyncPing(const std::string & value,PingCallback callback)148 void ReflectorImpl::SyncPing(const std::string& value, PingCallback callback) {
149   std::move(callback).Run(value);
150 }
151 
Quit()152 void ReflectorImpl::Quit() {
153   if (quit_closure_)
154     std::move(quit_closure_).Run();
155 }
156 
157 }  // namespace IPC
158