Abstract: In the multi-task environment, there will be multiple tasks accessing the same common resource, and some common resources are non-shared critical resources, which can only be used exclusively. LiteOS avoids this conflict by using mutex, a special binary semaphore used for exclusive processing of critical resources.

LiteOS kernel source code analysis series seven Mutex, originally written by zhushy.

In a multi-task environment, multiple tasks may access the same common resource. However, some common resources are non-shared critical resources and can only be used exclusively.

LiteOS avoids this conflict by using mutex, a special binary semaphore used for exclusive processing of critical resources. In addition, mutex can solve the semaphore priority flipping problem. When a mutex is used to process synchronous access to a critical resource, the mutex is locked if a task accesses the resource. Other tasks at this time if you want to visit this critical resource will be blocked, until the mutex is the task of holding the lock is released, other tasks to revisit the public resources, the mutex lock again, so make sure that the same time there is only one task is on a visit to the critical resources, to ensure the operating integrity of critical resources.

In this article, we come to learn the source code of LiteOS mutex module, the source code involved in the article, can be found on LiteOS open source site gitee.com/LiteOS/Lite… To obtain. Mutex source code, development documents, sample program code is as follows:

  • LiteOS kernel mutex source code

Kernel \include\los_mux_pri.h, kernel\include\los_mux.h,

C Source file kernel\base\los_mux.c

  • Development guide documentation – Mutex

Online documentation

Gitee.com/LiteOS/Lite…

Next, we look at the structure of the mutex, mutex initialization, mutex common operations of the source code.

1. Mutex structure definition and common macro definition

1.1 Mutex structure definition

In the kernel\base\include\los_mux_pri.h file, there are two MuxBaseCB and LosMuxCB. The former is the same as the first three members of the latter. The kernel mutex mechanism can be shared with pthread_mutex_t. The structure source code is shown below, and the structure members are explained in the comments section.

typedef struct { LOS_DL_LIST muxList; /**< mutex bidirectional list */ LosTaskCB *owner; /**< UINT16 muxCount; /**< lock hold times */} MuxBaseCB; typedef struct { LOS_DL_LIST muxList; /**< mutex bidirectional list */ LosTaskCB *owner; /**< UINT16 muxCount; /**< UINT8 muxStat; /**< Muxlock status: OS_MUX_UNUSED, OS_MUX_USED */ UINT32 muxId; /**< mutex Id */} LosMuxCB;Copy the code

1.2 Common macro definitions for mutex

The number of muxls supported by the system is defined by the macro LOSCFG_BASE_IPC_MUX_LIMIT based on the development board. The muxl Id is of the UINT32 type and consists of count and muxId, which are 16 bits high and 16 bits low respectively. When you create a mutex and delete it after it is used, the count value of the high 16 bits of the mutex Id is increased by 1 when the mutex is returned to the mutex pool. This is used to indicate the number of times the mutex is created or deleted. The value of muxId is [0,LOSCFG_BASE_IPC_MUX_LIMIT), indicating the number of each mutex in the muxtex pool.

The macro at ⑴ is used to split the number of digits of count and muxId. The muxId at ⑵ is updated when the muxId is deleted. Get the lower 16 bits of the mutex Id. ⑷ Count the number of times the mutex is created or deleted based on the mutex Id. ⑸ obtains the mutex control block corresponding to the specified mutex Id from the mutex pool.

⑴ ⑴ #define MUX_SPLIT_BIT (1) MuxId) (((count) < < MUX_SPLIT_BIT) | (muxId)) (3) # define GET_MUX_INDEX (muxId) ((muxId) & (u (1 < < MUX_SPLIT_BIT) - 1)) (4) #define GET_MUX_COUNT(muxId) ((muxId) >> MUX_SPLIT_BIT) ⑸ ⑸ #define GET_MUX(muxId) ((LosMuxCB *)g_allMux) + GET_MUX_INDEX(muxId))Copy the code

2. Mutex initialization

Mutexes are enabled by default in the kernel and can be disabled by using the macro LOSCFG_BASE_IPC_MUX. When mutex is enabled, OsMuxInit() is called in kernel\init\los_init.c to initialize the mutex module during system startup.

Next, let’s examine the mutex initialization code.

