1 /**
2 * Copyright (c) 2021-2022 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 "os/thread.h"
17 #include "os/mem.h"
18
19 #include "utils/span.h"
20 #include "utils/logger.h"
21
22 #include <chrono>
23 #include <cstdio>
24
25 #include <array>
26 #include <cstdint>
27 #include "os/failure_retry.h"
28 #ifdef PANDA_TARGET_UNIX
29 #include <fcntl.h>
30 #include <pthread.h>
31 #include <sys/resource.h>
32 #include <sys/syscall.h>
33 #include <csignal>
34 #endif
35 #include <securec.h>
36 #include <unistd.h>
37
38 namespace panda::os::thread {
39
GetCurrentThreadId()40 ThreadId GetCurrentThreadId()
41 {
42 #if defined(HAVE_GETTID)
43 static_assert(sizeof(decltype(gettid())) == sizeof(ThreadId), "Incorrect alias for ThreadID");
44 return static_cast<ThreadId>(gettid());
45 #elif defined(PANDA_TARGET_MACOS)
46 uint64_t tid64;
47 pthread_threadid_np(NULL, &tid64);
48 return static_cast<ThreadId>(tid64);
49 #else
50 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
51 return static_cast<ThreadId>(syscall(SYS_gettid));
52 #endif
53 }
54
GetPid()55 int GetPid()
56 {
57 return getpid();
58 }
59
SetPriority(int threadId,int prio)60 int SetPriority(int threadId, int prio)
61 {
62 // The priority can be set within range [-20, 19]
63 ASSERT(prio <= 19); // 19: the lowest priority
64 ASSERT(prio >= -20); // -20: the highest priority
65 // The return value is 0 if the function succeeds, and -1 if it fails.
66 return setpriority(PRIO_PROCESS, threadId, prio);
67 }
68
GetPriority(int threadId)69 int GetPriority(int threadId)
70 {
71 return getpriority(PRIO_PROCESS, threadId);
72 }
73
SetThreadName(NativeHandleType pthreadHandle,const char * name)74 int SetThreadName(NativeHandleType pthreadHandle, const char *name)
75 {
76 ASSERT(pthreadHandle != 0);
77 #if defined(PANDA_TARGET_MACOS)
78 return pthread_setname_np(name);
79 #else
80 return pthread_setname_np(pthreadHandle, name);
81 #endif
82 }
83
GetNativeHandle()84 NativeHandleType GetNativeHandle()
85 {
86 return pthread_self();
87 }
88
Yield()89 void Yield()
90 {
91 std::this_thread::yield();
92 }
93
NativeSleep(unsigned int ms)94 void NativeSleep(unsigned int ms)
95 {
96 std::this_thread::sleep_for(std::chrono::milliseconds(ms));
97 }
98
NativeSleepUS(std::chrono::microseconds us)99 void NativeSleepUS(std::chrono::microseconds us)
100 {
101 std::this_thread::sleep_for(us);
102 }
103
ThreadDetach(NativeHandleType pthreadHandle)104 void ThreadDetach(NativeHandleType pthreadHandle)
105 {
106 pthread_detach(pthreadHandle);
107 }
108
ThreadExit(void * ret)109 void ThreadExit(void *ret)
110 {
111 pthread_exit(ret);
112 }
113
ThreadJoin(NativeHandleType pthreadHandle,void ** ret)114 void ThreadJoin(NativeHandleType pthreadHandle, void **ret)
115 {
116 pthread_join(pthreadHandle, ret);
117 }
118
ThreadSendSignal(NativeHandleType pthreadHandle,int sig)119 void ThreadSendSignal(NativeHandleType pthreadHandle, int sig)
120 {
121 LOG_IF(pthread_kill(pthreadHandle, sig) != 0, FATAL, COMMON) << "pthread_kill failed";
122 }
123
ThreadGetStackInfo(NativeHandleType thread,void ** stackAddr,size_t * stackSize,size_t * guardSize)124 int ThreadGetStackInfo(NativeHandleType thread, void **stackAddr, size_t *stackSize, size_t *guardSize)
125 {
126 pthread_attr_t attr;
127 int s = pthread_attr_init(&attr);
128 #ifndef PANDA_TARGET_MACOS
129 s += pthread_getattr_np(thread, &attr);
130 if (s == 0) {
131 s += pthread_attr_getguardsize(&attr, guardSize);
132 s += pthread_attr_getstack(&attr, stackAddr, stackSize);
133 #if defined(PANDA_TARGET_OHOS) && !defined(NDEBUG)
134 if (getpid() == gettid()) {
135 /**
136 * konstanting:
137 * main thread's stack can automatically grow up to the RLIMIT_STACK by means of the OS,
138 * but MUSL does not care about that and returns the current (already mmap-ped) stack size.
139 * This can lead to complicated errors, so let's adjust the stack size manually.
140 */
141 struct rlimit lim;
142 s += getrlimit(RLIMIT_STACK, &lim);
143 if (s == 0) {
144 uintptr_t stackHiAddr = ToUintPtr(*stackAddr) + *stackSize;
145 size_t stackSizeLimit = lim.rlim_cur;
146 // for some reason pthread interfaces subtract 1 page from size regardless of guard size
147 uintptr_t stackLoAddr = stackHiAddr - stackSizeLimit + panda::os::mem::GetPageSize();
148 *stackSize = stackSizeLimit;
149 *stackAddr = ToVoidPtr(stackLoAddr);
150 }
151 }
152 #endif /* defined(PANDA_TARGET_OHOS) && !defined(NDEBUG) */
153 }
154 #else /* PANDA_TARGET_MACOS */
155 s += pthread_attr_getguardsize(&attr, guardSize);
156 s += pthread_attr_getstack(&attr, stackAddr, stackSize);
157 #endif /* PANDA_TARGET_MACOS */
158 s += pthread_attr_destroy(&attr);
159 return s;
160 }
161
162 } // namespace panda::os::thread
163