• 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 
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