⑴ Initializes g_unusedMuxList and maintains unused mutex. ⑵ Allocate memory for the mutex. If the request fails, the error LOS_ERRNO_MUX_NO_MEMORY is returned

Initialize each mutex, specify muxId (owner), muxStat (unused), and insert g_unusedMuxList (unusedmuxList).

(4) If mutex debugging is enabled, call UINT32OsMuxDbgInit(VOID) to initialize.

LITE_OS_SEC_TEXT UINT32 OsMuxInit(VOID) { LosMuxCB *muxNode = NULL; UINT32 index; (1) LOS_ListInit (& g_unusedMuxList); ⑵ g_allMux = (LosMuxCB *)LOS_MemAlloc(m_aucSysMem0, (LOSCFG_BASE_IPC_MUX_LIMIT * sizeof(LosMuxCB))); if (g_allMux == NULL) { return LOS_ERRNO_MUX_NO_MEMORY; } ⑶ for (index = 0; index < LOSCFG_BASE_IPC_MUX_LIMIT; index++) { muxNode = g_allMux + index; muxNode->muxId = index; muxNode->owner = NULL; muxNode->muxStat = OS_MUX_UNUSED; LOS_ListTailInsert(&g_unusedMuxList, &muxNode->muxList); } ⑷ ⑷ if (OsMuxDbgInitHook()! = LOS_OK) { return LOS_ERRNO_MUX_NO_MEMORY; } return LOS_OK; }Copy the code

3. Common operations for mutex

3.1 Creating a mutex

We can use the function UINT32 LOS_MuxCreate(UINT32 *muxHandle) to create a mutex. The following describes how to create a mutex by analyzing the source code.

1. Determine if g_unusedMuxList is empty and there are mutex resources available. If no mutex is available, the function OsMutexCheckHook() is called to check whether there is an error such as mutex overflow. This function needs to be switched on. (2) if g_unusedMuxList is not empty, get the first available mutex node and then delete it from g_unusedMuxList. Then call LOS_DL_LIST_ENTRY(unusedMux, LosMuxCB, muxList) to get LosMuxCB *muxCreated, initialize the created mutex information, including the number of lock holding, status, owner and other information. MuxCreated -> muxCreated->muxList; muxCreated->muxList; muxCreated->muxList; (4) Assign the output parameter *muxHandle, and subsequent programs use this mutex Id to perform other operations on the mutex. ⑸ When commissioning is started, the OsMuxDbgUpdateHook() function will be called to update the use of the mutex.

LITE_OS_SEC_TEXT UINT32 LOS_MuxCreate(UINT32 *muxHandle) { UINT32 intSave; LosMuxCB *muxCreated = NULL; LOS_DL_LIST *unusedMux = NULL; UINT32 errNo; UINT32 errLine; if (muxHandle == NULL) { return LOS_ERRNO_MUX_PTR_NULL; } SCHEDULER_LOCK(intSave); ⑴ if (LOS_ListEmpty(&g_unusedMuxList)) {SCHEDULER_UNLOCK(intSave); OsMutexCheckHook(); OS_GOTO_ERR_HANDLER(LOS_ERRNO_MUX_ALL_BUSY); } ⑵ unusedMux = LOS_DL_LIST_FIRST(&g_unusedmuxList); LOS_ListDelete(unusedMux); muxCreated = LOS_DL_LIST_ENTRY(unusedMux, LosMuxCB, muxList); muxCreated->muxCount = 0; muxCreated->muxStat = OS_MUX_USED; muxCreated->owner = NULL; (3) LOS_ListInit (& muxCreated - > muxList); *muxHandle = muxCreated->muxId; 5] OsMuxDbgUpdateHook (muxCreated - > muxId, OsCurrTaskGet () - > taskEntry); SCHEDULER_UNLOCK(intSave); LOS_TRACE(MUX_CREATE, muxCreated->muxId); return LOS_OK; ERR_HANDLER: OS_RETURN_ERROR_P2(errLine, errNo); }Copy the code

3.2 Deleting a mutex

LOS_MuxDelete(UINT32 muxHandle) is used to delete a mutex. The following describes how to delete a mutex by analyzing the source code.

