1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <pthread.h>
33 #include <time.h>
34 #include <securec.h>
35 #include "los_compiler.h"
36 #include "los_mux.h"
37 #include "errno.h"
38 #include "los_debug.h"
39 #include "los_hook.h"
40 #include "los_sched.h"
41
42 #define MUTEXATTR_TYPE_MASK 0x0FU
43 #define OS_SYS_NS_PER_MSECOND 1000000
44 #define OS_SYS_NS_PER_SECOND 1000000000
45
MapError(UINT32 err)46 static inline int MapError(UINT32 err)
47 {
48 switch (err) {
49 case LOS_OK:
50 return 0;
51 case LOS_ERRNO_MUX_IN_INTERR:
52 return EPERM;
53 case LOS_ERRNO_MUX_PEND_IN_LOCK:
54 return EDEADLK;
55 case LOS_ERRNO_MUX_PENDED:
56 case LOS_ERRNO_MUX_UNAVAILABLE:
57 return EBUSY;
58 case LOS_ERRNO_MUX_TIMEOUT:
59 return ETIMEDOUT;
60 case LOS_ERRNO_MUX_ALL_BUSY:
61 return EAGAIN;
62 case LOS_ERRNO_MUX_INVALID:
63 default:
64 return EINVAL;
65 }
66 }
67
pthread_mutexattr_init(pthread_mutexattr_t * mutexAttr)68 int pthread_mutexattr_init(pthread_mutexattr_t *mutexAttr)
69 {
70 if (mutexAttr == NULL) {
71 return EINVAL;
72 }
73
74 mutexAttr->type = PTHREAD_MUTEX_DEFAULT;
75
76 return 0;
77 }
78
pthread_mutexattr_gettype(const pthread_mutexattr_t * attr,int * outType)79 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *outType)
80 {
81 INT32 type;
82
83 if ((attr == NULL) || (outType == NULL)) {
84 return EINVAL;
85 }
86
87 type = (INT32)(attr->type & MUTEXATTR_TYPE_MASK);
88 if ((type != PTHREAD_MUTEX_NORMAL) &&
89 (type != PTHREAD_MUTEX_RECURSIVE) &&
90 (type != PTHREAD_MUTEX_ERRORCHECK)) {
91 return EINVAL;
92 }
93
94 *outType = type;
95
96 return 0;
97 }
98
pthread_mutexattr_settype(pthread_mutexattr_t * mutexAttr,int type)99 int pthread_mutexattr_settype(pthread_mutexattr_t *mutexAttr, int type)
100 {
101 if (mutexAttr == NULL) {
102 return EINVAL;
103 }
104
105 if (((unsigned)type != PTHREAD_MUTEX_NORMAL) &&
106 ((unsigned)type != PTHREAD_MUTEX_RECURSIVE) &&
107 ((unsigned)type != PTHREAD_MUTEX_ERRORCHECK)) {
108 return EINVAL;
109 }
110 mutexAttr->type = (UINT8)((mutexAttr->type & ~MUTEXATTR_TYPE_MASK) | (UINT32)type);
111
112 return 0;
113 }
114
pthread_mutexattr_destroy(pthread_mutexattr_t * mutexAttr)115 int pthread_mutexattr_destroy(pthread_mutexattr_t *mutexAttr)
116 {
117 if (mutexAttr == NULL) {
118 return EINVAL;
119 }
120
121 (VOID)memset_s(mutexAttr, sizeof(pthread_mutexattr_t), 0, sizeof(pthread_mutexattr_t));
122
123 return 0;
124 }
125
126 /* Initialize mutex. If mutexAttr is NULL, use default attributes. */
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * mutexAttr)127 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexAttr)
128 {
129 pthread_mutexattr_t useAttr;
130 UINT32 muxHandle;
131 UINT32 ret;
132
133 if (mutex == NULL) {
134 return EINVAL;
135 }
136
137 if (mutexAttr == NULL) {
138 (VOID)pthread_mutexattr_init(&useAttr);
139 } else {
140 useAttr = *mutexAttr;
141 }
142
143 ret = LOS_MuxCreate(&muxHandle);
144 if (ret != LOS_OK) {
145 return MapError(ret);
146 }
147
148 mutex->stAttr = useAttr;
149 mutex->magic = _MUX_MAGIC;
150 mutex->handle = muxHandle;
151
152 return 0;
153 }
154
pthread_mutex_destroy(pthread_mutex_t * mutex)155 int pthread_mutex_destroy(pthread_mutex_t *mutex)
156 {
157 UINT32 ret;
158 if ((mutex == NULL) || (mutex->magic != _MUX_MAGIC)) {
159 return EINVAL;
160 }
161 ret = LOS_MuxDelete(mutex->handle);
162 if (ret != LOS_OK) {
163 return MapError(ret);
164 }
165 mutex->handle = _MUX_INVALID_HANDLE;
166 mutex->magic = 0;
167
168 return 0;
169 }
170
CheckMutexAttr(const pthread_mutexattr_t * attr)171 STATIC UINT32 CheckMutexAttr(const pthread_mutexattr_t *attr)
172 {
173 if ((attr->type != PTHREAD_MUTEX_NORMAL) &&
174 (attr->type != PTHREAD_MUTEX_RECURSIVE) &&
175 (attr->type != PTHREAD_MUTEX_ERRORCHECK)) {
176 return LOS_NOK;
177 }
178
179 return LOS_OK;
180 }
181
MuxPreCheck(const pthread_mutex_t * mutex,const LosTaskCB * runTask)182 STATIC UINT32 MuxPreCheck(const pthread_mutex_t *mutex, const LosTaskCB *runTask)
183 {
184 if ((mutex == NULL) || (mutex->magic != _MUX_MAGIC) ||
185 ((mutex->handle != _MUX_INVALID_HANDLE) && (mutex->handle >= (UINT32)LOSCFG_BASE_IPC_MUX_LIMIT))) {
186 return EINVAL;
187 }
188
189 if (OS_INT_ACTIVE) {
190 return EPERM;
191 }
192 /* DO NOT recommend to use blocking API in system tasks */
193 if ((runTask != NULL) && (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK)) {
194 PRINT_DEBUG("Warning: DO NOT recommend to use %s in system tasks.\n", __FUNCTION__);
195 }
196
197 if (CheckMutexAttr(&mutex->stAttr) != LOS_OK) {
198 return EINVAL;
199 }
200
201 return 0;
202 }
203
MuxPendForPosix(pthread_mutex_t * mutex,UINT32 timeout)204 STATIC UINT32 MuxPendForPosix(pthread_mutex_t *mutex, UINT32 timeout)
205 {
206 UINT32 intSave;
207 LosMuxCB *muxPended = NULL;
208 UINT32 retErr;
209 LosTaskCB *runningTask = NULL;
210 UINT32 muxHandle = mutex->handle;
211
212 muxPended = GET_MUX(muxHandle);
213 intSave = LOS_IntLock();
214
215 if (muxPended->muxStat == OS_MUX_UNUSED) {
216 LOS_IntRestore(intSave);
217 OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID);
218 }
219
220 runningTask = (LosTaskCB *)g_losTask.runTask;
221 if (muxPended->muxCount == 0) {
222 muxPended->muxCount++;
223 muxPended->owner = runningTask;
224 muxPended->priority = runningTask->priority;
225 LOS_IntRestore(intSave);
226 OsHookCall(LOS_HOOK_TYPE_MUX_PEND, muxPended, timeout);
227 return LOS_OK;
228 }
229
230 if ((muxPended->owner == runningTask) && (mutex->stAttr.type == PTHREAD_MUTEX_RECURSIVE)) {
231 muxPended->muxCount++;
232 LOS_IntRestore(intSave);
233 OsHookCall(LOS_HOOK_TYPE_MUX_PEND, muxPended, timeout);
234 return LOS_OK;
235 }
236
237 if (!timeout) {
238 LOS_IntRestore(intSave);
239 OS_RETURN_ERROR(LOS_ERRNO_MUX_UNAVAILABLE);
240 }
241
242 runningTask->taskMux = (VOID *)muxPended;
243
244 if (muxPended->owner->priority > runningTask->priority) {
245 (VOID)OsSchedModifyTaskSchedParam(muxPended->owner, runningTask->priority);
246 }
247
248 OsSchedTaskWait(&muxPended->muxList, timeout);
249
250 LOS_IntRestore(intSave);
251 OsHookCall(LOS_HOOK_TYPE_MUX_PEND, muxPended, timeout);
252 LOS_Schedule();
253
254 intSave = LOS_IntLock();
255 if (runningTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {
256 runningTask->taskStatus &= (~OS_TASK_STATUS_TIMEOUT);
257 retErr = LOS_ERRNO_MUX_TIMEOUT;
258 LOS_IntRestore(intSave);
259 OS_RETURN_ERROR(retErr);
260 }
261
262 LOS_IntRestore(intSave);
263 return LOS_OK;
264 }
265
MuxPostForPosix(pthread_mutex_t * mutex)266 STATIC UINT32 MuxPostForPosix(pthread_mutex_t *mutex)
267 {
268 UINT32 intSave;
269 LosMuxCB *muxPosted = NULL;
270 LosTaskCB *resumedTask = NULL;
271 LosTaskCB *runningTask = NULL;
272 UINT32 muxHandle = mutex->handle;
273
274 muxPosted = GET_MUX(muxHandle);
275 intSave = LOS_IntLock();
276
277 if (muxPosted->muxStat == OS_MUX_UNUSED) {
278 LOS_IntRestore(intSave);
279 OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID);
280 }
281
282 runningTask = (LosTaskCB *)g_losTask.runTask;
283 if ((muxPosted->muxCount == 0) || (muxPosted->owner != runningTask)) {
284 LOS_IntRestore(intSave);
285 OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID);
286 }
287
288 if ((--(muxPosted->muxCount) != 0) && (mutex->stAttr.type == PTHREAD_MUTEX_RECURSIVE)) {
289 LOS_IntRestore(intSave);
290 OsHookCall(LOS_HOOK_TYPE_MUX_POST, muxPosted);
291 return LOS_OK;
292 }
293
294 if ((muxPosted->owner->priority) != muxPosted->priority) {
295 (VOID)OsSchedModifyTaskSchedParam(muxPosted->owner, muxPosted->priority);
296 }
297
298 if (!LOS_ListEmpty(&muxPosted->muxList)) {
299 resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(muxPosted->muxList)));
300
301 muxPosted->muxCount = 1;
302 muxPosted->owner = resumedTask;
303 muxPosted->priority = resumedTask->priority;
304 resumedTask->taskMux = NULL;
305
306 OsSchedTaskWake(resumedTask);
307
308 LOS_IntRestore(intSave);
309 OsHookCall(LOS_HOOK_TYPE_MUX_POST, muxPosted);
310 LOS_Schedule();
311 } else {
312 muxPosted->owner = NULL;
313 LOS_IntRestore(intSave);
314 }
315
316 return LOS_OK;
317 }
318
pthread_mutex_timedlock(pthread_mutex_t * mutex,const struct timespec * absTimeout)319 int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *absTimeout)
320 {
321 UINT32 ret;
322 UINT32 timeout;
323 UINT64 timeoutNs;
324 struct timespec curTime = {0};
325 LosMuxCB *muxPended = NULL;
326
327 ret = MuxPreCheck(mutex, OS_TCB_FROM_TID(LOS_CurTaskIDGet()));
328 if (ret != 0) {
329 return (INT32)ret;
330 }
331
332 if ((absTimeout == NULL) || (absTimeout->tv_nsec < 0) || (absTimeout->tv_nsec >= OS_SYS_NS_PER_SECOND)) {
333 return EINVAL;
334 }
335 if (mutex->handle == _MUX_INVALID_HANDLE) {
336 ret = LOS_MuxCreate(&mutex->handle);
337 if (ret != LOS_OK) {
338 return MapError(ret);
339 }
340 } else {
341 muxPended = GET_MUX(mutex->handle);
342 if ((mutex->stAttr.type == PTHREAD_MUTEX_ERRORCHECK) &&
343 (muxPended->muxCount != 0) &&
344 (muxPended->owner == OS_TCB_FROM_TID(LOS_CurTaskIDGet()))) {
345 return EDEADLK;
346 }
347 }
348 ret = clock_gettime(CLOCK_REALTIME, &curTime);
349 if (ret != LOS_OK) {
350 return EINVAL;
351 }
352 timeoutNs = (absTimeout->tv_sec - curTime.tv_sec) * OS_SYS_NS_PER_SECOND + (absTimeout->tv_nsec - curTime.tv_nsec);
353 if (timeoutNs <= 0) {
354 return ETIMEDOUT;
355 }
356 timeout = (timeoutNs + (OS_SYS_NS_PER_MSECOND - 1)) / OS_SYS_NS_PER_MSECOND;
357 ret = MuxPendForPosix(mutex, timeout);
358
359 return MapError(ret);
360 }
361
362 /* Lock mutex, waiting for it if necessary. */
pthread_mutex_lock(pthread_mutex_t * mutex)363 int pthread_mutex_lock(pthread_mutex_t *mutex)
364 {
365 UINT32 ret;
366 LosMuxCB *muxPended = NULL;
367 LosTaskCB *runTask = OS_TCB_FROM_TID(LOS_CurTaskIDGet());
368
369 ret = MuxPreCheck(mutex, runTask);
370 if (ret != 0) {
371 return (INT32)ret;
372 }
373
374 if (mutex->handle == _MUX_INVALID_HANDLE) {
375 ret = LOS_MuxCreate(&mutex->handle);
376 if (ret != LOS_OK) {
377 return MapError(ret);
378 }
379 } else {
380 muxPended = GET_MUX(mutex->handle);
381 if ((mutex->stAttr.type == PTHREAD_MUTEX_ERRORCHECK) &&
382 (muxPended->muxCount != 0) &&
383 (muxPended->owner == runTask)) {
384 return EDEADLK;
385 }
386 }
387 ret = MuxPendForPosix(mutex, LOS_WAIT_FOREVER);
388
389 return MapError(ret);
390 }
391
pthread_mutex_trylock(pthread_mutex_t * mutex)392 int pthread_mutex_trylock(pthread_mutex_t *mutex)
393 {
394 UINT32 ret;
395 LosMuxCB *muxPended = NULL;
396
397 ret = MuxPreCheck(mutex, OS_TCB_FROM_TID(LOS_CurTaskIDGet()));
398 if (ret != 0) {
399 return (INT32)ret;
400 }
401
402 if (mutex->handle == _MUX_INVALID_HANDLE) {
403 ret = LOS_MuxCreate(&mutex->handle);
404 if (ret != LOS_OK) {
405 return MapError(ret);
406 }
407 } else {
408 muxPended = GET_MUX(mutex->handle);
409 if ((mutex->stAttr.type != PTHREAD_MUTEX_RECURSIVE) && (muxPended->muxCount != 0)) {
410 return EBUSY;
411 }
412 }
413 ret = MuxPendForPosix(mutex, 0);
414
415 return MapError(ret);
416 }
417
pthread_mutex_unlock(pthread_mutex_t * mutex)418 int pthread_mutex_unlock(pthread_mutex_t *mutex)
419 {
420 UINT32 ret;
421 ret = MuxPreCheck(mutex, OS_TCB_FROM_TID(LOS_CurTaskIDGet()));
422 if (ret != 0) {
423 return (INT32)ret;
424 }
425
426 if (mutex->handle == _MUX_INVALID_HANDLE) {
427 return EINVAL;
428 }
429
430 ret = MuxPostForPosix(mutex);
431
432 return MapError(ret);
433 }
434
435