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