⑴ determines whether the muleID mutex exceeds LOSCFG_BASE_IPC_MUX_LIMIT, and returns an error code if it does. ⑵ Obtain the mutex control block LosMuxCB *muxDeleted. (3) If the mutex Id to be deleted is incorrect, or the mutex to be deleted is not in use, go to the error label for processing. (4) If the number of mutex holders is not empty, it is not allowed to delete. ⑸ recycle the deleted mutex into g_unusedMuxList, then update the status to unused, update the mutex Id. When the commissioning is started, the OsMuxDbgUpdateHook() function is called to update the mutex usage.

LITE_OS_SEC_TEXT UINT32 LOS_MuxDelete(UINT32 muxHandle) { UINT32 intSave; LosMuxCB *muxDeleted = NULL; UINT32 errNo; UINT32 errLine; ⑴ IF (GET_MUX_INDEX(muxHandle) >= (UINT32)LOSCFG_BASE_IPC_MUX_LIMIT) {OS_GOTO_ERR_HANDLER(LOS_ERRNO_MUX_INVALID); } ⑵ muxDeleted = GET_MUX(muxHandle); LOS_TRACE(MUX_DELETE, muxHandle, muxDeleted->muxStat, muxDeleted->muxCount, ((muxDeleted->owner == NULL) ? 0xFFFFFFFF : muxDeleted->owner->taskId)); SCHEDULER_LOCK(intSave); (3) if ((muxDeleted - > muxId! = muxHandle) || (muxDeleted->muxStat == OS_MUX_UNUSED)) { SCHEDULER_UNLOCK(intSave); OS_GOTO_ERR_HANDLER(LOS_ERRNO_MUX_INVALID); } (4) if (! LOS_ListEmpty(&muxDeleted->muxList) || muxDeleted->muxCount) { SCHEDULER_UNLOCK(intSave); OS_GOTO_ERR_HANDLER(LOS_ERRNO_MUX_PENDED); } [5] LOS_ListTailInsert (& g_unusedMuxList, & muxDeleted - > muxList); muxDeleted->muxStat = OS_MUX_UNUSED; muxDeleted->muxId = SET_MUX_ID(GET_MUX_COUNT(muxDeleted->muxId) + 1, GET_MUX_INDEX(muxDeleted->muxId)); [6] OsMuxDbgUpdateHook (muxDeleted - > muxId, NULL); SCHEDULER_UNLOCK(intSave); return LOS_OK; ERR_HANDLER: OS_RETURN_ERROR_P2(errLine, errNo); }Copy the code

3.3 Applying for a mutex

You can use the function UINT32 LOS_MuxPend(UINT32 muxHandle, UINT32 timeout) to request a mutex. The two parameters are mutex Id and timeout (unit: Tick). The value ranges from 0 to LOS_WAIT_FOREVER.

Here is how to request a mutex by analyzing the source code.

When applying for a mutex, the mutex Id and parameters are verified. The code judges whether the mutex application is a system task, if it is a system task output warning information. (2) If the mutex is not held, update the holding times of the mutex and the owner information to complete the mutex application. (3) If the hold times of the mutex are not 0 and are held by the current task, the hold times can be increased by 1, and the hold is nested again to complete the mutex application. (4) If the wait time is 0, the application fails. ⑸ If the current lock task is scheduled and mutex is not allowed, print the backtrace stack and return the error code.

If it reaches ⑹, the mutex is held by another task. If the priority of the mutex holding task is higher than that of the mutex holding task, the priority of the mutex holding task is changed to that of the current task. The priority of the mutex holding task is backed up to the member variable muxPended->owner->priBitMap. With this modification, priority flipping can be avoided. The function at ⑺ OsMuxPendOp() continues below.

