1 /*
2 * Copyright (c) 2023 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 "hwe_osdep.h"
17
18 #if defined(_WIN32)
19 #include "securec.h"
20 #endif
21
22 #define ID_AA64PFR0_ADVSIMD_BIT 20
23 #define MVFR1_ADVSIMD_BIT 8
24
25 namespace OHOS {
26 namespace ImagePlugin {
27 // detect cpu simd capibility
HWE_DetectSimdCapibility(void)28 HWE_KernelType HWE_DetectSimdCapibility(void)
29 {
30 HWE_KernelType ret = KERNEL_TYPE_C;
31 #if HWE_ARM_AARCH64
32 uint64_t regval = 0;
33 uint64_t advSimd;
34
35 asm volatile("mrs %0, ID_AA64PFR0_EL1" : "=r"(regval));
36 advSimd = (regval >> ID_AA64PFR0_ADVSIMD_BIT) & 0xf; // 0xf: bitmask
37 if (advSimd == 0x0 || advSimd == 0x1) { // 0x0: support neon without fp16; 0x1: support neno with fp16
38 ret = KERNEL_TYPE_NEON;
39 } else {
40 ret = KERNEL_TYPE_C;
41 }
42 #elif HWE_ARM_AARCH32
43 #if !HWE_IANDROID_ARM
44 uint32_t regval = 0;
45 uint32_t advSimd;
46
47 asm volatile("mrs %0, MVFR1" : "=r"(regval));
48 advSimd = (regval >> MVFR1_ADVSIMD_BIT) & 0xfff; // 0xff: bitmask
49 if (advSimd == 0x111) { // 0x111: support neon
50 ret = KERNEL_TYPE_NEON;
51 } else {
52 ret = KERNEL_TYPE_C;
53 }
54 #else
55 ret = KERNEL_TYPE_NEON;
56 #endif
57 #elif HWE_X86_64
58 ret = KERNEL_TYPE_AVX2;
59 #elif HWE_X86_32
60 ret = KERNEL_TYPE_C;
61 #endif
62 return ret;
63 }
64
65 #ifdef _WIN32
66 static HWE_Win32ThreadControl g_threadPool;
67
HWE_PthreadMutexInit(HWE_PthreadMutex * mutex)68 int32_t HWE_PthreadMutexInit(HWE_PthreadMutex *mutex)
69 {
70 return !InitializeCriticalSectionAndSpinCount(mutex, HWE_SPIN_COUNT);
71 }
72
HWE_PthreadMutexLock(HWE_PthreadMutex * mutex)73 int32_t HWE_PthreadMutexLock(HWE_PthreadMutex *mutex)
74 {
75 static HWE_PthreadMutex init = HWE_PTHREAD_MUTEX_INITIALIZER;
76 if (!memcmp(mutex, &init, sizeof(HWE_PthreadMutex))) {
77 *mutex = g_threadPool.staticMutex;
78 }
79 EnterCriticalSection(mutex);
80 return 0;
81 }
82
HWE_PthreadMutexUnLock(HWE_PthreadMutex * mutex)83 int32_t HWE_PthreadMutexUnLock(HWE_PthreadMutex *mutex)
84 {
85 LeaveCriticalSection(mutex);
86 return 0;
87 }
88
HWE_PthreadMutexDestroy(HWE_PthreadMutex * mutex)89 int32_t HWE_PthreadMutexDestroy(HWE_PthreadMutex *mutex)
90 {
91 LeaveCriticalSection(mutex);
92 return 0;
93 }
94
HWE_PthreadCondInit(HWE_PthreadCond * cond)95 int32_t HWE_PthreadCondInit(HWE_PthreadCond *cond)
96 {
97 HWE_Win32Cond *win32Cond = nullptr;
98 if (g_threadPool.condInit) {
99 g_threadPool.condInit(cond);
100 return 0;
101 }
102 win32Cond = (HWE_Win32Cond *)calloc(1, sizeof(HWE_Win32Cond));
103 if (!win32Cond) {
104 return -1;
105 }
106 cond->ptr = win32Cond;
107 win32Cond->semaphore = CreateSemaphore(nullptr, 0, 0x7fffffff, nullptr);
108 if (!win32Cond->semaphore) {
109 return -1;
110 }
111 if (HWE_PthreadMutexInit(&win32Cond->mtxWaiterCount)) {
112 return -1;
113 }
114 if (HWE_PthreadMutexInit(&win32Cond->mtxBroadcast)) {
115 return -1;
116 }
117 win32Cond->waitersDone = CreateEvent(nullptr, FALSE, FALSE, nullptr);
118 if (!win32Cond->waitersDone) {
119 return -1;
120 }
121 return 0;
122 }
123
HWE_PthreadCondDestroy(HWE_PthreadCond * cond)124 int32_t HWE_PthreadCondDestroy(HWE_PthreadCond *cond)
125 {
126 HWE_Win32Cond *win32Cond = nullptr;
127 if (g_threadPool.condInit) {
128 return 0;
129 }
130 win32Cond = (HWE_Win32Cond *)cond->ptr;
131 CloseHandle(win32Cond->semaphore);
132 CloseHandle(win32Cond->waitersDone);
133 HWE_PthreadMutexDestroy(&win32Cond->mtxBroadcast);
134 HWE_PthreadMutexDestroy(&win32Cond->mtxWaiterCount);
135 free(win32Cond);
136 return 0;
137 }
138
HWE_PthreadCondWait(HWE_PthreadCond * cond,HWE_PthreadMutex * mutex)139 int32_t HWE_PthreadCondWait(HWE_PthreadCond *cond, HWE_PthreadMutex *mutex)
140 {
141 HWE_Win32Cond *win32Cond = nullptr;
142 int32_t iLastWaiter;
143 if (g_threadPool.condWait) {
144 return !g_threadPool.condWait(cond, mutex, INFINITE);
145 }
146 win32Cond = (HWE_Win32Cond *)cond->ptr;
147 (VOID)HWE_PthreadMutexLock(&win32Cond->mtxBroadcast);
148 (VOID)HWE_PthreadMutexLock(&win32Cond->mtxWaiterCount);
149 win32Cond->waiterCount++;
150 (VOID)HWE_PthreadMutexUnLock(&win32Cond->mtxWaiterCount);
151 (VOID)HWE_PthreadMutexUnLock(&win32Cond->mtxBroadcast);
152 (VOID)HWE_PthreadMutexUnLock(mutex);
153 WaitForSingleObject(win32Cond->semaphore, INFINITE);
154 (VOID)HWE_PthreadMutexLock(&win32Cond->mtxWaiterCount);
155 win32Cond->waiterCount--;
156 iLastWaiter = !win32Cond->waiterCount || !win32Cond->isBroadcast;
157 (VOID)HWE_PthreadMutexUnLock(&win32Cond->mtxWaiterCount);
158 if (iLastWaiter) {
159 SetEvent(win32Cond->waitersDone);
160 }
161 return HWE_PthreadMutexLock(mutex);
162 }
163
HWE_PthreadCondSignal(HWE_PthreadCond * cond)164 int32_t HWE_PthreadCondSignal(HWE_PthreadCond *cond)
165 {
166 HWE_Win32Cond *win32Cond = nullptr;
167 int32_t haveWaiter;
168 if (g_threadPool.condSignal) {
169 g_threadPool.condSignal(cond);
170 return 0;
171 }
172 win32Cond = (HWE_Win32Cond *)cond->ptr;
173 (VOID)HWE_PthreadMutexLock(&win32Cond->mtxBroadcast);
174 (VOID)HWE_PthreadMutexLock(&win32Cond->mtxWaiterCount);
175 haveWaiter = win32Cond->waiterCount;
176 (VOID)HWE_PthreadMutexUnLock(&win32Cond->mtxWaiterCount);
177 if (haveWaiter) {
178 ReleaseSemaphore(win32Cond->semaphore, 1, nullptr);
179 WaitForSingleObject(win32Cond->waitersDone, INFINITE);
180 }
181 return HWE_PthreadMutexUnLock(&win32Cond->mtxBroadcast);
182 }
183
HWE_PthreadCondBroadcast(HWE_PthreadCond * cond)184 int32_t HWE_PthreadCondBroadcast(HWE_PthreadCond *cond)
185 {
186 HWE_Win32Cond *win32Cond = nullptr;
187 int32_t haveWaiter = 0;
188 if (g_threadPool.condBroadcast) {
189 g_threadPool.condBroadcast(cond);
190 return 0;
191 }
192 win32Cond = (HWE_Win32Cond *)cond->ptr;
193 (VOID)HWE_PthreadMutexLock(&win32Cond->mtxBroadcast);
194 (VOID)HWE_PthreadMutexLock(&win32Cond->mtxWaiterCount);
195 if (win32Cond->waiterCount) {
196 win32Cond->isBroadcast = 1;
197 haveWaiter = 1;
198 }
199 if (haveWaiter) {
200 ReleaseSemaphore(win32Cond->semaphore, win32Cond->waiterCount, nullptr);
201 (VOID)HWE_PthreadMutexUnLock(&win32Cond->mtxWaiterCount);
202 WaitForSingleObject(win32Cond->waitersDone, INFINITE);
203 win32Cond->isBroadcast = 0;
204 } else {
205 (VOID)HWE_PthreadMutexUnLock(&win32Cond->mtxWaiterCount);
206 }
207 return HWE_PthreadMutexUnLock(&win32Cond->mtxBroadcast);
208 }
209
HWE_Win32ThreadWorker(void * arg)210 static unsigned __stdcall HWE_Win32ThreadWorker(void *arg)
211 {
212 HWE_Pthread *enc = (HWE_Pthread *)arg;
213 enc->ret = enc->func(enc->arg);
214 return 0;
215 }
216
HWE_PthreadJoin(HWE_Pthread thread)217 int32_t HWE_PthreadJoin(HWE_Pthread thread)
218 {
219 if (thread.isInit == 1) {
220 DWORD pRet = WaitForSingleObject(thread.handle, INFINITE);
221 if (pRet != WAIT_OBJECT_0) {
222 return -1;
223 }
224 CloseHandle(thread.handle);
225 }
226 return 0;
227 }
228 #endif
229
230 #if !HWE_IANDROID_ARM
HWE_SetThreadAffinityMask(const HWE_Pthread * thread,uint32_t cpuNum,const uint32_t * cpuIdxArray)231 int32_t HWE_SetThreadAffinityMask(const HWE_Pthread *thread, uint32_t cpuNum, const uint32_t *cpuIdxArray)
232 {
233 if (cpuNum == 0) {
234 return 0;
235 }
236 if (thread->isInit) {
237 #if defined(_WIN32)
238 DWORD_PTR threadAffinityMask;
239 if (memset_s((void *)&threadAffinityMask, sizeof(DWORD_PTR), 0, sizeof(DWORD_PTR)) != 0) {
240 return -1;
241 }
242 for (uint32_t idx = 0; idx < cpuNum; idx++) {
243 threadAffinityMask |= (1 << cpuIdxArray[idx]);
244 }
245 int32_t ret = SetThreadAffinityMask(thread->handle, threadAffinityMask);
246 return (ret == 0);
247 #elif defined(__GNUC__)
248 cpu_set_t threadAffinityMask;
249 CPU_ZERO(&threadAffinityMask);
250 for (uint32_t idx = 0; idx < cpuNum; idx++) {
251 CPU_SET(cpuIdxArray[idx], &threadAffinityMask);
252 }
253 #ifdef A_PLATFORM
254 return sched_setaffinity(thread->thread, sizeof(threadAffinityMask), &threadAffinityMask);
255 #else
256 return pthread_setaffinity_np(thread->thread, sizeof(threadAffinityMask), &threadAffinityMask);
257 #endif
258 #else
259 return 0;
260 #endif
261 } else {
262 return -1;
263 }
264 }
265
HWE_SetThreadPriority(const HWE_Pthread * thread,int32_t schedPriority)266 int32_t HWE_SetThreadPriority(const HWE_Pthread *thread, int32_t schedPriority)
267 {
268 if (thread->isInit) {
269 #if defined(_WIN32)
270 return (SetThreadPriority(thread->handle, schedPriority) == 0);
271 #elif defined(__GNUC__)
272 struct sched_param threadParam;
273 threadParam.sched_priority = schedPriority;
274 if (threadParam.sched_priority <= 0) {
275 return pthread_setschedparam(thread->thread, SCHED_OTHER, &threadParam);
276 } else {
277 return pthread_setschedparam(thread->thread, SCHED_RR, &threadParam);
278 }
279 #else
280 return 0;
281 #endif
282 } else {
283 return -1;
284 }
285 }
286 #endif
287 } // namespace ImagePlugin
288 } // namespace OHOS