1 /**
2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <algorithm>
17 #include <chrono>
18 #include <cstdint>
19 #include <cstdio>
20 #include "libpandabase/os/thread.h"
21 #include "libpandabase/utils/logger.h"
22 #ifdef PANDA_TARGET_OHOS
23 #include "libpandabase/os/mem.h"
24 #endif
25 #ifdef PANDA_TARGET_UNIX
26 #include <fcntl.h>
27 #include <pthread.h>
28 #include <sys/resource.h>
29 #include <sys/syscall.h>
30 #include <csignal>
31 #endif
32 #include <securec.h>
33 #include <unistd.h>
34
35 namespace ark::os::thread {
GetCurrentThreadId()36 ThreadId GetCurrentThreadId()
37 {
38 #if defined(HAVE_GETTID)
39 static_assert(sizeof(decltype(gettid())) == sizeof(ThreadId), "Incorrect alias for ThreadID");
40 return static_cast<ThreadId>(gettid());
41 #elif defined(PANDA_TARGET_MACOS)
42 uint64_t tid64;
43 pthread_threadid_np(NULL, &tid64);
44 return static_cast<ThreadId>(tid64);
45 #else
46 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
47 return static_cast<ThreadId>(syscall(SYS_gettid));
48 #endif
49 }
50
GetPid()51 int GetPid()
52 {
53 return getpid();
54 }
55
GetPPid()56 int GetPPid()
57 {
58 return getppid();
59 }
60
GetUid()61 int GetUid()
62 {
63 return getuid();
64 }
65
GetEuid()66 int GetEuid()
67 {
68 return geteuid();
69 }
70
GetGid()71 uint32_t GetGid()
72 {
73 return getgid();
74 }
75
GetEgid()76 uint32_t GetEgid()
77 {
78 return getegid();
79 }
80
GetGroups()81 std::vector<uint32_t> GetGroups()
82 {
83 int groupCount = getgroups(0, nullptr);
84 if (groupCount == -1) {
85 return {};
86 }
87
88 std::vector<gid_t> groups(groupCount);
89 groupCount = getgroups(groupCount, groups.data());
90 if (groupCount == -1) {
91 return {};
92 }
93
94 groups.resize(groupCount);
95
96 gid_t egid = getegid();
97 if (std::find(groups.begin(), groups.end(), egid) == groups.end()) {
98 groups.push_back(egid);
99 }
100
101 return groups;
102 }
103
SetPriority(int threadId,int prio)104 int SetPriority(int threadId, int prio)
105 {
106 // The priority can be set within range [-20, 19]
107 ASSERT(prio <= 19); // 19: the lowest priority
108 ASSERT(prio >= -20); // -20: the highest priority
109 // The return value is 0 if the function succeeds, and -1 if it fails.
110 return setpriority(PRIO_PROCESS, threadId, prio);
111 }
112
GetPriority(int threadId)113 int GetPriority(int threadId)
114 {
115 return getpriority(PRIO_PROCESS, threadId);
116 }
117
SetThreadName(NativeHandleType pthreadHandle,const char * name)118 int SetThreadName(NativeHandleType pthreadHandle, const char *name)
119 {
120 ASSERT(pthreadHandle != 0);
121 #if defined(PANDA_TARGET_MACOS)
122 return pthread_setname_np(name);
123 #else
124 return pthread_setname_np(pthreadHandle, name);
125 #endif
126 }
127
GetNativeHandle()128 NativeHandleType GetNativeHandle()
129 {
130 return pthread_self();
131 }
132
Yield()133 void Yield()
134 {
135 std::this_thread::yield();
136 }
137
NativeSleep(unsigned int ms)138 void NativeSleep(unsigned int ms)
139 {
140 std::this_thread::sleep_for(std::chrono::milliseconds(ms));
141 }
142
NativeSleepUS(std::chrono::microseconds us)143 void NativeSleepUS(std::chrono::microseconds us)
144 {
145 std::this_thread::sleep_for(us);
146 }
147
ThreadDetach(NativeHandleType pthreadHandle)148 void ThreadDetach(NativeHandleType pthreadHandle)
149 {
150 pthread_detach(pthreadHandle);
151 }
152
ThreadJoin(NativeHandleType pthreadHandle,void ** ret)153 void ThreadJoin(NativeHandleType pthreadHandle, void **ret)
154 {
155 pthread_join(pthreadHandle, ret);
156 }
157
ThreadSendSignal(NativeHandleType pthreadHandle,int sig)158 void ThreadSendSignal(NativeHandleType pthreadHandle, int sig)
159 {
160 LOG_IF(pthread_kill(pthreadHandle, sig) != 0, FATAL, COMMON) << "pthread_kill failed";
161 }
162
ThreadGetStackInfo(NativeHandleType thread,void ** stackAddr,size_t * stackSize,size_t * guardSize)163 int ThreadGetStackInfo(NativeHandleType thread, void **stackAddr, size_t *stackSize, size_t *guardSize)
164 {
165 pthread_attr_t attr;
166 int s = pthread_attr_init(&attr);
167 #ifndef PANDA_TARGET_MACOS
168 s += pthread_getattr_np(thread, &attr);
169 if (s == 0) {
170 s += pthread_attr_getguardsize(&attr, guardSize);
171 s += pthread_attr_getstack(&attr, stackAddr, stackSize);
172 #if defined(PANDA_TARGET_OHOS)
173 if (getpid() == gettid()) {
174 /**
175 * konstanting:
176 * main thread's stack can automatically grow up to the RLIMIT_STACK by means of the OS,
177 * but MUSL does not care about that and returns the current (already mmap-ped) stack size.
178 * This can lead to complicated errors, so let's adjust the stack size manually.
179 */
180 struct rlimit lim;
181 s += getrlimit(RLIMIT_STACK, &lim);
182 if (s == 0) {
183 uintptr_t stackHiAddr = ToUintPtr(*stackAddr) + *stackSize;
184 size_t stackSizeLimit = lim.rlim_cur;
185 // for some reason pthread interfaces subtract 1 page from size regardless of guard size
186 uintptr_t stackLoAddr = stackHiAddr - stackSizeLimit + ark::os::mem::GetPageSize();
187 *stackSize = stackSizeLimit;
188 *stackAddr = ToVoidPtr(stackLoAddr);
189 }
190 }
191 #endif /* defined(PANDA_TARGET_OHOS) */
192 }
193 #else /* PANDA_TARGET_MACOS */
194 s += pthread_attr_getguardsize(&attr, guardSize);
195 s += pthread_attr_getstack(&attr, stackAddr, stackSize);
196 #endif /* PANDA_TARGET_MACOS */
197 s += pthread_attr_destroy(&attr);
198 return s;
199 }
200
201 } // namespace ark::os::thread
202