LITE_OS_SEC_TEXT UINT32 LOS_MuxPend(UINT32 muxHandle, UINT32 timeout) { UINT32 ret; UINT32 intSave; LosMuxCB *muxPended = NULL; LosTaskCB *runTask = NULL; if (GET_MUX_INDEX(muxHandle) >= (UINT32)LOSCFG_BASE_IPC_MUX_LIMIT) { OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID); } muxPended = GET_MUX(muxHandle); LOS_TRACE(MUX_PEND, muxHandle, muxPended->muxCount, ((muxPended->owner == NULL) ? 0xFFFFFFFF : muxPended->owner->taskId), timeout); SCHEDULER_LOCK(intSave); ret = OsMuxParaCheck(muxPended, muxHandle); if (ret ! = LOS_OK) { goto OUT_UNLOCK; } runTask = OsCurrTaskGet(); ⑴ if (runTask->taskFlags & OS_TASK_FLAG_SYSTEM) {PRINT_DEBUG("Warning: DO NOT recommend to use %s in system tasks.\n", __FUNCTION__); } ⑵ if (muxPended->muxCount == 0) {OsMuxDlockNodeInsertHook(runTask->taskId, muxPended); muxPended->muxCount++; muxPended->owner = runTask; goto OUT_UNLOCK; } ⑶ if (muxPended->owner == runTask) {muxPended->muxCount++; goto OUT_UNLOCK; } (4) if (! timeout) { ret = LOS_ERRNO_MUX_UNAVAILABLE; goto OUT_UNLOCK; } [5] the if (! OsPreemptableInSched()) { ret = LOS_ERRNO_MUX_PEND_IN_LOCK; PRINT_ERR("!!! LOS_ERRNO_MUX_PEND_IN_LOCK!!! \n"); OsBackTrace(); goto OUT_UNLOCK; } ⑹ OsMuxBitmapSet(runTask, (MuxBaseCB *)muxPended); ⑺ ret = OsMuxPendOp(runTask, (MuxBaseCB *)muxPended, timeout, &intSave); OUT_UNLOCK: SCHEDULER_UNLOCK(intSave); return ret; }Copy the code

OsMuxPendOp(); (1) set the mutex member variable runTask->taskMux to the mutex. (2) fetches the bidirectional list of mutex that blocks tasks requesting the mutex. This function is examined in more detail later. (3) Change the mutex request task to unready state, block state, insert mutex block task list. If the mutex is not permanent, you also need to add the task to the sorted timeout list. (4) Trigger task scheduling, subsequent programs are temporarily not executed until mutex can be acquired or time out.

If the time times out or a mutex is applied, the system reschedules to execute this task and the program continues from ⑸. If the time times out, the ⑹ office updates the task status and returns the code, and fails to apply for the mutex. ⑺ If the mutex is successfully applied for and the timeout duration is not equal to LOS_WAIT_FOREVER, determine whether to restore the task priority.

LITE_OS_SEC_TEXT UINT32 OsMuxPendOp(LosTaskCB *runTask, MuxBaseCB *muxPended, UINT32 timeout, UINT32 *intSave) { LOS_DL_LIST *node = NULL; UINT32 ret = LOS_OK; LosTaskCB *owner = muxPended->owner; ⑴ runTask->taskMux = (VOID *)muxPended; ⑵ node = OsMuxPendFindPos(runTask, muxPended); (3) OsTaskWait (node, OS_TASK_STATUS_PEND, timeout); (4) OsSchedResched (); SCHEDULER_UNLOCK(*intSave); 5] SCHEDULER_LOCK intSave (*); If (runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT) {runTask->taskStatus &= ~OS_TASK_STATUS_TIMEOUT; ret = LOS_ERRNO_MUX_TIMEOUT; } ⑺ if (timeout! = LOS_WAIT_FOREVER) { OsMuxBitmapRestore(runTask, owner); } return ret; }Copy the code

Next, examine the internal function OsMuxPendFindPos(). LiteOS mutex supports two wait modes, which can be configured using macros:

  • LOSCFG_MUTEX_WAITMODE_PRIO

Mutex is based on the task priority waiting mode, blocking the mutex task whose priority is higher and who gets the mutex first when the mutex is released.

  • LOSCFG_MUTEX_WAITMODE_FIFO

Mutex is based on the FIFO wait mode, which blocks the mutex task, the first to enter the blocking queue, and the first to acquire the mutex when the mutex is released.

LOSCFG_MUTEX_WAITMODE_FIFO; OsMuxPendFindPos(); OsMuxPendFindPos(); Hangs tasks at the end of the acquired blocking list. The code is as follows:

LITE_OS_SEC_TEXT STATIC LOS_DL_LIST *OsMuxPendFindPos(const LosTaskCB *runTask, MuxBaseCB *muxPended)
{
    LOS_DL_LIST *node = NULL;
    node = &muxPended->muxList;
    return node;
}
Copy the code

