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 #include "base/threading/platform_thread.h"
6
7 #include <fidl/fuchsia.media/cpp/fidl.h>
8 #include <lib/fdio/directory.h>
9 #include <lib/sys/cpp/component_context.h>
10 #include <pthread.h>
11 #include <sched.h>
12 #include <zircon/syscalls.h>
13
14 #include <mutex>
15 #include <string_view>
16
17 #include "base/fuchsia/fuchsia_component_connect.h"
18 #include "base/fuchsia/fuchsia_logging.h"
19 #include "base/fuchsia/scheduler.h"
20 #include "base/no_destructor.h"
21 #include "base/threading/platform_thread_internal_posix.h"
22 #include "base/threading/thread_id_name_manager.h"
23 #include "base/threading/thread_local_storage.h"
24
25 namespace base {
26
27 namespace {
28
ConnectProfileProvider()29 fidl::SyncClient<fuchsia_media::ProfileProvider> ConnectProfileProvider() {
30 auto profile_provider_client_end =
31 base::fuchsia_component::Connect<fuchsia_media::ProfileProvider>();
32 if (profile_provider_client_end.is_error()) {
33 LOG(ERROR) << base::FidlConnectionErrorMessage(profile_provider_client_end);
34 return {};
35 }
36 return fidl::SyncClient(std::move(profile_provider_client_end.value()));
37 }
38
39 // Sets the current thread to the given scheduling role, optionally including
40 // hints about the workload period and max CPU runtime (capacity * period) in
41 // that period.
42 // TODO(crbug.com/1365682): Migrate to the new fuchsia.scheduler.ProfileProvider
43 // API when available.
SetThreadRole(std::string_view role_name,TimeDelta period={},float capacity=0.0f)44 void SetThreadRole(std::string_view role_name,
45 TimeDelta period = {},
46 float capacity = 0.0f) {
47 DCHECK_GE(capacity, 0.0);
48 DCHECK_LE(capacity, 1.0);
49
50 static const base::NoDestructor<
51 fidl::SyncClient<fuchsia_media::ProfileProvider>>
52 profile_provider(ConnectProfileProvider());
53
54 if (!profile_provider->is_valid()) {
55 return;
56 }
57
58 zx::thread dup_thread;
59 zx_status_t status =
60 zx::thread::self()->duplicate(ZX_RIGHT_SAME_RIGHTS, &dup_thread);
61 ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
62
63 std::string role_selector{role_name};
64 auto result = (*profile_provider)
65 ->RegisterHandlerWithCapacity(
66 {{.thread_handle = std::move(dup_thread),
67 .name = role_selector,
68 .period = period.ToZxDuration(),
69 .capacity = capacity}});
70 if (result.is_error()) {
71 ZX_DLOG(ERROR, result.error_value().status())
72 << "Failed call to RegisterHandlerWithCapacity";
73 }
74 }
75
76 } // namespace
77
InitThreading()78 void InitThreading() {}
79
TerminateOnThread()80 void TerminateOnThread() {}
81
GetDefaultThreadStackSize(const pthread_attr_t & attributes)82 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
83 return 0;
84 }
85
86 // static
SetName(const std::string & name)87 void PlatformThread::SetName(const std::string& name) {
88 zx_status_t status =
89 zx::thread::self()->set_property(ZX_PROP_NAME, name.data(), name.size());
90 DCHECK_EQ(status, ZX_OK);
91
92 SetNameCommon(name);
93 }
94
95 // static
CanChangeThreadType(ThreadType from,ThreadType to)96 bool PlatformThread::CanChangeThreadType(ThreadType from, ThreadType to) {
97 return from == to || to == ThreadType::kDisplayCritical ||
98 to == ThreadType::kRealtimeAudio;
99 }
100
101 namespace internal {
102
SetCurrentThreadTypeImpl(ThreadType thread_type,MessagePumpType pump_type_hint)103 void SetCurrentThreadTypeImpl(ThreadType thread_type,
104 MessagePumpType pump_type_hint) {
105 switch (thread_type) {
106 case ThreadType::kDefault:
107 SetThreadRole("chromium.base.threading.default");
108
109 break;
110
111 case ThreadType::kBackground:
112 SetThreadRole("chromium.base.threading.background");
113 break;
114
115 case ThreadType::kUtility:
116 SetThreadRole("chromium.base.threading.utility");
117 break;
118
119 case ThreadType::kResourceEfficient:
120 SetThreadRole("chromium.base.threading.resource-efficient");
121 break;
122
123 case ThreadType::kCompositing:
124 SetThreadRole("chromium.base.threading.compositing",
125 kDisplaySchedulingPeriod, kDisplaySchedulingCapacity);
126 break;
127
128 case ThreadType::kDisplayCritical:
129 SetThreadRole("chromium.base.threading.display", kDisplaySchedulingPeriod,
130 kDisplaySchedulingCapacity);
131 break;
132
133 case ThreadType::kRealtimeAudio:
134 SetThreadRole("chromium.base.threading.realtime-audio",
135 kAudioSchedulingPeriod, kAudioSchedulingCapacity);
136 break;
137 }
138 }
139
140 } // namespace internal
141
142 // static
GetCurrentThreadPriorityForTest()143 ThreadPriorityForTest PlatformThread::GetCurrentThreadPriorityForTest() {
144 // Fuchsia doesn't provide a way to get the current thread's priority.
145 // Use ThreadType stored in TLS as a proxy.
146 const ThreadType thread_type = PlatformThread::GetCurrentThreadType();
147 switch (thread_type) {
148 case ThreadType::kBackground:
149 case ThreadType::kUtility:
150 case ThreadType::kResourceEfficient:
151 case ThreadType::kDefault:
152 case ThreadType::kCompositing:
153 return ThreadPriorityForTest::kNormal;
154 case ThreadType::kDisplayCritical:
155 return ThreadPriorityForTest::kDisplay;
156 case ThreadType::kRealtimeAudio:
157 return ThreadPriorityForTest::kRealtimeAudio;
158 }
159 }
160
161 } // namespace base
162