Abstract:This paper leads us to analyze the source code of the semaphore module of Hongmeng light kernel, including the structure of the semaphore, the initialization of the semaphore pool, the creation and deletion of the semaphore, the application for release, etc.

This article is shared from the Huawei cloud community “HongMeng light kernel M kernel source analysis series 11 Semaphore Semaphore”, the original author: Zhushy.

Semaphore (Semaphore) is a mechanism to achieve communication between tasks, which can achieve synchronization between tasks or mutually exclusive access to shared resources. In a semaphore’s data structure, there is usually a count of available resources, representing the number of shared resources that are left to be used. Semaphore for synchronization and semaphore for mutual exclusion are used differently. In this paper, by analyzing the source code of Hongmeng light kernel semaphore module, we grasp the differences in the use of semaphore. In this article the source involved in OpenHarmony LiteOS -m kernel, for example, can be in the open source site https://gitee.com/openharmony… To obtain.

Next, let’s look at the structure of the semaphore, semaphore initialization, and the source code for the common operations of the semaphore.

1. Semaphore structure definition and common macro definition

1.1 Definition of semaphore structure

The semaphore control block structure defined in the file kernel\include\ los_semm. h is LosSemCB. The source code for the structure is as follows. Semaphore status. The value of semStat is OS_SEM_UNUSED, OS_SEM_USED, and other member variables are commented in the comments section.

typedef struct { UINT16 semStat; /**< semaphore state */ UINT16 semCount; /**< number of semaphore available */ UINT16 maxSemCount; /**< maximum number of semaphore available */ UINT16 semID; /**< semaphore Id */ LOS_DL_LIST semList; /**< block task list in this semaphore */} LosSemCB;

1.2 Definition of semaphore common macros

The amount of semaphore the system can create is defined by the macro LOSCFG_BASE_IPC_SEM_LIMIT. Each semId is of type UINT32 and has a value of [0,LOSCFG_BASE_IPC_SEM_LIMIT). Represents the number of each semaphore in the semaphore pool.

The macros at ⑴ indicate that the maximum value of the binary semaphore is 1, and the macros at ⑵ and ⑶ indicate that the semaphore is unused and in use. (4) The pointer of the structure of the semaphore control block is obtained according to the pointer of the linked list node in the bidirectional linked list of the semaphore blocking task. — Gets the semaphore control block corresponding to the specified semId from the semaphore pool.

⑴ ⑴ #define OS_SEM_USED 1 ⑷ #define GET_SEM_LIST(PTR) ⑴ ⑴ #define OS_SEM_USED 0 ⑶ #define OS_SEM_USED 1 ⑷ #define GET_SEM_LIST(PTR) ⑴ ⑴ #define OS_SEM_USED 0 ⑶ #define OS_SEM_USED 1 ⑷ #define GET_SEM_LIST(PTR) 5) ⑸ #define GET_SEM(semid) ((LosSemCB *)g_allSem) + (semid))

2. Semaphore initialization

The semaphore is turned on by default in the kernel and can be turned off by the user with the macro LOSCFG_BASE_IPC_SEM. When the semaphore is turned on, OSSeminit () is called from kernel\ SRC \los_init.c to initialize the semaphore module at system startup.

Next, let’s examine the semaphore initialization code.

⑴ Initialize G_UnusedSemList and maintain unused semaphore pool. (2) Request memory for the semaphore pool. If the request fails, an error is returned. (3) iterate through each semaphore node, assign index semID to each semaphore node, set. SemStat to unused OS_SEM_UNUSED, and execute (4) insert semaphore node into unused biaxially linked list (g_unusedSemList).