Let’s look again at the code for the function that turns on the macro LOSCFG_MUTEX_WAITMODE_PRIO, which locks the wait mode based on task priority. (1) If the mutex block list is empty, return to the list directly. (2) When the block list is not empty, the first and last list nodes, pendedTask1 and pendedTask2, are obtained from the list. If the priority of the first task in the blocking list is lower than the priority of the current task, all tasks in the list will have a lower priority, and return the first interface of the mutex blocking list. (4) If the last task blocking the list has a higher priority than the current task, return the mutex blocking head. ⑸ For other cases, call the function OsMuxPendFindPosSub().

LITE_OS_SEC_TEXT STATIC LOS_DL_LIST *OsMuxPendFindPos(const LosTaskCB *runTask, MuxBaseCB *muxPended) { LOS_DL_LIST *node = NULL; LosTaskCB *pendedTask1 = NULL; LosTaskCB *pendedTask2 = NULL; ⑴ if (LOS_ListEmpty(&muxPended->muxList)) {node = &muxPended->muxList; } else {⑵ pendedTask1 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&muxPended->muxList)); pendedTask2 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_LAST(&muxPended->muxList)); (3) if ((pendedTask1! = NULL) && (pendedTask1->priority > runTask->priority)) { node = muxPended->muxList.pstNext; ⑷} else if ((pendedTask2! = NULL) && (pendedTask2->priority <= runTask->priority)) { node = &muxPended->muxList; } else {⑸ node = OsMuxPendFindPosSub(runTask, muxPended); } } return node; }Copy the code

Continue with the OsMuxPendFindPosSub() function. (1) Loop through the mutex blocking list, (2) continue if the priority of the task on the list is greater than that of the current task. If the priority of the task on the list is lower than the priority of the current task, no need to continue traversal, return the current node of the list. ⑷ If the priorities are equal, return the next node in the list.

LITE_OS_SEC_TEXT STATIC LOS_DL_LIST *OsMuxPendFindPosSub(const LosTaskCB *runTask, const MuxBaseCB *muxPended) { LosTaskCB *pendedTask = NULL; LOS_DL_LIST *node = NULL; (1) LOS_DL_LIST_FOR_EACH_ENTRY (pendedTask, & (muxPended - > muxList), LosTaskCB, PendList) {⑵ if (pendedTask->priority < runTask->priority) {continue; } else if (pendedTask->priority > runTask->priority) {node = &pendedTask-> priority; break; } else {⑷ node = pendedTask->pendList. break; } } return node; }Copy the code

3.4 Releasing the mutex

We can use the function UINT32 LOS_MuxPost(UINT32 muxHandle) to release the mutex. The following describes how to release the mutex by analyzing the source code.

Before releasing a mutex, check the validity of the mutex Id and parameters. You can read these parameters by yourself. ⑴ returns an error code if the mutex to be released is not held, or is not held by the current task. (2) The number of mutex holders is reduced by 1. If it is not 0, the current task holds the mutex nested and does not need scheduling, and returns that the mutex is released successfully. If the mutex is no longer held by the current task after the release, the ⑶ function OsMuxPostOp() is called to determine whether there are tasks blocking the mutex and whether task scheduling needs to be triggered. This function is analyzed below. After executing ⑶, execute ⑷, and trigger task scheduling if needed.

LITE_OS_SEC_TEXT UINT32 LOS_MuxPost(UINT32 muxHandle) { UINT32 ret; LosTaskCB *runTask = NULL; LosMuxCB *muxPosted = GET_MUX(muxHandle); UINT32 intSave; if (GET_MUX_INDEX(muxHandle) >= (UINT32)LOSCFG_BASE_IPC_MUX_LIMIT) { OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID); } LOS_TRACE(MUX_POST, muxHandle, muxPosted->muxCount, ((muxPosted->owner == NULL) ? 0xFFFFFFFF : muxPosted->owner->taskId)); SCHEDULER_LOCK(intSave); ret = OsMuxParaCheck(muxPosted, muxHandle); if (ret ! = LOS_OK) { SCHEDULER_UNLOCK(intSave); return ret; } runTask = OsCurrTaskGet(); (1) if ((muxPosted - > muxCount = = 0) | | (muxPosted - > owner! = runTask)) { SCHEDULER_UNLOCK(intSave); OS_RETURN_ERROR(LOS_ERRNO_MUX_INVALID); } ⑵ ⑵ if (--muxPosted->muxCount! = 0) { SCHEDULER_UNLOCK(intSave); return LOS_OK; } ⑶ ret = OsMuxPostOp(runTask, (MuxBaseCB *)muxPosted); SCHEDULER_UNLOCK(intSave); ⑷ if (ret == MUX_SCHEDULE) {LOS_MpSchedule(OS_MP_CPU_ALL); LOS_Schedule(); } return LOS_OK; }Copy the code

