xref: /kernel/liteos_m/kernel/src/los_sem.c (revision 3d8536b4)
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 "los_sem.h"
33#include "los_config.h"
34#include "los_debug.h"
35#include "los_hook.h"
36#include "los_interrupt.h"
37#include "los_memory.h"
38#include "los_sched.h"
39
40
41#if (LOSCFG_BASE_IPC_SEM == 1)
42
43LITE_OS_SEC_DATA_INIT LOS_DL_LIST g_unusedSemList;
44LITE_OS_SEC_BSS LosSemCB *g_allSem = NULL;
45
46/*****************************************************************************
47 Function     : OsSemInit
48 Description  : Initialize the Semaphore doubly linked list
49 Input        : None
50 Output       : None
51 Return       : LOS_OK on success, or error code on failure
52 *****************************************************************************/
53LITE_OS_SEC_TEXT_INIT UINT32 OsSemInit(VOID)
54{
55    LosSemCB *semNode = NULL;
56    UINT16 index;
57
58    LOS_ListInit(&g_unusedSemList);
59
60    if (LOSCFG_BASE_IPC_SEM_LIMIT == 0) {
61        return LOS_ERRNO_SEM_MAXNUM_ZERO;
62    }
63
64    g_allSem = (LosSemCB *)LOS_MemAlloc(m_aucSysMem0, (LOSCFG_BASE_IPC_SEM_LIMIT * sizeof(LosSemCB)));
65    if (g_allSem == NULL) {
66        return LOS_ERRNO_SEM_NO_MEMORY;
67    }
68
69    /* Connect all the semaphore CBs in a doubly linked list. */
70    for (index = 0; index < LOSCFG_BASE_IPC_SEM_LIMIT; index++) {
71        semNode = ((LosSemCB *)g_allSem) + index;
72        semNode->semID = index;
73        semNode->semStat = OS_SEM_UNUSED;
74        LOS_ListTailInsert(&g_unusedSemList, &semNode->semList);
75    }
76    return LOS_OK;
77}
78
79/*****************************************************************************
80 Function     : OsSemCreate
81 Description  : create the Semaphore
82 Input        : count      --- Semaphore count
83              : maxCount   --- Max semaphore count for check
84 Output       : semHandle  --- Index of semaphore
85 Return       : LOS_OK on success, or error code on failure
86 *****************************************************************************/
87LITE_OS_SEC_TEXT_INIT UINT32 OsSemCreate(UINT16 count, UINT16 maxCount, UINT32 *semHandle)
88{
89    UINT32 intSave;
90    LosSemCB *semCreated = NULL;
91    LOS_DL_LIST *unusedSem = NULL;
92    UINT32 errNo;
93    UINT32 errLine;
94
95    if (semHandle == NULL) {
96        return LOS_ERRNO_SEM_PTR_NULL;
97    }
98
99    if (count > maxCount) {
100        OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_OVERFLOW);
101    }
102
103    intSave = LOS_IntLock();
104
105    if (LOS_ListEmpty(&g_unusedSemList)) {
106        LOS_IntRestore(intSave);
107        OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_ALL_BUSY);
108    }
109
110    unusedSem = LOS_DL_LIST_FIRST(&(g_unusedSemList));
111    LOS_ListDelete(unusedSem);
112    semCreated = (GET_SEM_LIST(unusedSem));
113    semCreated->semCount = count;
114    semCreated->semStat = OS_SEM_USED;
115    semCreated->maxSemCount = maxCount;
116    LOS_ListInit(&semCreated->semList);
117    *semHandle = (UINT32)semCreated->semID;
118    LOS_IntRestore(intSave);
119    OsHookCall(LOS_HOOK_TYPE_SEM_CREATE, semCreated);
120    return LOS_OK;
121
122ERR_HANDLER:
123    OS_RETURN_ERROR_P2(errLine, errNo);
124}
125
126/*****************************************************************************
127 Function     : LOS_SemCreate
128 Description  : Create a semaphore
129 Input        : count--------- semaphore count
130 Output       : semHandle-----Index of semaphore
131 Return       : LOS_OK on success, or error code on failure
132 *****************************************************************************/
133LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemCreate(UINT16 count, UINT32 *semHandle)
134{
135    return OsSemCreate(count, OS_SEM_COUNTING_MAX_COUNT, semHandle);
136}
137
138/*****************************************************************************
139 Function     : LOS_BinarySemCreate
140 Description  : Create a binary semaphore
141 Input        : count--------- semaphore count
142 Output       : semHandle-----Index of semaphore
143 Return       : LOS_OK on success, or error code on failure
144 *****************************************************************************/
145LITE_OS_SEC_TEXT_INIT UINT32 LOS_BinarySemCreate(UINT16 count, UINT32 *semHandle)
146{
147    return OsSemCreate(count, OS_SEM_BINARY_MAX_COUNT, semHandle);
148}
149
150/*****************************************************************************
151 Function     : LOS_SemDelete
152 Description  : Delete a semaphore
153 Input        : semHandle--------- semaphore operation handle
154 Output       : None
155 Return       : LOS_OK on success or error code on failure
156 *****************************************************************************/
157LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemDelete(UINT32 semHandle)
158{
159    UINT32 intSave;
160    LosSemCB *semDeleted = NULL;
161    UINT32 errNo;
162    UINT32 errLine;
163
164    if (semHandle >= (UINT32)LOSCFG_BASE_IPC_SEM_LIMIT) {
165        OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID);
166    }
167
168    semDeleted = GET_SEM(semHandle);
169    intSave = LOS_IntLock();
170    if (semDeleted->semStat == OS_SEM_UNUSED) {
171        LOS_IntRestore(intSave);
172        OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID);
173    }
174
175    if (!LOS_ListEmpty(&semDeleted->semList)) {
176        LOS_IntRestore(intSave);
177        OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_PENDED);
178    }
179
180    LOS_ListAdd(&g_unusedSemList, &semDeleted->semList);
181    semDeleted->semStat = OS_SEM_UNUSED;
182    LOS_IntRestore(intSave);
183    OsHookCall(LOS_HOOK_TYPE_SEM_DELETE, semDeleted);
184    return LOS_OK;
185ERR_HANDLER:
186    OS_RETURN_ERROR_P2(errLine, errNo);
187}
188
189STATIC_INLINE UINT32 OsSemValidCheck(LosSemCB *semPended)
190{
191    if (semPended->semStat == OS_SEM_UNUSED) {
192        return LOS_ERRNO_SEM_INVALID;
193    }
194
195    if (OS_INT_ACTIVE) {
196        PRINT_ERR("!!!LOS_ERRNO_SEM_PEND_INTERR!!!\n");
197        return LOS_ERRNO_SEM_PEND_INTERR;
198    }
199
200    if (g_losTaskLock) {
201        PRINT_ERR("!!!LOS_ERRNO_SEM_PEND_IN_LOCK!!!\n");
202        return LOS_ERRNO_SEM_PEND_IN_LOCK;
203    }
204
205    if (g_losTask.runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
206        return LOS_ERRNO_SEM_PEND_IN_SYSTEM_TASK;
207    }
208    return LOS_OK;
209}
210
211/*****************************************************************************
212 Function     : LOS_SemPend
213 Description  : Specified semaphore P operation
214 Input        : semHandle --------- semaphore operation handle
215              : timeout   --------- waitting time
216 Output       : None
217 Return       : LOS_OK on success or error code on failure
218 *****************************************************************************/
219LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
220{
221    UINT32 intSave;
222    LosSemCB *semPended = NULL;
223    UINT32 retErr;
224    LosTaskCB *runningTask = NULL;
225
226    if (semHandle >= (UINT32)LOSCFG_BASE_IPC_SEM_LIMIT) {
227        OS_RETURN_ERROR(LOS_ERRNO_SEM_INVALID);
228    }
229
230    semPended = GET_SEM(semHandle);
231    intSave = LOS_IntLock();
232
233    retErr = OsSemValidCheck(semPended);
234    if (retErr) {
235        goto ERROR_SEM_PEND;
236    }
237
238    runningTask = (LosTaskCB *)g_losTask.runTask;
239
240    if (semPended->semCount > 0) {
241        semPended->semCount--;
242        LOS_IntRestore(intSave);
243        OsHookCall(LOS_HOOK_TYPE_SEM_PEND, semPended, runningTask, timeout);
244        return LOS_OK;
245    }
246
247    if (!timeout) {
248        retErr = LOS_ERRNO_SEM_UNAVAILABLE;
249        goto ERROR_SEM_PEND;
250    }
251
252    runningTask->taskSem = (VOID *)semPended;
253    OsSchedTaskWait(&semPended->semList, timeout);
254    LOS_IntRestore(intSave);
255    OsHookCall(LOS_HOOK_TYPE_SEM_PEND, semPended, runningTask, timeout);
256    LOS_Schedule();
257
258    intSave = LOS_IntLock();
259    if (runningTask->taskStatus & OS_TASK_STATUS_TIMEOUT) {
260        runningTask->taskStatus &= (~OS_TASK_STATUS_TIMEOUT);
261        retErr = LOS_ERRNO_SEM_TIMEOUT;
262        goto ERROR_SEM_PEND;
263    }
264
265    LOS_IntRestore(intSave);
266    return LOS_OK;
267
268ERROR_SEM_PEND:
269    LOS_IntRestore(intSave);
270    OS_RETURN_ERROR(retErr);
271}
272
273/*****************************************************************************
274 Function     : LOS_SemPost
275 Description  : Specified semaphore V operation
276 Input        : semHandle--------- semaphore operation handle
277 Output       : None
278 Return       : LOS_OK on success or error code on failure
279 *****************************************************************************/
280LITE_OS_SEC_TEXT UINT32 LOS_SemPost(UINT32 semHandle)
281{
282    UINT32 intSave;
283    LosSemCB *semPosted = GET_SEM(semHandle);
284    LosTaskCB *resumedTask = NULL;
285
286    if (semHandle >= LOSCFG_BASE_IPC_SEM_LIMIT) {
287        return LOS_ERRNO_SEM_INVALID;
288    }
289
290    intSave = LOS_IntLock();
291
292    if (semPosted->semStat == OS_SEM_UNUSED) {
293        LOS_IntRestore(intSave);
294        OS_RETURN_ERROR(LOS_ERRNO_SEM_INVALID);
295    }
296
297    if (semPosted->maxSemCount == semPosted->semCount) {
298        LOS_IntRestore(intSave);
299        OS_RETURN_ERROR(LOS_ERRNO_SEM_OVERFLOW);
300    }
301    if (!LOS_ListEmpty(&semPosted->semList)) {
302        resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(semPosted->semList)));
303        resumedTask->taskSem = NULL;
304        OsSchedTaskWake(resumedTask);
305
306        LOS_IntRestore(intSave);
307        OsHookCall(LOS_HOOK_TYPE_SEM_POST, semPosted, resumedTask);
308        LOS_Schedule();
309    } else {
310        semPosted->semCount++;
311        LOS_IntRestore(intSave);
312        OsHookCall(LOS_HOOK_TYPE_SEM_POST, semPosted, resumedTask);
313    }
314
315    return LOS_OK;
316}
317
318LITE_OS_SEC_TEXT UINT32 LOS_SemGetValue(UINT32 semHandle, INT32 *currVal)
319{
320    LosSemCB *sem = GET_SEM(semHandle);
321
322    if (semHandle >= (UINT32)LOSCFG_BASE_IPC_SEM_LIMIT) {
323        OS_RETURN_ERROR(LOS_ERRNO_SEM_INVALID);
324    }
325
326    *currVal = sem->semCount;
327    return 0;
328}
329
330#endif /* (LOSCFG_BASE_IPC_SEM == 1) */
331