LITE_OS_SEC_TEXT_INIT UINT32 OsSemInit(VOID) { LosSemCB *semNode = NULL; UINT16 index; (1) LOS_ListInit (& g_unusedSemList); if (LOSCFG_BASE_IPC_SEM_LIMIT == 0) { return LOS_ERRNO_SEM_MAXNUM_ZERO; } ⑵ g_allSem = (LosSemCB *)LOS_MemAlloc(m_aucSysMem0, (LOSCFG_BASE_IPC_SEM_LIMIT * sizeof(LosSemCB)); if (g_allSem == NULL) { return LOS_ERRNO_SEM_NO_MEMORY; } ⑶ for (index = 0; index < LOSCFG_BASE_IPC_SEM_LIMIT; index++) { semNode = ((LosSemCB *)g_allSem) + index; semNode->semID = index; semNode->semStat = OS_SEM_UNUSED; (4) LOS_ListTailInsert (& g_unusedSemList, & semNode - > semList); } return LOS_OK; }

3. Common operation of semaphore

3.1 Semaphore creation

Los_semCreate (UINT16 count, UINT32 semHandle) to create the count semaphore Use UINT32LOS_BINARYSEMCREATE (UINT16 COUNT, UINT32 SEMHANDLE) to create a binary semaphore.

Both functions are passed in the same way as the number of semaphore, count, and semHandle, which holds the semaphore number. The maximum number of count semaphore is OS_SEM_COUNTING_MAX_COUNT, and the maximum number of binary semaphore is OS_SEM_BINARY_MAX_COUNT. A further call to ossemCreate () is made to create the semaphore, which we’ll look at later.

LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemCreate(UINT16 count, UINT32 *semHandle)
{
    return OsSemCreate(count, OS_SEM_COUNTING_MAX_COUNT, semHandle);
}

LITE_OS_SEC_TEXT_INIT UINT32 LOS_BinarySemCreate(UINT16 count, UINT32 *semHandle)
{
    return OsSemCreate(count, OS_SEM_BINARY_MAX_COUNT, semHandle);
}

Let’s look at the semaphore creation function osseCreate (), which takes three parameters, the number of semaphore created, the maximum number, and the semaphore number.

⑴ Determine if g_unusedSemList is empty and if there are any semaphore resources available. If there is no semaphore available, call the function osseInfoGetFullDataLook () to do some lookup related to tuning. This function needs to turn on the tuning switch, which will be covered in the following series.

(2) If g_unusedSemList is not empty, then get the first available semaphore node, then remove it from the bifurcally linked list g_unusedSemList, then call the macro GET_SEM_LIST to get LosSemCB *semCreated, initialize the semaphore information created. Contains the status of the semaphore, the number of semaphore, the maximum number of semaphore and other information. (3) Initialize the bifurcated list &semCreated->semList. Tasks that block on the semaphore will hang on the list. ⑷ Assign a value to the output parameter *semHandle. Subsequent programs use this semaphore number to perform other operations on the semaphore.

LITE_OS_SEC_TEXT_INIT UINT32 OsSemCreate(UINT16 count, UINT16 maxCount, UINT32 *semHandle) { UINT32 intSave; LosSemCB *semCreated = NULL; LOS_DL_LIST *unusedSem = NULL; UINT32 errNo; UINT32 errLine; if (semHandle == NULL) { return LOS_ERRNO_SEM_PTR_NULL; } if (count > maxCount) { OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_OVERFLOW); } intSave = LOS_IntLock(); ⑴ if (los_listEmpty (&g_unusedSeList)) {los_intRestore (intSave); OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_ALL_BUSY); } ⑵ unusedSem = LOS_DL_LIST_FIRST(&(g_unusedSemList)); ⑵ unusedSem = LOS_DL_LIST_FIRST(&(g_unusedSemList)); LOS_ListDelete(unusedSem); semCreated = (GET_SEM_LIST(unusedSem)); semCreated->semCount = count; semCreated->semStat = OS_SEM_USED; semCreated->maxSemCount = maxCount; (3) LOS_ListInit (& semCreated - > semList); (4) * semHandle = (UINT32) semCreated - > semID; LOS_IntRestore(intSave); OsHookCall(LOS_HOOK_TYPE_SEM_CREATE, semCreated); return LOS_OK; ERR_HANDLER: OS_RETURN_ERROR_P2(errLine, errNo); }

3.2 Deletion of semaphore

We can use the function LOS_semDelete(UINT32 semHandle) to delete a semaphore. Let’s look at the source code to see how to delete a semaphore.

(1) If the semaphore semHandle exceeds LOSCFG_BASE_IPC_SEM_LIMIT, an error code is returned. If there is no problem with semaphore numbering, get the semaphore control block Lossemcb *semDeleted. (2) Determines the status of the semaphore to be deleted. If it is not in use, it jumps to the error label ERR_HANDLER: for processing. (3) If the list of semaphore blocking tasks is not empty, it is not allowed to delete, jump to the error label for processing. (4) If it is possible to delete a semaphore, then.semstat will be set to unused OS_SEM_UNUSED and the semaphore node will be inserted into the unused bidirectional linked list G_UNUSEDSELIST.

LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemDelete(UINT32 semHandle) { UINT32 intSave; LosSemCB *semDeleted = NULL; UINT32 errNo; UINT32 errLine; ⑴ if (semHandle = (UINT32)LOSCFG_BASE_IPC_SEM_LIMIT) {OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID); ⑴ if (semHandle = (UINT32)LOSCFG_BASE_IPC_SEM_LIMIT) {OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID); } semDeleted = GET_SEM(semHandle); intSave = LOS_IntLock(); 2 the if (semDeleted - > semStat = = OS_SEM_UNUSED) {LOS_IntRestore (intSave); OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID); } (3) if (! LOS_ListEmpty(&semDeleted->semList)) { LOS_IntRestore(intSave); OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_PENDED); } (4) LOS_ListAdd (& g_unusedSemList, & semDeleted - > semList); semDeleted->semStat = OS_SEM_UNUSED; LOS_IntRestore(intSave); OsHookCall(LOS_HOOK_TYPE_SEM_DELETE, semDeleted); return LOS_OK; ERR_HANDLER: OS_RETURN_ERROR_P2(errLine, errNo); }

3.3 Semaphore application

We can use the function uint32los_sempend (UINT32 semHandle, UINT32 timeout) to request a semaphore. The two parameters required are semHandle and timeout. Values in the range [0, LOS_WAIT_FOREVER], in ticks. Let’s examine the source code to see how the semaphore is requested.

When applying for semaphore, the validity of semaphore number and parameters will be checked first. The code at (1) indicates that if the semaphore is greater than the configured maximum, it returns an error code. ⑵ Gets semaphore control block sempEnded to be applied. ⑶ The function is called to check the semaphore control block. If the semaphore is not created, during interrupt processing, or during lock task scheduling, the error code will be returned. (4) If the validation fails, go to ERROR_SEM_PEND: tag to stop the semaphore application.

⑸ If the semaphore count is greater than 0, the semaphore count is reduced by 1 to return the result of successful application. ⑹ If the semaphore count is equal to 0 and the wait time is zero timeout, the result code LOS_ERRNO_SEM_UNAVAILABLE is returned. √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ √ Add the blocking list of the semaphore. If you are not waiting for LOS_WAIT_FOREVER permanently, you also need to change the task status to OS_TASK_STATUS_PEND_TIME and set the WaitTimes wait time. The ⑻ place triggers the task scheduling to switch tasks, and the subsequent code is not executed temporarily.

If the waiting time expires and the semaphore is not available, the task continues executing, changing the status of the task, and returning an error code. If the semaphore is available, execute the task to obtain the semaphore and return the application successfully.

LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout) { UINT32 intSave; LosSemCB *semPended = NULL; UINT32 retErr; LosTaskCB *runningTask = NULL; ⑴ if (semHandle >= (UINT32)LOSCFG_BASE_IPC_SEM_LIMIT) {OS_RETURN_ERROR(LOS_ERRNO_SEM_INVALID); } ⑵ semPended = GET_SEM(semHandle); intSave = LOS_IntLock(); (3) retErr = OsSemValidCheck (semPended); If (retErr) {⑷ goto ERROR_SEM_PEND; } ⑸ if (semPended->semCount > 0) {semPended->semCount--; LOS_IntRestore(intSave); OsHookCall(LOS_HOOK_TYPE_SEM_PEND, semPended, runningTask); return LOS_OK; } [6] the if (! timeout) { retErr = LOS_ERRNO_SEM_UNAVAILABLE; goto ERROR_SEM_PEND; } ⑺ RunningTask = (LOSTASKCB *) g_LOSTASK.RunTask; runningTask->taskSem = (VOID *)semPended; OsSchedTaskWait(&semPended->semList, timeout); LOS_IntRestore(intSave); OsHookCall(LOS_HOOK_TYPE_SEM_PEND, semPended, runningTask); Being LOS_Schedule (); intSave = LOS_IntLock(); Maw (runtime (runningTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {runningTask->taskStatus &= (~OS_TASK_STATUS_TIMEOUT); retErr = LOS_ERRNO_SEM_TIMEOUT; goto ERROR_SEM_PEND; } LOS_IntRestore(intSave); ⑽ return LOS_OK; ERROR_SEM_PEND: LOS_IntRestore(intSave); OS_RETURN_ERROR(retErr); }

3.4 Semaphore release

We can use the function uint32los_sempost (uint32semhandle) to release the semaphore. Let’s look at the source code to see how the semaphore is released.

When the semaphore is released, it will first check the validity of the semaphore number and parameters. These are relatively simple and can be read by yourself. (1) Check whether semaphore overflow occurs. ⑶ Get the first task from the blocking list and set.tasksem to NULL, so that the semaphore is not blocked. Execute the task that has received the semaphore to adjust its state and join the queue. ⑸ Trigger task scheduling to switch tasks. If the task blocking list of the semaphore is empty, increase the count of the semaphore by 1.

LITE_OS_SEC_TEXT UINT32 LOS_SemPost(UINT32 semHandle) { UINT32 intSave; LosSemCB *semPosted = GET_SEM(semHandle); LosTaskCB *resumedTask = NULL; if (semHandle >= LOSCFG_BASE_IPC_SEM_LIMIT) { return LOS_ERRNO_SEM_INVALID; } intSave = LOS_IntLock(); if (semPosted->semStat == OS_SEM_UNUSED) { LOS_IntRestore(intSave); OS_RETURN_ERROR(LOS_ERRNO_SEM_INVALID); If (semsemcount == sempost-> semCount) {LOS_IntRestore(intSave); if (sempost-> semCount == sempost-> semCount); OS_RETURN_ERROR(LOS_ERRNO_SEM_OVERFLOW); } [2] the if (! Los_listEmpty (semPosted->semList) {⑶ resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(semPosted->semList)); resumedTask->taskSem = NULL; (4) OsSchedTaskWake (resumedTask); LOS_IntRestore(intSave); OsHookCall(LOS_HOOK_TYPE_SEM_POST, semPosted, resumedTask); 5] LOS_Schedule (); } else {⑹ semPosted->semCount++; LOS_IntRestore(intSave); OsHookCall(LOS_HOOK_TYPE_SEM_POST, semPosted, resumedTask); } return LOS_OK; }

4. Summary of semaphore usage

4.1 Counting semaphore, binary semaphore and mutex

The only difference between a counting semaphore and a binary semaphore is that the initial number of a binary semaphore is not the same. The initial number of a binary semaphore can only be 0 and 1, while the initial number of a counting semaphore can be 0 and an integer greater than 1.

A mutex can be understood as a binary semaphore of a characteristic that makes no essential difference when implementing exclusive processing of critical resources in a mutex scenario. Compare the next binary structure, the mutex member variable. MuxCount represents the number of locks, the semaphore member variable. SemCount represents the count of the semaphore, which has a slightly different meaning.

4.2 Mutual exclusion and synchronization of semaphore

Semaphore can be used in both mutually exclusive and synchronous scenarios. Semaphore for synchronization and semaphore for mutual exclusion are used differently as follows:

  • Semaphore for mutual exclusion

The initial semaphore count value is not 0, indicating the number of available shared resources. A semaphore is acquired before a shared resource is needed, then a shared resource is used, and the semaphore is released after use. In this way, when the shared resource is fetched out, that is, the semaphore count is reduced to 0, other tasks that need to acquire the semaphore will be blocked, so as to ensure the mutually exclusive access of the shared resource. Request and release of semaphore should be done in pairs in the same task.

  • Semaphore used for synchronization

When multiple tasks access the same shared resource at the same time, it will lead to conflicts. At this time, it is necessary to introduce task synchronization mechanism so that each task can access the shared resource one by one according to the business requirements. The essence of task synchronization is queuing tasks on demand.

Semaphore for synchronization. The initial semaphore count is 0. Task 1 is blocked by applying for a semaphore, and it is not until Task 2 or an interrupt releases the semaphore that Task 1 enters the Ready or Running state, thus achieving synchronization between tasks. Whether the semaphore can be successfully applied depends on whether other tasks release the semaphore. The application and release are completed in different tasks.

summary

This paper leads us to analyze the source code of the semaphore module of Hongmeng light kernel, including the semaphore structure, semaphore pool initialization, semaphore creation and deletion, application release, etc. Thanks for reading, if you have any question, advice, can leave a message to us: https://gitee.com/openharmony… . In order to more easily find HongMeng kernel code warehouse, suggest to https://gitee.com/openharmony… , follow Watch, thumb up Star, and Fork to your account, thank you.

Click on the attention, the first time to understand Huawei cloud fresh technology ~