Let’s continue with the function OsMuxPostOp(). (1) If the task list waiting for the mutex is empty, it marks that no task holds the mutex and returns that no scheduling is required. ⑵ Get the resumedTask, the first task waiting for the mutex. If the macro LOSCFG_MUTEX_WAITMODE_PRIO is enabled, if the priority of the resumedTask waiting for the mutex is lower than the current priority, you need to restore the priority of the current task. If the current task priority runTask->priBitMap is not 0, the OsMuxPostOpSub function at ⑷ is called, which will be examined later.

(5) Set the mutex holding quantity to 1, and set the holder to wait for the first mutex task resumedTask, resumedTask will not block after holding the mutex resumedTask->taskMux = NULL. And then two statements, belonging to the commissioning properties. (6) resumedTask is removed from the mutex blocking list by calling OsTaskWake(). Update task status, join ready queue, return task need scheduling.

LITE_OS_SEC_TEXT UINT32 OsMuxPostOp(LosTaskCB *runTask, MuxBaseCB *muxPosted) { LosTaskCB *resumedTask = NULL; ⑴ if (LOS_ListEmpty(&muxPosted->muxList)) {muxPosted->owner = NULL; OsMuxDlockNodeDeleteHook(runTask->taskId, muxPosted); return MUX_NO_SCHEDULE; } ⑵ OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(muxPosted->muxList))); #ifdef LOSCFG_MUTEX_WAITMODE_PRIO ⑶ if (resumedTask->priority > runTask->priority) {if (LOS_HighBitGet(runTask->priBitMap) ! = resumedTask->priority) { LOS_BitmapClr(&runTask->priBitMap, resumedTask->priority); } } else if (runTask->priBitMap ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * } #else if (runTask->priBitMap ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * } #endif ⑸ muxPosted->muxCount = 1; muxPosted->owner = resumedTask; resumedTask->taskMux = NULL; OsMuxDlockNodeDeleteHook(runTask->taskId, muxPosted); OsMuxDlockNodeInsertHook(resumedTask->taskId, muxPosted); [6] OsTaskWake (resumedTask OS_TASK_STATUS_PEND); return MUX_SCHEDULE; }Copy the code

Finally, we analyze the function OsMuxPostOpSub().

(1) If there are other tasks blocking on the mutex, get the priority of the current running task record. (2) loops through each task attached to the mutex blocking list. If the priority of the blocking task is not equal to bitMapPri, perform (3) to clean the priority bit. (4) restore the priority of tasks currently holding mutex.

LITE_OS_SEC_TEXT STATIC VOID OsMuxPostOpSub(LosTaskCB *runTask, MuxBaseCB *muxPosted) { LosTaskCB *pendedTask = NULL; UINT16 bitMapPri; (1) if (! LOS_ListEmpty(&muxPosted->muxList)) { bitMapPri = LOS_HighBitGet(runTask->priBitMap); ⑵ LOS_DL_LIST_FOR_EACH_ENTRY(pendedTask, (&muxPosted->muxList), LosTaskCB, pendList) {if (bitMapPri! (3) {LOS_BitmapClr(&runTask->priBitMap, pendedTask->priority); * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * LOS_BitmapClr(&runTask->priBitMap, bitMapPri); OsTaskPriModify(muxPosted->owner, bitMapPri); }Copy the code

summary

This article leads you to analyze the source code of LiteOS mutex module, including the structure of the mutex, mutex pool initialization, mutex creation and deletion, application release, etc.

Click to follow, the first time to learn about Huawei cloud fresh technology ~