• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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