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, ¶m);
271 owner->ops->priorityInheritance(owner, ¶m);
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, ¶m);
284 owner->ops->priorityRestore(owner, list, ¶m);
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, ¶m);
305 param.priority = mutex->attr.prioceiling;
306 runTask->ops->priorityInheritance(runTask, ¶m);
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, ¶m);
487 taskCB->ops->priorityRestore(taskCB, NULL, ¶m);
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