• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
43 LITE_OS_SEC_DATA_INIT LOS_DL_LIST g_unusedSemList;
44 LITE_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  *****************************************************************************/
OsSemInit(VOID)53 LITE_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  *****************************************************************************/
OsSemCreate(UINT16 count,UINT16 maxCount,UINT32 * semHandle)87 LITE_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 
122 ERR_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  *****************************************************************************/
LOS_SemCreate(UINT16 count,UINT32 * semHandle)133 LITE_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  *****************************************************************************/
LOS_BinarySemCreate(UINT16 count,UINT32 * semHandle)145 LITE_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  *****************************************************************************/
LOS_SemDelete(UINT32 semHandle)157 LITE_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;
185 ERR_HANDLER:
186     OS_RETURN_ERROR_P2(errLine, errNo);
187 }
188 
OsSemValidCheck(LosSemCB * semPended)189 STATIC_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  *****************************************************************************/
LOS_SemPend(UINT32 semHandle,UINT32 timeout)219 LITE_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 
268 ERROR_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  *****************************************************************************/
LOS_SemPost(UINT32 semHandle)280 LITE_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 
LOS_SemGetValue(UINT32 semHandle,INT32 * currVal)318 LITE_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