• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2022 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 "los_mux_pri.h"
33 #include "los_bitmap.h"
34 #include "los_spinlock.h"
35 #include "los_mp.h"
36 #include "los_task_pri.h"
37 #include "los_exc.h"
38 #include "los_sched_pri.h"
39 
40 
41 #ifdef LOSCFG_BASE_IPC_MUX
42 #define MUTEXATTR_TYPE_MASK 0x0FU
43 
LOS_MuxAttrInit(LosMuxAttr * attr)44 LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrInit(LosMuxAttr *attr)
45 {
46     if (attr == NULL) {
47         return LOS_EINVAL;
48     }
49 
50     attr->protocol    = LOS_MUX_PRIO_INHERIT;
51     attr->prioceiling = OS_TASK_PRIORITY_LOWEST;
52     attr->type        = LOS_MUX_DEFAULT;
53     return LOS_OK;
54 }
55 
LOS_MuxAttrDestroy(LosMuxAttr * attr)56 LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrDestroy(LosMuxAttr *attr)
57 {
58     if (attr == NULL) {
59         return LOS_EINVAL;
60     }
61 
62     return LOS_OK;
63 }
64 
LOS_MuxAttrGetType(const LosMuxAttr * attr,INT32 * outType)65 LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetType(const LosMuxAttr *attr, INT32 *outType)
66 {
67     INT32 type;
68 
69     if ((attr == NULL) || (outType == NULL)) {
70         return LOS_EINVAL;
71     }
72 
73     type = (INT32)(attr->type & MUTEXATTR_TYPE_MASK);
74     if ((type < LOS_MUX_NORMAL) || (type > LOS_MUX_ERRORCHECK)) {
75         return LOS_EINVAL;
76     }
77 
78     *outType = type;
79 
80     return LOS_OK;
81 }
82 
LOS_MuxAttrSetType(LosMuxAttr * attr,INT32 type)83 LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetType(LosMuxAttr *attr, INT32 type)
84 {
85     if ((attr == NULL) || (type < LOS_MUX_NORMAL) || (type > LOS_MUX_ERRORCHECK)) {
86         return LOS_EINVAL;
87     }
88 
89     attr->type = (UINT8)((attr->type & ~MUTEXATTR_TYPE_MASK) | (UINT32)type);
90     return LOS_OK;
91 }
92 
LOS_MuxAttrGetProtocol(const LosMuxAttr * attr,INT32 * protocol)93 LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetProtocol(const LosMuxAttr *attr, INT32 *protocol)
94 {
95     if ((attr != NULL) && (protocol != NULL)) {
96         *protocol = attr->protocol;
97     } else {
98         return LOS_EINVAL;
99     }
100 
101     return LOS_OK;
102 }
103 
LOS_MuxAttrSetProtocol(LosMuxAttr * attr,INT32 protocol)104 LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetProtocol(LosMuxAttr *attr, INT32 protocol)
105 {
106     if (attr == NULL) {
107         return LOS_EINVAL;
108     }
109 
110     switch (protocol) {
111         case LOS_MUX_PRIO_NONE:
112         case LOS_MUX_PRIO_INHERIT:
113         case LOS_MUX_PRIO_PROTECT:
114             attr->protocol = (UINT8)protocol;
115             return LOS_OK;
116         default:
117             return LOS_EINVAL;
118     }
119 }
120 
LOS_MuxAttrGetPrioceiling(const LosMuxAttr * attr,INT32 * prioceiling)121 LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetPrioceiling(const LosMuxAttr *attr, INT32 *prioceiling)
122 {
123     if (attr == NULL) {
124         return LOS_EINVAL;
125     }
126 
127     if (prioceiling != NULL) {
128         *prioceiling = attr->prioceiling;
129     }
130 
131     return LOS_OK;
132 }
133 
LOS_MuxAttrSetPrioceiling(LosMuxAttr * attr,INT32 prioceiling)134 LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetPrioceiling(LosMuxAttr *attr, INT32 prioceiling)
135 {
136     if ((attr == NULL) ||
137         (prioceiling < OS_TASK_PRIORITY_HIGHEST) ||
138         (prioceiling > OS_TASK_PRIORITY_LOWEST)) {
139         return LOS_EINVAL;
140     }
141 
142     attr->prioceiling = (UINT8)prioceiling;
143 
144     return LOS_OK;
145 }
146 
LOS_MuxSetPrioceiling(LosMux * mutex,INT32 prioceiling,INT32 * oldPrioceiling)147 LITE_OS_SEC_TEXT UINT32 LOS_MuxSetPrioceiling(LosMux *mutex, INT32 prioceiling, INT32 *oldPrioceiling)
148 {
149     INT32 ret;
150     INT32 retLock;
151     if ((mutex == NULL) ||
152         (prioceiling < OS_TASK_PRIORITY_HIGHEST) ||
153         (prioceiling > OS_TASK_PRIORITY_LOWEST)) {
154         return LOS_EINVAL;
155     }
156 
157     retLock = LOS_MuxLock(mutex, LOS_WAIT_FOREVER);
158     if (retLock != LOS_OK) {
159         return retLock;
160     }
161 
162     if (oldPrioceiling != NULL) {
163         *oldPrioceiling = mutex->attr.prioceiling;
164     }
165 
166     ret = LOS_MuxAttrSetPrioceiling(&mutex->attr, prioceiling);
167 
168     retLock = LOS_MuxUnlock(mutex);
169     if ((ret == LOS_OK) && (retLock != LOS_OK)) {
170         return retLock;
171     }
172 
173     return ret;
174 }
175 
LOS_MuxGetPrioceiling(const LosMux * mutex,INT32 * prioceiling)176 LITE_OS_SEC_TEXT UINT32 LOS_MuxGetPrioceiling(const LosMux *mutex, INT32 *prioceiling)
177 {
178     if ((mutex != NULL) && (prioceiling != NULL) && (mutex->magic == OS_MUX_MAGIC)) {
179         *prioceiling = mutex->attr.prioceiling;
180         return LOS_OK;
181     }
182 
183     return LOS_EINVAL;
184 }
185 
LOS_MuxIsValid(const LosMux * mutex)186 LITE_OS_SEC_TEXT BOOL LOS_MuxIsValid(const LosMux *mutex)
187 {
188     if ((mutex != NULL) && (mutex->magic == OS_MUX_MAGIC)) {
189         return TRUE;
190     }
191 
192     return FALSE;
193 }
194 
OsCheckMutexAttr(const LosMuxAttr * attr)195 STATIC UINT32 OsCheckMutexAttr(const LosMuxAttr *attr)
196 {
197     if (((INT8)(attr->type) < LOS_MUX_NORMAL) || (attr->type > LOS_MUX_ERRORCHECK)) {
198         return LOS_NOK;
199     }
200     if (((INT8)(attr->prioceiling) < OS_TASK_PRIORITY_HIGHEST) || (attr->prioceiling > OS_TASK_PRIORITY_LOWEST)) {
201         return LOS_NOK;
202     }
203     if (((INT8)(attr->protocol) < LOS_MUX_PRIO_NONE) || (attr->protocol > LOS_MUX_PRIO_PROTECT)) {
204         return LOS_NOK;
205     }
206     return LOS_OK;
207 }
208 
LOS_MuxInit(LosMux * mutex,const LosMuxAttr * attr)209 LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
210 {
211     UINT32 intSave;
212 
213     if (mutex == NULL) {
214         return LOS_EINVAL;
215     }
216 
217     if (attr == NULL) {
218         (VOID)LOS_MuxAttrInit(&mutex->attr);
219     } else {
220         (VOID)memcpy_s(&mutex->attr, sizeof(LosMuxAttr), attr, sizeof(LosMuxAttr));
221     }
222 
223     if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
224         return LOS_EINVAL;
225     }
226 
227     SCHEDULER_LOCK(intSave);
228     mutex->muxCount = 0;
229     mutex->owner = NULL;
230     LOS_ListInit(&mutex->muxList);
231     mutex->magic = OS_MUX_MAGIC;
232     SCHEDULER_UNLOCK(intSave);
233     return LOS_OK;
234 }
235 
LOS_MuxDestroy(LosMux * mutex)236 LITE_OS_SEC_TEXT UINT32 LOS_MuxDestroy(LosMux *mutex)
237 {
238     UINT32 intSave;
239 
240     if (mutex == NULL) {
241         return LOS_EINVAL;
242     }
243 
244     SCHEDULER_LOCK(intSave);
245     if (mutex->magic != OS_MUX_MAGIC) {
246         SCHEDULER_UNLOCK(intSave);
247         return LOS_EBADF;
248     }
249 
250     if (mutex->muxCount != 0) {
251         SCHEDULER_UNLOCK(intSave);
252         return LOS_EBUSY;
253     }
254 
255     (VOID)memset_s(mutex, sizeof(LosMux), 0, sizeof(LosMux));
256     SCHEDULER_UNLOCK(intSave);
257     return LOS_OK;
258 }
259 
OsMuxBitmapSet(const LosMux * mutex,const LosTaskCB * runTask)260 STATIC VOID OsMuxBitmapSet(const LosMux *mutex, const LosTaskCB *runTask)
261 {
262     if (mutex->attr.protocol != LOS_MUX_PRIO_INHERIT) {
263         return;
264     }
265 
266     SchedParam param = { 0 };
267     LosTaskCB *owner = (LosTaskCB *)mutex->owner;
268     INT32 ret = OsSchedParamCompare(owner, runTask);
269     if (ret > 0) {
270         runTask->ops->schedParamGet(runTask, &param);
271         owner->ops->priorityInheritance(owner, &param);
272     }
273 }
274 
OsMuxBitmapRestore(const LosMux * mutex,const LOS_DL_LIST * list,const LosTaskCB * runTask)275 VOID OsMuxBitmapRestore(const LosMux *mutex, const LOS_DL_LIST *list, const LosTaskCB *runTask)
276 {
277     if (mutex->attr.protocol != LOS_MUX_PRIO_INHERIT) {
278         return;
279     }
280 
281     SchedParam param = { 0 };
282     LosTaskCB *owner = (LosTaskCB *)mutex->owner;
283     runTask->ops->schedParamGet(runTask, &param);
284     owner->ops->priorityRestore(owner, list, &param);
285 }
286 
OsMuxPendOp(LosTaskCB * runTask,LosMux * mutex,UINT32 timeout)287 STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
288 {
289     UINT32 ret;
290 
291     if ((mutex->muxList.pstPrev == NULL) || (mutex->muxList.pstNext == NULL)) {
292         /* This is for mutex macro initialization. */
293         mutex->muxCount = 0;
294         mutex->owner = NULL;
295         LOS_ListInit(&mutex->muxList);
296     }
297 
298     if (mutex->muxCount == 0) {
299         mutex->muxCount++;
300         mutex->owner = (VOID *)runTask;
301         LOS_ListTailInsert(&runTask->lockList, &mutex->holdList);
302         if (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT) {
303             SchedParam param = { 0 };
304             runTask->ops->schedParamGet(runTask, &param);
305             param.priority = mutex->attr.prioceiling;
306             runTask->ops->priorityInheritance(runTask, &param);
307         }
308         return LOS_OK;
309     }
310 
311     if (((LosTaskCB *)mutex->owner == runTask) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {
312         mutex->muxCount++;
313         return LOS_OK;
314     }
315 
316     if (!timeout) {
317         return LOS_EINVAL;
318     }
319 
320     if (!OsPreemptableInSched()) {
321         return LOS_EDEADLK;
322     }
323 
324     OsMuxBitmapSet(mutex, runTask);
325 
326     runTask->taskMux = (VOID *)mutex;
327     LOS_DL_LIST *node = OsSchedLockPendFindPos(runTask, &mutex->muxList);
328     if (node == NULL) {
329         ret = LOS_NOK;
330         return ret;
331     }
332 
333     OsTaskWaitSetPendMask(OS_TASK_WAIT_MUTEX, (UINTPTR)mutex, timeout);
334     ret = runTask->ops->wait(runTask, node, timeout);
335     if (ret == LOS_ERRNO_TSK_TIMEOUT) {
336         OsMuxBitmapRestore(mutex, NULL, runTask);
337         runTask->taskMux = NULL;
338         ret = LOS_ETIMEDOUT;
339     }
340 
341     return ret;
342 }
343 
OsMuxLockUnsafe(LosMux * mutex,UINT32 timeout)344 UINT32 OsMuxLockUnsafe(LosMux *mutex, UINT32 timeout)
345 {
346     LosTaskCB *runTask = OsCurrTaskGet();
347 
348     if (mutex->magic != OS_MUX_MAGIC) {
349         return LOS_EBADF;
350     }
351 
352     if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
353         return LOS_EINVAL;
354     }
355 
356     if ((mutex->attr.type == LOS_MUX_ERRORCHECK) && (mutex->owner == (VOID *)runTask)) {
357         return LOS_EDEADLK;
358     }
359 
360     return OsMuxPendOp(runTask, mutex, timeout);
361 }
362 
OsMuxTrylockUnsafe(LosMux * mutex,UINT32 timeout)363 UINT32 OsMuxTrylockUnsafe(LosMux *mutex, UINT32 timeout)
364 {
365     LosTaskCB *runTask = OsCurrTaskGet();
366 
367     if (mutex->magic != OS_MUX_MAGIC) {
368         return LOS_EBADF;
369     }
370 
371     if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
372         return LOS_EINVAL;
373     }
374 
375     if ((mutex->owner != NULL) &&
376         (((LosTaskCB *)mutex->owner != runTask) || (mutex->attr.type != LOS_MUX_RECURSIVE))) {
377         return LOS_EBUSY;
378     }
379 
380     return OsMuxPendOp(runTask, mutex, timeout);
381 }
382 
LOS_MuxLock(LosMux * mutex,UINT32 timeout)383 LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
384 {
385     LosTaskCB *runTask = NULL;
386     UINT32 intSave;
387     UINT32 ret;
388 
389     if (mutex == NULL) {
390         return LOS_EINVAL;
391     }
392 
393     if (OS_INT_ACTIVE) {
394         return LOS_EINTR;
395     }
396 
397     runTask = (LosTaskCB *)OsCurrTaskGet();
398     /* DO NOT Call blocking API in system tasks */
399     if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
400         PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
401         OsBackTrace();
402     }
403 
404     SCHEDULER_LOCK(intSave);
405     ret = OsMuxLockUnsafe(mutex, timeout);
406     SCHEDULER_UNLOCK(intSave);
407     return ret;
408 }
409 
LOS_MuxTrylock(LosMux * mutex)410 LITE_OS_SEC_TEXT UINT32 LOS_MuxTrylock(LosMux *mutex)
411 {
412     LosTaskCB *runTask = NULL;
413     UINT32 intSave;
414     UINT32 ret;
415 
416     if (mutex == NULL) {
417         return LOS_EINVAL;
418     }
419 
420     if (OS_INT_ACTIVE) {
421         return LOS_EINTR;
422     }
423 
424     runTask = (LosTaskCB *)OsCurrTaskGet();
425     /* DO NOT Call blocking API in system tasks */
426     if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
427         PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
428         OsBackTrace();
429     }
430 
431     SCHEDULER_LOCK(intSave);
432     ret = OsMuxTrylockUnsafe(mutex, 0);
433     SCHEDULER_UNLOCK(intSave);
434     return ret;
435 }
436 
OsMuxPostOp(LosTaskCB * taskCB,LosMux * mutex,BOOL * needSched)437 STATIC UINT32 OsMuxPostOp(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
438 {
439     if (LOS_ListEmpty(&mutex->muxList)) {
440         LOS_ListDelete(&mutex->holdList);
441         mutex->owner = NULL;
442         return LOS_OK;
443     }
444 
445     LosTaskCB *resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(mutex->muxList)));
446     OsMuxBitmapRestore(mutex, &mutex->muxList, resumedTask);
447 
448     mutex->muxCount = 1;
449     mutex->owner = (VOID *)resumedTask;
450     LOS_ListDelete(&mutex->holdList);
451     LOS_ListTailInsert(&resumedTask->lockList, &mutex->holdList);
452     OsTaskWakeClearPendMask(resumedTask);
453     resumedTask->ops->wake(resumedTask);
454     resumedTask->taskMux = NULL;
455     if (needSched != NULL) {
456         *needSched = TRUE;
457     }
458 
459     return LOS_OK;
460 }
461 
OsMuxUnlockUnsafe(LosTaskCB * taskCB,LosMux * mutex,BOOL * needSched)462 UINT32 OsMuxUnlockUnsafe(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
463 {
464     if (mutex->magic != OS_MUX_MAGIC) {
465         return LOS_EBADF;
466     }
467 
468     if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
469         return LOS_EINVAL;
470     }
471 
472     if ((LosTaskCB *)mutex->owner != taskCB) {
473         return LOS_EPERM;
474     }
475 
476     if (mutex->muxCount == 0) {
477         return LOS_EPERM;
478     }
479 
480     if ((--mutex->muxCount != 0) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {
481         return LOS_OK;
482     }
483 
484     if (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT) {
485         SchedParam param = { 0 };
486         taskCB->ops->schedParamGet(taskCB, &param);
487         taskCB->ops->priorityRestore(taskCB, NULL, &param);
488     }
489 
490     /* Whether a task block the mutex lock. */
491     return OsMuxPostOp(taskCB, mutex, needSched);
492 }
493 
LOS_MuxUnlock(LosMux * mutex)494 LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
495 {
496     LosTaskCB *runTask = NULL;
497     BOOL needSched = FALSE;
498     UINT32 intSave;
499     UINT32 ret;
500 
501     if (mutex == NULL) {
502         return LOS_EINVAL;
503     }
504 
505     if (OS_INT_ACTIVE) {
506         return LOS_EINTR;
507     }
508 
509     runTask = (LosTaskCB *)OsCurrTaskGet();
510     /* DO NOT Call blocking API in system tasks */
511     if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
512         PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
513         OsBackTrace();
514     }
515 
516     SCHEDULER_LOCK(intSave);
517     ret = OsMuxUnlockUnsafe(runTask, mutex, &needSched);
518     SCHEDULER_UNLOCK(intSave);
519     if (needSched == TRUE) {
520         LOS_MpSchedule(OS_MP_CPU_ALL);
521         LOS_Schedule();
522     }
523     return ret;
524 }
525 
526 #endif /* LOSCFG_BASE_IPC_MUX */
527 
528