• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #if (LOSCFG_MUTEX_CREATE_TRACE == 1)
42 #include "los_arch.h"
43 #endif
44 
45 #define MUTEXATTR_TYPE_MASK   0x0FU
46 #define OS_SYS_NS_PER_MSECOND 1000000
47 #define OS_SYS_NS_PER_SECOND  1000000000
48 
MapError(UINT32 err)49 static inline int MapError(UINT32 err)
50 {
51     switch (err) {
52         case LOS_OK:
53             return 0;
54         case LOS_ERRNO_MUX_IN_INTERR:
55             return EPERM;
56         case LOS_ERRNO_MUX_PEND_IN_LOCK:
57             return EDEADLK;
58         case LOS_ERRNO_MUX_PENDED:
59         case LOS_ERRNO_MUX_UNAVAILABLE:
60             return EBUSY;
61         case LOS_ERRNO_MUX_TIMEOUT:
62             return ETIMEDOUT;
63         case LOS_ERRNO_MUX_ALL_BUSY:
64             return EAGAIN;
65         case LOS_ERRNO_MUX_INVALID:
66         default:
67             return EINVAL;
68     }
69 }
70 
pthread_mutexattr_init(pthread_mutexattr_t * mutexAttr)71 int pthread_mutexattr_init(pthread_mutexattr_t *mutexAttr)
72 {
73     if (mutexAttr == NULL) {
74         return EINVAL;
75     }
76 
77     mutexAttr->type = PTHREAD_MUTEX_DEFAULT;
78 
79     return 0;
80 }
81 
pthread_mutexattr_gettype(const pthread_mutexattr_t * attr,int * outType)82 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *outType)
83 {
84     INT32 type;
85 
86     if ((attr == NULL) || (outType == NULL)) {
87         return EINVAL;
88     }
89 
90     type = (INT32)(attr->type & MUTEXATTR_TYPE_MASK);
91     if ((type != PTHREAD_MUTEX_NORMAL) &&
92         (type != PTHREAD_MUTEX_RECURSIVE) &&
93         (type != PTHREAD_MUTEX_ERRORCHECK)) {
94         return EINVAL;
95     }
96 
97     *outType = type;
98 
99     return 0;
100 }
101 
pthread_mutexattr_settype(pthread_mutexattr_t * mutexAttr,int type)102 int pthread_mutexattr_settype(pthread_mutexattr_t *mutexAttr, int type)
103 {
104     if (mutexAttr == NULL) {
105         return EINVAL;
106     }
107 
108     if (((unsigned)type != PTHREAD_MUTEX_NORMAL) &&
109         ((unsigned)type != PTHREAD_MUTEX_RECURSIVE) &&
110         ((unsigned)type != PTHREAD_MUTEX_ERRORCHECK)) {
111         return EINVAL;
112     }
113     mutexAttr->type = (UINT8)((mutexAttr->type & ~MUTEXATTR_TYPE_MASK) | (UINT32)type);
114 
115     return 0;
116 }
117 
pthread_mutexattr_destroy(pthread_mutexattr_t * mutexAttr)118 int pthread_mutexattr_destroy(pthread_mutexattr_t *mutexAttr)
119 {
120     if (mutexAttr == NULL) {
121         return EINVAL;
122     }
123 
124     (VOID)memset_s(mutexAttr, sizeof(pthread_mutexattr_t), 0, sizeof(pthread_mutexattr_t));
125 
126     return 0;
127 }
128 
129 /* Initialize mutex. If mutexAttr is NULL, use default attributes. */
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * mutexAttr)130 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexAttr)
131 {
132     pthread_mutexattr_t useAttr;
133     UINT32 muxHandle;
134     UINT32 ret;
135 
136 #if (LOSCFG_MUTEX_CREATE_TRACE == 1)
137     UINTPTR regLR = ArchLRGet();
138 #endif
139 
140     if (mutex == NULL) {
141         return EINVAL;
142     }
143 
144     if (mutexAttr == NULL) {
145         (VOID)pthread_mutexattr_init(&useAttr);
146     } else {
147         useAttr = *mutexAttr;
148     }
149 
150     ret = LOS_MuxCreate(&muxHandle);
151     if (ret != LOS_OK) {
152         return MapError(ret);
153     }
154 
155     mutex->stAttr = useAttr;
156     mutex->magic = _MUX_MAGIC;
157     mutex->handle = muxHandle;
158 #if (LOSCFG_MUTEX_CREATE_TRACE == 1)
159     OsSetMutexCreateInfo(GET_MUX(mutex->handle), regLR);
160 #endif
161 
162     return 0;
163 }
164 
pthread_mutex_destroy(pthread_mutex_t * mutex)165 int pthread_mutex_destroy(pthread_mutex_t *mutex)
166 {
167     UINT32 ret;
168     if ((mutex == NULL) || (mutex->magic != _MUX_MAGIC)) {
169         return EINVAL;
170     }
171     ret = LOS_MuxDelete(mutex->handle);
172     if (ret != LOS_OK) {
173         return MapError(ret);
174     }
175     mutex->handle = _MUX_INVALID_HANDLE;
176     mutex->magic = 0;
177 
178     return 0;
179 }
180 
CheckMutexAttr(const pthread_mutexattr_t * attr)181 STATIC UINT32 CheckMutexAttr(const pthread_mutexattr_t *attr)
182 {
183     if ((attr->type != PTHREAD_MUTEX_NORMAL) &&
184         (attr->type != PTHREAD_MUTEX_RECURSIVE) &&
185         (attr->type != PTHREAD_MUTEX_ERRORCHECK)) {
186         return LOS_NOK;
187     }
188 
189     return LOS_OK;
190 }
191 
MuxPreCheck(const pthread_mutex_t * mutex,const LosTaskCB * runTask)192 STATIC UINT32 MuxPreCheck(const pthread_mutex_t *mutex, const LosTaskCB *runTask)
193 {
194     if ((mutex == NULL) || (mutex->magic != _MUX_MAGIC) ||
195         ((mutex->handle != _MUX_INVALID_HANDLE) && (mutex->handle >= (UINT32)LOSCFG_BASE_IPC_MUX_LIMIT))) {
196         return EINVAL;
197     }
198 
199     if (OS_INT_ACTIVE) {
200         return EPERM;
201     }
202     /* DO NOT recommend to use blocking API in system tasks */
203     if ((runTask != NULL) && (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK)) {
204         PRINT_DEBUG("Warning: DO NOT recommend to use %s in system tasks.\n", __FUNCTION__);
205     }
206 
207     if (CheckMutexAttr(&mutex->stAttr) != LOS_OK) {
208         return EINVAL;
209     }
210 
211     return 0;
212 }
213 
MuxPendForPosix(pthread_mutex_t * mutex,UINT32 timeout)214 STATIC UINT32 MuxPendForPosix(pthread_mutex_t *mutex, UINT32 timeout)
215 {
216     UINT32 intSave;
217     LosMuxCB *muxPended = NULL;
218     UINT32 retErr;
219     LosTaskCB *runningTask = NULL;
220     UINT32 muxHandle = mutex->handle;
221 
222     muxPended = GET_MUX(muxHandle);
223     intSave = LOS_IntLock();
224 
225     if (muxPended->muxStat == OS_MUX_UNUSED) {
226         LOS_IntRestore(intSave);
227         OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID);
228     }
229 
230     runningTask = (LosTaskCB *)g_losTask.runTask;
231     if (muxPended->muxCount == 0) {
232         muxPended->muxCount++;
233         muxPended->owner = runningTask;
234         muxPended->priority = runningTask->priority;
235         LOS_IntRestore(intSave);
236         OsHookCall(LOS_HOOK_TYPE_MUX_PEND, muxPended, timeout);
237         return LOS_OK;
238     }
239 
240     if ((muxPended->owner == runningTask) && (mutex->stAttr.type == PTHREAD_MUTEX_RECURSIVE)) {
241         muxPended->muxCount++;
242         LOS_IntRestore(intSave);
243         OsHookCall(LOS_HOOK_TYPE_MUX_PEND, muxPended, timeout);
244         return LOS_OK;
245     }
246 
247     if (!timeout) {
248         LOS_IntRestore(intSave);
249         OS_RETURN_ERROR(LOS_ERRNO_MUX_UNAVAILABLE);
250     }
251 
252     runningTask->taskMux = (VOID *)muxPended;
253 
254     if (muxPended->owner->priority > runningTask->priority) {
255         (VOID)OsSchedModifyTaskSchedParam(muxPended->owner, runningTask->priority);
256     }
257 
258     OsSchedTaskWait(&muxPended->muxList, timeout);
259 
260     LOS_IntRestore(intSave);
261     OsHookCall(LOS_HOOK_TYPE_MUX_PEND, muxPended, timeout);
262     LOS_Schedule();
263 
264     intSave = LOS_IntLock();
265     if (runningTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {
266         runningTask->taskStatus &= (~OS_TASK_STATUS_TIMEOUT);
267         retErr = LOS_ERRNO_MUX_TIMEOUT;
268         LOS_IntRestore(intSave);
269         OS_RETURN_ERROR(retErr);
270     }
271 
272     LOS_IntRestore(intSave);
273     return LOS_OK;
274 }
275 
MuxPostForPosix(pthread_mutex_t * mutex)276 STATIC UINT32 MuxPostForPosix(pthread_mutex_t *mutex)
277 {
278     UINT32 intSave;
279     LosMuxCB *muxPosted = NULL;
280     LosTaskCB *resumedTask = NULL;
281     LosTaskCB *runningTask = NULL;
282     UINT32 muxHandle = mutex->handle;
283 
284     muxPosted = GET_MUX(muxHandle);
285     intSave = LOS_IntLock();
286 
287     if (muxPosted->muxStat == OS_MUX_UNUSED) {
288         LOS_IntRestore(intSave);
289         OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID);
290     }
291 
292     runningTask = (LosTaskCB *)g_losTask.runTask;
293     if ((muxPosted->muxCount == 0) || (muxPosted->owner != runningTask)) {
294         LOS_IntRestore(intSave);
295         OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID);
296     }
297 
298     if ((--(muxPosted->muxCount) != 0) && (mutex->stAttr.type == PTHREAD_MUTEX_RECURSIVE)) {
299         LOS_IntRestore(intSave);
300         OsHookCall(LOS_HOOK_TYPE_MUX_POST, muxPosted);
301         return LOS_OK;
302     }
303 
304     if ((muxPosted->owner->priority) != muxPosted->priority) {
305         (VOID)OsSchedModifyTaskSchedParam(muxPosted->owner, muxPosted->priority);
306     }
307 
308     if (!LOS_ListEmpty(&muxPosted->muxList)) {
309         resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(muxPosted->muxList)));
310 
311         muxPosted->muxCount = 1;
312         muxPosted->owner = resumedTask;
313         muxPosted->priority = resumedTask->priority;
314         resumedTask->taskMux = NULL;
315 
316         OsSchedTaskWake(resumedTask);
317 
318         LOS_IntRestore(intSave);
319         OsHookCall(LOS_HOOK_TYPE_MUX_POST, muxPosted);
320         LOS_Schedule();
321     } else {
322         muxPosted->owner = NULL;
323         LOS_IntRestore(intSave);
324     }
325 
326     return LOS_OK;
327 }
328 
pthread_mutex_timedlock(pthread_mutex_t * mutex,const struct timespec * absTimeout)329 int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *absTimeout)
330 {
331     UINT32 ret;
332     UINT32 timeout;
333     UINT64 timeoutNs;
334     struct timespec curTime = {0};
335     LosMuxCB *muxPended = NULL;
336 
337 #if (LOSCFG_MUTEX_CREATE_TRACE == 1)
338     UINTPTR regLR = ArchLRGet();
339 #endif
340 
341     ret = MuxPreCheck(mutex, OS_TCB_FROM_TID(LOS_CurTaskIDGet()));
342     if (ret != 0) {
343         return (INT32)ret;
344     }
345 
346     if ((absTimeout == NULL) || (absTimeout->tv_nsec < 0) || (absTimeout->tv_nsec >= OS_SYS_NS_PER_SECOND)) {
347         return EINVAL;
348     }
349     if (mutex->handle == _MUX_INVALID_HANDLE) {
350         ret = LOS_MuxCreate(&mutex->handle);
351         if (ret != LOS_OK) {
352             return MapError(ret);
353         }
354 #if (LOSCFG_MUTEX_CREATE_TRACE == 1)
355         OsSetMutexCreateInfo(GET_MUX(mutex->handle), regLR);
356 #endif
357     } else {
358         muxPended = GET_MUX(mutex->handle);
359         if ((mutex->stAttr.type == PTHREAD_MUTEX_ERRORCHECK) &&
360             (muxPended->muxCount != 0) &&
361             (muxPended->owner == OS_TCB_FROM_TID(LOS_CurTaskIDGet()))) {
362             return EDEADLK;
363         }
364     }
365     ret = clock_gettime(CLOCK_REALTIME, &curTime);
366     if (ret != LOS_OK) {
367         return EINVAL;
368     }
369     timeoutNs = (absTimeout->tv_sec - curTime.tv_sec) * OS_SYS_NS_PER_SECOND + (absTimeout->tv_nsec - curTime.tv_nsec);
370     if (timeoutNs <= 0) {
371         return ETIMEDOUT;
372     }
373     timeout = (timeoutNs + (OS_SYS_NS_PER_MSECOND - 1)) / OS_SYS_NS_PER_MSECOND;
374     ret = MuxPendForPosix(mutex, timeout);
375 
376     return MapError(ret);
377 }
378 
379 /* Lock mutex, waiting for it if necessary. */
pthread_mutex_lock(pthread_mutex_t * mutex)380 int pthread_mutex_lock(pthread_mutex_t *mutex)
381 {
382     UINT32 ret;
383     LosMuxCB *muxPended = NULL;
384 
385 #if (LOSCFG_MUTEX_CREATE_TRACE == 1)
386     UINTPTR regLR = ArchLRGet();
387 #endif
388 
389     LosTaskCB *runTask = OS_TCB_FROM_TID(LOS_CurTaskIDGet());
390 
391     ret = MuxPreCheck(mutex, runTask);
392     if (ret != 0) {
393         return (INT32)ret;
394     }
395 
396     if (mutex->handle == _MUX_INVALID_HANDLE) {
397         ret = LOS_MuxCreate(&mutex->handle);
398         if (ret != LOS_OK) {
399             return MapError(ret);
400         }
401 #if (LOSCFG_MUTEX_CREATE_TRACE == 1)
402         OsSetMutexCreateInfo(GET_MUX(mutex->handle), regLR);
403 #endif
404     } else {
405         muxPended = GET_MUX(mutex->handle);
406         if ((mutex->stAttr.type == PTHREAD_MUTEX_ERRORCHECK) &&
407             (muxPended->muxCount != 0) &&
408             (muxPended->owner == runTask)) {
409             return EDEADLK;
410         }
411     }
412     ret = MuxPendForPosix(mutex, LOS_WAIT_FOREVER);
413 
414     return MapError(ret);
415 }
416 
pthread_mutex_trylock(pthread_mutex_t * mutex)417 int pthread_mutex_trylock(pthread_mutex_t *mutex)
418 {
419     UINT32 ret;
420     LosMuxCB *muxPended = NULL;
421 
422 #if (LOSCFG_MUTEX_CREATE_TRACE == 1)
423     UINTPTR regLR = ArchLRGet();
424 #endif
425 
426     ret = MuxPreCheck(mutex, OS_TCB_FROM_TID(LOS_CurTaskIDGet()));
427     if (ret != 0) {
428         return (INT32)ret;
429     }
430 
431     if (mutex->handle == _MUX_INVALID_HANDLE) {
432         ret = LOS_MuxCreate(&mutex->handle);
433         if (ret != LOS_OK) {
434             return MapError(ret);
435         }
436 #if (LOSCFG_MUTEX_CREATE_TRACE == 1)
437         OsSetMutexCreateInfo(GET_MUX(mutex->handle), regLR);
438 #endif
439     } else {
440         muxPended = GET_MUX(mutex->handle);
441         if ((mutex->stAttr.type != PTHREAD_MUTEX_RECURSIVE) && (muxPended->muxCount != 0)) {
442             return EBUSY;
443         }
444     }
445     ret = MuxPendForPosix(mutex, 0);
446 
447     return MapError(ret);
448 }
449 
pthread_mutex_unlock(pthread_mutex_t * mutex)450 int pthread_mutex_unlock(pthread_mutex_t *mutex)
451 {
452     UINT32 ret;
453     ret = MuxPreCheck(mutex, OS_TCB_FROM_TID(LOS_CurTaskIDGet()));
454     if (ret != 0) {
455         return (INT32)ret;
456     }
457 
458     if (mutex->handle == _MUX_INVALID_HANDLE) {
459         return EINVAL;
460     }
461 
462     ret = MuxPostForPosix(mutex);
463 
464     return MapError(ret);
465 }
466 
467