xref: /aosp_15_r20/external/cronet/base/threading/platform_thread_fuchsia.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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