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