add OpenHarmony 1.0 baseline

This commit is contained in:
wenjun
2020-09-08 10:21:39 +08:00
parent 94f5f466b4
commit 6df931fc98
736 changed files with 111817 additions and 0 deletions

349
kernel/base/ipc/los_event.c Executable file
View File

@@ -0,0 +1,349 @@
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_event_pri.h"
#include "los_task_pri.h"
#include "los_spinlock.h"
#include "los_mp.h"
#include "los_percpu_pri.h"
#if (LOSCFG_BASE_CORE_SWTMR == YES)
#include "los_exc.h"
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventInit(PEVENT_CB_S eventCB)
{
UINT32 intSave;
if (eventCB == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
intSave = LOS_IntLock();
eventCB->uwEventID = 0;
LOS_ListInit(&eventCB->stEventList);
LOS_IntRestore(intSave);
return LOS_OK;
}
LITE_OS_SEC_TEXT STATIC UINT32 OsEventParamCheck(const VOID *ptr, UINT32 eventMask, UINT32 mode)
{
if (ptr == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
if (eventMask == 0) {
return LOS_ERRNO_EVENT_EVENTMASK_INVALID;
}
if (eventMask & LOS_ERRTYPE_ERROR) {
return LOS_ERRNO_EVENT_SETBIT_INVALID;
}
if (((mode & LOS_WAITMODE_OR) && (mode & LOS_WAITMODE_AND)) ||
(mode & ~(LOS_WAITMODE_OR | LOS_WAITMODE_AND | LOS_WAITMODE_CLR)) ||
!(mode & (LOS_WAITMODE_OR | LOS_WAITMODE_AND))) {
return LOS_ERRNO_EVENT_FLAGS_INVALID;
}
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 OsEventPoll(UINT32 *eventID, UINT32 eventMask, UINT32 mode)
{
UINT32 ret = 0;
LOS_ASSERT(OsIntLocked());
LOS_ASSERT(LOS_SpinHeld(&g_taskSpin));
if (mode & LOS_WAITMODE_OR) {
if ((*eventID & eventMask) != 0) {
ret = *eventID & eventMask;
}
} else {
if ((eventMask != 0) && (eventMask == (*eventID & eventMask))) {
ret = *eventID & eventMask;
}
}
if (ret && (mode & LOS_WAITMODE_CLR)) {
*eventID = *eventID & ~ret;
}
return ret;
}
LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadCheck(const PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode)
{
UINT32 ret;
LosTaskCB *runTask = NULL;
ret = OsEventParamCheck(eventCB, eventMask, mode);
if (ret != LOS_OK) {
return ret;
}
if (OS_INT_ACTIVE) {
return LOS_ERRNO_EVENT_READ_IN_INTERRUPT;
}
runTask = OsCurrTaskGet();
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
OsBackTrace();
return LOS_ERRNO_EVENT_READ_IN_SYSTEM_TASK;
}
return LOS_OK;
}
LITE_OS_SEC_TEXT STATIC UINT32 OsEventReadImp(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode,
UINT32 timeout, BOOL once)
{
UINT32 ret = 0;
LosTaskCB *runTask = OsCurrTaskGet();
if (once == FALSE) {
ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode);
}
if (ret == 0) {
if (timeout == 0) {
return ret;
}
if (!OsPreemptableInSched()) {
return LOS_ERRNO_EVENT_READ_IN_LOCK;
}
runTask->eventMask = eventMask;
runTask->eventMode = mode;
runTask->taskEvent = eventCB;
ret = OsTaskWait(&eventCB->stEventList, timeout, TRUE);
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
runTask->taskEvent = NULL;
return LOS_ERRNO_EVENT_READ_TIMEOUT;
}
ret = OsEventPoll(&eventCB->uwEventID, eventMask, mode);
}
return ret;
}
LITE_OS_SEC_TEXT STATIC UINT32 OsEventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout,
BOOL once)
{
UINT32 ret;
UINT32 intSave;
ret = OsEventReadCheck(eventCB, eventMask, mode);
if (ret != LOS_OK) {
return ret;
}
SCHEDULER_LOCK(intSave);
ret = OsEventReadImp(eventCB, eventMask, mode, timeout, once);
SCHEDULER_UNLOCK(intSave);
return ret;
}
LITE_OS_SEC_TEXT STATIC UINT8 OsEventResume(LosTaskCB *resumedTask, const PEVENT_CB_S eventCB, UINT32 events)
{
UINT8 exitFlag = 0;
if (((resumedTask->eventMode & LOS_WAITMODE_OR) && ((resumedTask->eventMask & events) != 0)) ||
((resumedTask->eventMode & LOS_WAITMODE_AND) &&
((resumedTask->eventMask & eventCB->uwEventID) == resumedTask->eventMask))) {
exitFlag = 1;
resumedTask->taskEvent = NULL;
OsTaskWake(resumedTask);
}
return exitFlag;
}
LITE_OS_SEC_TEXT VOID OsEventWriteUnsafe(PEVENT_CB_S eventCB, UINT32 events, BOOL once, UINT8 *exitFlag)
{
LosTaskCB *resumedTask = NULL;
LosTaskCB *nextTask = NULL;
BOOL schedFlag = FALSE;
eventCB->uwEventID |= events;
if (!LOS_ListEmpty(&eventCB->stEventList)) {
for (resumedTask = LOS_DL_LIST_ENTRY((&eventCB->stEventList)->pstNext, LosTaskCB, pendList);
&resumedTask->pendList != &eventCB->stEventList;) {
nextTask = LOS_DL_LIST_ENTRY(resumedTask->pendList.pstNext, LosTaskCB, pendList);
if (OsEventResume(resumedTask, eventCB, events)) {
schedFlag = TRUE;
}
if (once == TRUE) {
break;
}
resumedTask = nextTask;
}
}
if ((exitFlag != NULL) && (schedFlag == TRUE)) {
*exitFlag = 1;
}
}
LITE_OS_SEC_TEXT STATIC UINT32 OsEventWrite(PEVENT_CB_S eventCB, UINT32 events, BOOL once)
{
UINT32 intSave;
UINT8 exitFlag = 0;
if (eventCB == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
if (events & LOS_ERRTYPE_ERROR) {
return LOS_ERRNO_EVENT_SETBIT_INVALID;
}
SCHEDULER_LOCK(intSave);
OsEventWriteUnsafe(eventCB, events, once, &exitFlag);
SCHEDULER_UNLOCK(intSave);
if (exitFlag == 1) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
}
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_EventPoll(UINT32 *eventID, UINT32 eventMask, UINT32 mode)
{
UINT32 ret;
UINT32 intSave;
ret = OsEventParamCheck((VOID *)eventID, eventMask, mode);
if (ret != LOS_OK) {
return ret;
}
SCHEDULER_LOCK(intSave);
ret = OsEventPoll(eventID, eventMask, mode);
SCHEDULER_UNLOCK(intSave);
return ret;
}
LITE_OS_SEC_TEXT UINT32 LOS_EventRead(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode, UINT32 timeout)
{
return OsEventRead(eventCB, eventMask, mode, timeout, FALSE);
}
LITE_OS_SEC_TEXT UINT32 LOS_EventWrite(PEVENT_CB_S eventCB, UINT32 events)
{
return OsEventWrite(eventCB, events, FALSE);
}
LITE_OS_SEC_TEXT_MINOR UINT32 OsEventReadOnce(PEVENT_CB_S eventCB, UINT32 eventMask, UINT32 mode,
UINT32 timeout)
{
return OsEventRead(eventCB, eventMask, mode, timeout, TRUE);
}
LITE_OS_SEC_TEXT_MINOR UINT32 OsEventWriteOnce(PEVENT_CB_S eventCB, UINT32 events)
{
return OsEventWrite(eventCB, events, TRUE);
}
LITE_OS_SEC_TEXT_INIT UINT32 LOS_EventDestroy(PEVENT_CB_S eventCB)
{
UINT32 intSave;
if (eventCB == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
SCHEDULER_LOCK(intSave);
if (!LOS_ListEmpty(&eventCB->stEventList)) {
SCHEDULER_UNLOCK(intSave);
return LOS_ERRNO_EVENT_SHOULD_NOT_DESTORY;
}
eventCB->uwEventID = 0;
LOS_ListDelInit(&eventCB->stEventList);
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_EventClear(PEVENT_CB_S eventCB, UINT32 events)
{
UINT32 intSave;
if (eventCB == NULL) {
return LOS_ERRNO_EVENT_PTR_NULL;
}
SCHEDULER_LOCK(intSave);
eventCB->uwEventID &= events;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
#ifdef LOSCFG_COMPAT_POSIX
LITE_OS_SEC_TEXT UINT32 OsEventReadWithCond(const EventCond *cond, PEVENT_CB_S eventCB,
UINT32 eventMask, UINT32 mode, UINT32 timeout)
{
UINT32 ret;
UINT32 intSave;
ret = OsEventReadCheck(eventCB, eventMask, mode);
if (ret != LOS_OK) {
return ret;
}
SCHEDULER_LOCK(intSave);
if (*cond->realValue != cond->value) {
eventCB->uwEventID &= cond->clearEvent;
goto OUT;
}
ret = OsEventReadImp(eventCB, eventMask, mode, timeout, FALSE);
OUT:
SCHEDULER_UNLOCK(intSave);
return ret;
}
#endif
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

944
kernel/base/ipc/los_futex.c Executable file
View File

@@ -0,0 +1,944 @@
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_futex_pri.h"
#include "los_process_pri.h"
#include "los_sys_pri.h"
#include "los_sched_pri.h"
#include "los_mp.h"
#include "los_exc.h"
#include "los_mux_pri.h"
#include "user_copy.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define OS_FUTEX_FROM_FUTEXLIST(ptr) LOS_DL_LIST_ENTRY(ptr, FutexNode, futexList)
#define OS_FUTEX_FROM_QUEUELIST(ptr) LOS_DL_LIST_ENTRY(ptr, FutexNode, queueList)
#define OS_FUTEX_KEY_BASE USER_ASPACE_BASE
#define OS_FUTEX_KEY_MAX (USER_ASPACE_BASE + USER_ASPACE_SIZE)
typedef struct {
LosMux listLock;
LOS_DL_LIST lockList;
} FutexHash;
#define FUTEX_INDEX_MAX 128
FutexHash g_futexHash[FUTEX_INDEX_MAX];
STATIC INT32 OsFutexLock(LosMux *lock)
{
UINT32 ret = LOS_MuxLock(lock, LOS_WAIT_FOREVER);
if (ret != LOS_OK) {
PRINT_ERR("Futex lock failed! ERROR: 0x%x!\n", ret);
return LOS_EINVAL;
}
return LOS_OK;
}
STATIC INT32 OsFutexUnlock(LosMux *lock)
{
UINT32 ret = LOS_MuxUnlock(lock);
if (ret != LOS_OK) {
PRINT_ERR("Futex unlock failed! ERROR: 0x%x!\n", ret);
return LOS_EINVAL;
}
return LOS_OK;
}
UINT32 OsFutexInit(VOID)
{
INT32 count;
UINT32 ret;
for (count = 0; count < FUTEX_INDEX_MAX; count++) {
LOS_ListInit(&g_futexHash[count].lockList);
ret = LOS_MuxInit(&(g_futexHash[count].listLock), NULL);
if (ret) {
return ret;
}
}
return LOS_OK;
}
#ifdef LOS_FUTEX_DEBUG
STATIC VOID OsFutexShowTaskNodeAttr(const LOS_DL_LIST *futexList)
{
FutexNode *tempNode = NULL;
FutexNode *lastNode = NULL;
LosTaskCB *taskCB = NULL;
LOS_DL_LIST *queueList = NULL;
tempNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
PRINTK("key : 0x%x : ->", tempNode->key);
for (queueList = &tempNode->queueList; ;) {
lastNode = OS_FUTEX_FROM_QUEUELIST(queueList);
if (!LOS_ListEmpty(&(lastNode->pendList))) {
taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(lastNode->pendList)));
PRINTK(" %d(%d) ->", taskCB->taskID, taskCB->priority);
} else {
taskCB = LOS_DL_LIST_ENTRY(lastNode, LosTaskCB, futex);
PRINTK(" %d(%d) ->", taskCB->taskID, -1);
}
queueList = queueList->pstNext;
if (queueList == &tempNode->queueList) {
break;
}
}
PRINTK("\n");
}
VOID OsFutexHashShow(VOID)
{
LOS_DL_LIST *futexList = NULL;
INT32 count;
/* The maximum number of barrels of a hash table */
INT32 hashNodeMax = FUTEX_INDEX_MAX;
PRINTK("################los_futex_pri.hash ######################\n");
for (count = 0; count < hashNodeMax; count++) {
futexList = &(g_futexHash[count].lockList);
if (LOS_ListEmpty(futexList)) {
continue;
}
PRINTK("hash -> index : %d\n", count);
for (futexList = futexList->pstNext;
futexList != &(g_futexHash[count].lockList);
futexList = futexList->pstNext) {
OsFutexShowTaskNodeAttr(futexList);
}
}
}
#endif
STATIC UINT32 OsFutexGetTick(UINT32 absTime)
{
UINT32 interval;
/* the values not less than per Millisecond */
if (absTime < OS_SYS_MS_PER_SECOND) {
interval = OS_SYS_MS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND;
} else {
interval = absTime / OS_SYS_MS_PER_SECOND;
}
interval = LOS_MS2Tick(interval);
if (interval == 0) {
interval = 1;
}
return interval;
}
STATIC INLINE VOID OsFutexSetKey(UINTPTR futexKey, FutexNode *node)
{
node->key = futexKey;
node->index = futexKey / OS_FUTEX_KEY_BASE;
node->pid = LOS_GetCurrProcessID();
}
STATIC INLINE VOID OsFutexDeinitFutexNode(FutexNode *node)
{
node->index = OS_INVALID_VALUE;
node->pid = 0;
LOS_ListDelete(&node->queueList);
}
STATIC INLINE VOID OsFutexReplaceQueueListHeadNode(FutexNode *oldHeadNode, FutexNode *newHeadNode)
{
LOS_DL_LIST *futexList = oldHeadNode->futexList.pstPrev;
LOS_ListDelete(&oldHeadNode->futexList);
LOS_ListHeadInsert(futexList, &newHeadNode->futexList);
}
STATIC INLINE VOID OsFutexDeleteKeyFromFutexList(FutexNode *node)
{
LOS_ListDelete(&node->futexList);
}
STATIC VOID OsFutexDeleteKeyNodeFromHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
{
FutexNode *nextNode = NULL;
if (node->index >= FUTEX_INDEX_MAX) {
return;
}
if (LOS_ListEmpty(&node->queueList)) {
OsFutexDeleteKeyFromFutexList(node);
if (queueFlags != NULL) {
*queueFlags = TRUE;
}
goto EXIT;
}
/* FutexList is not NULL, but the header node of queueList */
if (node->futexList.pstNext != NULL) {
if (isDeleteHead == TRUE) {
nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&node->queueList));
OsFutexReplaceQueueListHeadNode(node, nextNode);
if (headNode != NULL) {
*headNode = nextNode;
}
} else {
return;
}
}
EXIT:
OsFutexDeinitFutexNode(node);
return;
}
VOID OsFutexNodeDeleteFromFutexHash(FutexNode *node, BOOL isDeleteHead, FutexNode **headNode, BOOL *queueFlags)
{
FutexHash *hashNode = NULL;
UINT32 index = node->key / OS_FUTEX_KEY_BASE;
if (index >= FUTEX_INDEX_MAX) {
return;
}
hashNode = &g_futexHash[index];
if (OsMuxLockUnsafe(&hashNode->listLock, LOS_WAIT_FOREVER)) {
return;
}
if (node->index != index) {
goto EXIT;
}
OsFutexDeleteKeyNodeFromHash(node, isDeleteHead, headNode, queueFlags);
EXIT:
if (OsMuxUnlockUnsafe(OsCurrTaskGet(), &hashNode->listLock, NULL)) {
return;
}
return;
}
STATIC FutexNode *OsFutexDeleteAlreadyWakeTaskAndGetNext(const FutexNode *node, FutexNode **headNode, BOOL isDeleteHead)
{
FutexNode *tempNode = (FutexNode *)node;
FutexNode *nextNode = NULL;
BOOL queueFlag = FALSE;
while (LOS_ListEmpty(&(tempNode->pendList))) { /* already weak */
if (!LOS_ListEmpty(&(tempNode->queueList))) { /* It's not a head node */
nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&(tempNode->queueList)));
}
OsFutexDeleteKeyNodeFromHash(tempNode, isDeleteHead, headNode, &queueFlag);
if (queueFlag) {
return NULL;
}
tempNode = nextNode;
}
return tempNode;
}
STATIC VOID OsFutexInsertNewFutexKeyToHash(FutexNode *node)
{
FutexNode *headNode = NULL;
FutexNode *tailNode = NULL;
LOS_DL_LIST *futexList = NULL;
FutexHash *hashNode = &g_futexHash[node->index];
if (LOS_ListEmpty(&hashNode->lockList)) {
LOS_ListHeadInsert(&(hashNode->lockList), &(node->futexList));
goto EXIT;
}
headNode = OS_FUTEX_FROM_FUTEXLIST(LOS_DL_LIST_FIRST(&(hashNode->lockList)));
/* The small key is at the front of the queue */
if (node->key < headNode->key) {
LOS_ListHeadInsert(&(hashNode->lockList), &(node->futexList));
goto EXIT;
}
tailNode = OS_FUTEX_FROM_FUTEXLIST(LOS_DL_LIST_LAST(&(hashNode->lockList)));
if (node->key > tailNode->key) {
LOS_ListTailInsert(&(hashNode->lockList), &(node->futexList));
goto EXIT;
}
for (futexList = hashNode->lockList.pstNext;
futexList != &(hashNode->lockList);
futexList = futexList->pstNext) {
headNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
if (node->key > headNode->key) {
continue;
} else if (node->key < headNode->key) {
LOS_ListTailInsert(&(headNode->futexList), &(node->futexList));
break;
}
LOS_ListTailInsert(&(headNode->futexList), &(node->futexList));
break;
}
EXIT:
return;
}
STATIC INT32 OsFutexInsertFindFormBackToFront(LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
{
LOS_DL_LIST *listHead = queueList;
LOS_DL_LIST *listTail = queueList->pstPrev;
FutexNode *tempNode = NULL;
LosTaskCB *taskTail = NULL;
for (; listHead != listTail; listTail = listTail->pstPrev) {
tempNode = OS_FUTEX_FROM_QUEUELIST(listTail);
tempNode = OsFutexDeleteAlreadyWakeTaskAndGetNext(tempNode, NULL, FALSE);
taskTail = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tempNode->pendList)));
if (runTask->priority >= taskTail->priority) {
LOS_ListHeadInsert(&(tempNode->queueList), &(node->queueList));
return LOS_OK;
} else if (runTask->priority < taskTail->priority) {
if (listTail->pstPrev == listHead) {
LOS_ListTailInsert(&(tempNode->queueList), &(node->queueList));
return LOS_OK;
}
}
}
return LOS_NOK;
}
STATIC INT32 OsFutexInsertFindFromFrontToBack(LOS_DL_LIST *queueList, const LosTaskCB *runTask, FutexNode *node)
{
LOS_DL_LIST *listHead = queueList;
LOS_DL_LIST *listTail = queueList->pstPrev;
FutexNode *tempNode = NULL;
LosTaskCB *taskHead = NULL;
for (; listHead != listTail; listHead = listHead->pstNext) {
tempNode = OS_FUTEX_FROM_QUEUELIST(listHead);
tempNode = OsFutexDeleteAlreadyWakeTaskAndGetNext(tempNode, NULL, FALSE);
taskHead = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tempNode->pendList)));
/* High priority comes before low priority,
* in the case of the same priority, after the current node
*/
if (runTask->priority >= taskHead->priority) {
if (listHead->pstNext == listTail) {
LOS_ListHeadInsert(&(tempNode->queueList), &(node->queueList));
return LOS_OK;
}
continue;
} else if (runTask->priority < taskHead->priority) {
LOS_ListTailInsert(&(tempNode->queueList), &(node->queueList));
return LOS_OK;
}
}
return LOS_NOK;
}
STATIC INT32 OsFutexRecycleAndFindHeadNode(FutexNode *headNode, FutexNode *node, FutexNode **firstNode)
{
UINT32 intSave;
SCHEDULER_LOCK(intSave);
*firstNode = OsFutexDeleteAlreadyWakeTaskAndGetNext(headNode, NULL, TRUE);
SCHEDULER_UNLOCK(intSave);
/* The head node is removed and there was originally only one node under the key */
if (*firstNode == NULL) {
OsFutexInsertNewFutexKeyToHash(node);
LOS_ListInit(&(node->queueList));
return LOS_OK;
}
return LOS_OK;
}
STATIC INT32 OsFutexInsertTasktoPendList(FutexNode **firstNode, FutexNode *node, const LosTaskCB *run)
{
LosTaskCB *taskHead = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&((*firstNode)->pendList)));
LOS_DL_LIST *queueList = &((*firstNode)->queueList);
FutexNode *tailNode = NULL;
LosTaskCB *taskTail = NULL;
if (run->priority < taskHead->priority) {
/* The one with the highest priority is inserted at the top of the queue */
LOS_ListTailInsert(queueList, &(node->queueList));
OsFutexReplaceQueueListHeadNode(*firstNode, node);
*firstNode = node;
return LOS_OK;
}
if (LOS_ListEmpty(queueList) && (run->priority >= taskHead->priority)) {
/* Insert the next position in the queue with equal priority */
LOS_ListHeadInsert(queueList, &(node->queueList));
return LOS_OK;
}
tailNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_LAST(queueList));
taskTail = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(tailNode->pendList)));
if ((run->priority >= taskTail->priority) ||
((run->priority - taskHead->priority) > (taskTail->priority - run->priority))) {
return OsFutexInsertFindFormBackToFront(queueList, run, node);
}
return OsFutexInsertFindFromFrontToBack(queueList, run, node);
}
STATIC FutexNode *OsFindFutexNode(const FutexNode *node)
{
FutexHash *hashNode = &g_futexHash[node->index];
LOS_DL_LIST *futexList = &(hashNode->lockList);
FutexNode *headNode = NULL;
for (futexList = futexList->pstNext;
futexList != &(hashNode->lockList);
futexList = futexList->pstNext) {
headNode = OS_FUTEX_FROM_FUTEXLIST(futexList);
if ((headNode->key == node->key) && (headNode->pid == node->pid)) {
return headNode;
}
}
return NULL;
}
STATIC INT32 OsFindAndInsertToHash(FutexNode *node)
{
FutexNode *headNode = NULL;
FutexNode *firstNode = NULL;
UINT32 intSave;
INT32 ret;
headNode = OsFindFutexNode(node);
if (headNode == NULL) {
OsFutexInsertNewFutexKeyToHash(node);
LOS_ListInit(&(node->queueList));
return LOS_OK;
}
ret = OsFutexRecycleAndFindHeadNode(headNode, node, &firstNode);
if (ret != LOS_OK) {
return ret;
} else if (firstNode == NULL) {
return ret;
}
SCHEDULER_LOCK(intSave);
ret = OsFutexInsertTasktoPendList(&firstNode, node, OsCurrTaskGet());
SCHEDULER_UNLOCK(intSave);
return ret;
}
STATIC INT32 OsFutexWaitParmaCheck(const UINT32 *userVaddr, UINT32 flags, UINT32 val, UINT32 absTime)
{
UINTPTR futexKey = (UINTPTR)userVaddr;
UINT32 lockVal;
INT32 ret;
if (OS_INT_ACTIVE) {
return LOS_EINTR;
}
if (flags) {
PRINT_ERR("Futex wait parma check failed! error flags: 0x%x\n", flags);
return LOS_EINVAL;
}
if ((futexKey % sizeof(INT32)) || (futexKey < OS_FUTEX_KEY_BASE) || (futexKey >= OS_FUTEX_KEY_MAX)) {
PRINT_ERR("Futex wait parma check failed! error futex key: 0x%x\n", futexKey);
return LOS_EINVAL;
}
if (!absTime) {
PRINT_ERR("Futex wait parma check failed! error absTime: %u\n", absTime);
return LOS_EINVAL;
}
ret = LOS_ArchCopyFromUser(&lockVal, userVaddr, sizeof(UINT32));
if (ret) {
PRINT_ERR("Futex wait parma check failed! copy from user failed!\n");
return LOS_EINVAL;
}
if (lockVal != val) {
return LOS_EBADF;
}
return LOS_OK;
}
STATIC INT32 OsFutexDeleteTimeoutTaskNode(FutexHash *hashNode, FutexNode *node)
{
UINT32 intSave;
if (OsFutexLock(&hashNode->listLock)) {
return LOS_EINVAL;
}
if (node->index < FUTEX_INDEX_MAX) {
SCHEDULER_LOCK(intSave);
(VOID)OsFutexDeleteAlreadyWakeTaskAndGetNext(node, NULL, TRUE);
SCHEDULER_UNLOCK(intSave);
}
#ifdef LOS_FUTEX_DEBUG
OsFutexHashShow();
#endif
if (OsFutexUnlock(&hashNode->listLock)) {
return LOS_EINVAL;
}
return LOS_ETIMEDOUT;
}
STATIC INT32 OsFutexInserTaskToHash(LosTaskCB **taskCB, FutexNode **node, const UINTPTR futexKey)
{
INT32 ret;
*taskCB = OsCurrTaskGet();
*node = &((*taskCB)->futex);
OsFutexSetKey(futexKey, *node);
ret = OsFindAndInsertToHash(*node);
if (ret) {
return LOS_NOK;
}
LOS_ListInit(&((*node)->pendList));
return LOS_OK;
}
STATIC INT32 OsFutexWaitTask(const UINT32 timeOut, const UINT32 *userVaddr)
{
INT32 futexRet;
UINT32 intSave;
LosTaskCB *taskCB = NULL;
FutexNode *node = NULL;
UINTPTR futexKey = (UINTPTR)userVaddr;
UINT32 index = futexKey / OS_FUTEX_KEY_BASE;
FutexHash *hashNode = &g_futexHash[index];
if (OsFutexLock(&hashNode->listLock)) {
return LOS_EINVAL;
}
if (OsFutexInserTaskToHash(&taskCB, &node, futexKey)) {
goto EXIT_ERR;
}
SCHEDULER_LOCK(intSave);
OsTaskWait(&(node->pendList), timeOut, FALSE);
OsPercpuGet()->taskLockCnt++;
LOS_SpinUnlock(&g_taskSpin);
#ifdef LOS_FUTEX_DEBUG
OsFutexHashShow();
#endif
futexRet = OsFutexUnlock(&hashNode->listLock);
if (futexRet) {
OsPercpuGet()->taskLockCnt--;
LOS_IntRestore(intSave);
goto EXIT_UNLOCK_ERR;
}
LOS_SpinLock(&g_taskSpin);
OsPercpuGet()->taskLockCnt--;
/*
* it will immediately do the scheduling, so there's no need to release the
* task spinlock. when this task's been rescheduled, it will be holding the spinlock.
*/
OsSchedResched();
if (taskCB->taskStatus & OS_TASK_STATUS_TIMEOUT) {
taskCB->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
SCHEDULER_UNLOCK(intSave);
return OsFutexDeleteTimeoutTaskNode(hashNode, node);
}
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
EXIT_ERR:
futexRet = OsFutexUnlock(&hashNode->listLock);
EXIT_UNLOCK_ERR:
if (futexRet) {
return futexRet;
}
return LOS_NOK;
}
INT32 OsFutexWait(const UINT32 *userVaddr, UINT32 flags, UINT32 val, UINT32 absTime)
{
INT32 ret;
UINT32 timeOut = LOS_WAIT_FOREVER;
ret = OsFutexWaitParmaCheck(userVaddr, flags, val, absTime);
if (ret) {
return ret;
}
if (absTime != LOS_WAIT_FOREVER) {
timeOut = OsFutexGetTick(absTime);
}
return OsFutexWaitTask(timeOut, userVaddr);
}
/* Check to see if the task to be awakened has timed out
* if time out, to weak next pend task.
*/
STATIC VOID OsFutexCheckAndWakePendTask(FutexNode *headNode, const INT32 wakeNumber,
FutexHash *hashNode, FutexNode **nextNode, BOOL *wakeAny)
{
INT32 count;
LosTaskCB *taskCB = NULL;
FutexNode *node = headNode;
for (count = 0; count < wakeNumber; count++) {
/* Ensure the integrity of the head */
*nextNode = OsFutexDeleteAlreadyWakeTaskAndGetNext(node, NULL, FALSE);
if (*nextNode == NULL) {
/* The last node in queuelist is invalid or the entire list is invalid */
return;
}
node = *nextNode;
taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(node->pendList)));
OsTaskWake(taskCB);
*wakeAny = TRUE;
*nextNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_FIRST(&(node->queueList)));
if (node != headNode) {
OsFutexDeinitFutexNode(node);
}
if (LOS_ListEmpty(&headNode->queueList)) {
/* Wakes up the entire linked list node */
*nextNode = NULL;
return;
}
node = *nextNode;
}
return;
}
STATIC INT32 OsFutexWakeTask(UINTPTR futexKey, INT32 wakeNumber, FutexNode **newHeadNode, BOOL *wakeAny)
{
UINT32 intSave;
FutexNode *node = NULL;
FutexNode *headNode = NULL;
UINT32 index = futexKey / OS_FUTEX_KEY_BASE;
FutexHash *hashNode = &g_futexHash[index];
FutexNode tempNode = {
.key = futexKey,
.index = index,
.pid = LOS_GetCurrProcessID(),
};
node = OsFindFutexNode(&tempNode);
if (node == NULL) {
return LOS_EBADF;
}
headNode = node;
SCHEDULER_LOCK(intSave);
OsFutexCheckAndWakePendTask(headNode, wakeNumber, hashNode, newHeadNode, wakeAny);
if ((*newHeadNode) != NULL) {
OsFutexReplaceQueueListHeadNode(headNode, *newHeadNode);
OsFutexDeinitFutexNode(headNode);
} else if (headNode->index < FUTEX_INDEX_MAX) {
OsFutexDeleteKeyFromFutexList(headNode);
OsFutexDeinitFutexNode(headNode);
}
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
INT32 OsFutexWake(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber)
{
INT32 ret, futexRet;
UINTPTR futexKey = (UINTPTR)userVaddr;
FutexHash *hashNode = NULL;
INT32 index = futexKey / OS_FUTEX_KEY_BASE;
FutexNode *headNode = NULL;
BOOL wakeAny = FALSE;
if (!(flags & FUTEX_WAKE)) {
PRINT_ERR("Futex wake param check failed! error flags: 0x%x\n", flags);
return LOS_EINVAL;
}
if ((futexKey % sizeof(INT32)) || (futexKey < OS_FUTEX_KEY_BASE) || (futexKey >= OS_FUTEX_KEY_MAX)) {
PRINT_ERR("Futex wake param check failed! error futex key: 0x%x\n", futexKey);
return LOS_EINVAL;
}
hashNode = &g_futexHash[index];
if (OsFutexLock(&hashNode->listLock)) {
return LOS_EINVAL;
}
ret = OsFutexWakeTask(futexKey, wakeNumber, &headNode, &wakeAny);
if (ret) {
goto EXIT_ERR;
}
#ifdef LOS_FUTEX_DEBUG
OsFutexHashShow();
#endif
futexRet = OsFutexUnlock(&hashNode->listLock);
if (futexRet) {
goto EXIT_UNLOCK_ERR;
}
if (wakeAny == TRUE) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
}
return LOS_OK;
EXIT_ERR:
futexRet = OsFutexUnlock(&hashNode->listLock);
EXIT_UNLOCK_ERR:
if (futexRet) {
return futexRet;
}
return ret;
}
STATIC INT32 OsFutexRequeueInsertNewKey(UINTPTR newFutexKey, INT32 newIndex, FutexNode *oldHeadNode)
{
INT32 ret;
UINT32 intSave;
LosTaskCB *task = NULL;
FutexNode *nextNode = NULL;
FutexNode newTempNode = {
.key = newFutexKey,
.index = newIndex,
.pid = LOS_GetCurrProcessID(),
};
LOS_DL_LIST *queueList = &oldHeadNode->queueList;
FutexNode *newHeadNode = OsFindFutexNode(&newTempNode);
if (newHeadNode == NULL) {
OsFutexInsertNewFutexKeyToHash(oldHeadNode);
return LOS_OK;
}
do {
nextNode = OS_FUTEX_FROM_QUEUELIST(queueList);
SCHEDULER_LOCK(intSave);
if (LOS_ListEmpty(&nextNode->pendList)) {
queueList = queueList->pstNext;
OsFutexDeinitFutexNode(nextNode);
SCHEDULER_UNLOCK(intSave);
if (queueList->pstNext != NULL) {
continue;
} else {
return LOS_OK;
}
}
task = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(nextNode->pendList)));
queueList = queueList->pstNext;
LOS_ListDelete(&nextNode->queueList);
ret = OsFutexInsertTasktoPendList(&newHeadNode, nextNode, task);
SCHEDULER_UNLOCK(intSave);
if (ret != LOS_OK) {
PRINT_ERR("Futex requeue insert new key failed!\n");
}
} while (queueList->pstNext != NULL);
return LOS_OK;
}
STATIC VOID OsFutexRequeueSplitTwoLists(FutexHash *oldHashNode, FutexNode *oldHeadNode, UINTPTR futexKey, INT32 count)
{
LOS_DL_LIST *queueList = &oldHeadNode->queueList;
FutexNode *tailNode = OS_FUTEX_FROM_QUEUELIST(LOS_DL_LIST_LAST(queueList));
INT32 newIndex = futexKey / OS_FUTEX_KEY_BASE;
FutexNode *nextNode = NULL;
FutexNode *newHeadNode = NULL;
LOS_DL_LIST *futexList = NULL;
BOOL IsAll = FALSE;
INT32 i;
for (i = 0; i < count; i++) {
nextNode = OS_FUTEX_FROM_QUEUELIST(queueList);
nextNode->key = futexKey;
nextNode->index = newIndex;
if (queueList->pstNext == &oldHeadNode->queueList) {
IsAll = TRUE;
break;
}
queueList = queueList->pstNext;
}
futexList = oldHeadNode->futexList.pstPrev;
LOS_ListDelete(&oldHeadNode->futexList);
if (IsAll == TRUE) {
return;
}
newHeadNode = OS_FUTEX_FROM_QUEUELIST(queueList);
LOS_ListHeadInsert(futexList, &newHeadNode->futexList);
oldHeadNode->queueList.pstPrev = &nextNode->queueList;
nextNode->queueList.pstNext = &oldHeadNode->queueList;
newHeadNode->queueList.pstPrev = &tailNode->queueList;
tailNode->queueList.pstNext = &newHeadNode->queueList;
return;
}
STATIC FutexNode *OsFutexRequeueRemoveOldKeyAndGetHead(UINTPTR oldFutexKey, INT32 wakeNumber,
UINTPTR newFutexKey, INT32 requeueCount, BOOL *wakeAny)
{
INT32 ret;
FutexNode *oldHeadNode = NULL;
INT32 oldIndex = oldFutexKey / OS_FUTEX_KEY_BASE;
FutexHash *oldHashNode = &g_futexHash[oldIndex];
FutexNode oldTempNode = {
.key = oldFutexKey,
.index = oldIndex,
.pid = LOS_GetCurrProcessID(),
};
if (wakeNumber > 0) {
ret = OsFutexWakeTask(oldFutexKey, wakeNumber, &oldHeadNode, wakeAny);
if ((ret != LOS_OK) || (oldHeadNode == NULL)) {
return NULL;
}
}
if (requeueCount <= 0) {
return NULL;
}
if (oldHeadNode == NULL) {
oldHeadNode = OsFindFutexNode(&oldTempNode);
if (oldHeadNode == NULL) {
return NULL;
}
}
OsFutexRequeueSplitTwoLists(oldHashNode, oldHeadNode, newFutexKey, requeueCount);
return oldHeadNode;
}
STATIC INT32 OsFutexRequeueParamCheck(UINTPTR oldFutexKey, UINTPTR newFutexKey)
{
if (oldFutexKey == newFutexKey) {
return LOS_EINVAL;
}
if ((oldFutexKey % sizeof(INT32)) || (oldFutexKey < OS_FUTEX_KEY_BASE) || (oldFutexKey >= OS_FUTEX_KEY_MAX)) {
PRINT_ERR("Futex requeue param check failed! error old futex key: 0x%x\n", oldFutexKey);
return LOS_EINVAL;
}
if ((newFutexKey % sizeof(INT32)) || (newFutexKey < OS_FUTEX_KEY_BASE) || (newFutexKey >= OS_FUTEX_KEY_MAX)) {
PRINT_ERR("Futex requeue param check failed! error new futex key: 0x%x\n", newFutexKey);
return LOS_EINVAL;
}
return LOS_OK;
}
INT32 OsFutexRequeue(const UINT32 *userVaddr, UINT32 flags, INT32 wakeNumber, INT32 count, const UINT32 *newUserVaddr)
{
INT32 ret;
UINTPTR oldFutexKey = (UINTPTR)userVaddr;
UINTPTR newFutexKey = (UINTPTR)newUserVaddr;
INT32 oldIndex = oldFutexKey / OS_FUTEX_KEY_BASE;
INT32 newIndex = newFutexKey / OS_FUTEX_KEY_BASE;
FutexHash *oldHashNode = NULL;
FutexHash *newHashNode = NULL;
FutexNode *oldHeadNode = NULL;
BOOL wakeAny = FALSE;
if (OsFutexRequeueParamCheck(oldFutexKey, newFutexKey)) {
return LOS_EINVAL;
}
oldHashNode = &g_futexHash[oldIndex];
if (OsFutexLock(&oldHashNode->listLock)) {
return LOS_EINVAL;
}
oldHeadNode = OsFutexRequeueRemoveOldKeyAndGetHead(oldFutexKey, wakeNumber, newFutexKey, count, &wakeAny);
if (oldHeadNode == NULL) {
(VOID)OsFutexUnlock(&oldHashNode->listLock);
if (wakeAny == TRUE) {
ret = LOS_OK;
goto EXIT;
}
return LOS_EBADF;
}
newHashNode = &g_futexHash[newIndex];
if (oldIndex != newIndex) {
if (OsFutexUnlock(&oldHashNode->listLock)) {
return LOS_EINVAL;
}
if (OsFutexLock(&newHashNode->listLock)) {
return LOS_EINVAL;
}
}
ret = OsFutexRequeueInsertNewKey(newFutexKey, newIndex, oldHeadNode);
if (OsFutexUnlock(&newHashNode->listLock)) {
return LOS_EINVAL;
}
EXIT:
if (wakeAny == TRUE) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
}
return ret;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

90
kernel/base/ipc/los_ipcdebug.c Executable file
View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_ipcdebug_pri.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#if defined(LOSCFG_DEBUG_SEMAPHORE) || defined(LOSCFG_DEBUG_QUEUE)
VOID OsArraySortByTime(UINT32 *sortArray, UINT32 start, UINT32 end, const IpcSortParam *sortParam,
OsCompareFunc compareFunc)
{
UINT32 left = start;
UINT32 right = end;
UINT32 idx = start;
UINT32 pivot = sortArray[start];
while (left < right) {
while ((left < right) && (sortArray[right] < sortParam->ipcDebugCBCnt) && (pivot < sortParam->ipcDebugCBCnt) &&
compareFunc(sortParam, sortArray[right], pivot)) {
right--;
}
if (left < right) {
sortArray[left] = sortArray[right];
idx = right;
left++;
}
while ((left < right) && (sortArray[left] < sortParam->ipcDebugCBCnt) && (pivot < sortParam->ipcDebugCBCnt) &&
compareFunc(sortParam, pivot, sortArray[left])) {
left++;
}
if (left < right) {
sortArray[right] = sortArray[left];
idx = left;
right--;
}
}
sortArray[idx] = pivot;
if (start < idx) {
OsArraySortByTime(sortArray, start, idx - 1, sortParam, compareFunc);
}
if (idx < end) {
OsArraySortByTime(sortArray, idx + 1, end, sortParam, compareFunc);
}
}
#endif
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

612
kernel/base/ipc/los_mux.c Executable file
View File

@@ -0,0 +1,612 @@
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_mux_pri.h"
#include "los_bitmap.h"
#include "los_spinlock.h"
#include "los_mp.h"
#include "los_task_pri.h"
#include "los_exc.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#if (LOSCFG_BASE_IPC_MUX == YES)
#define MUTEXATTR_TYPE_MASK 0x0FU
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrInit(LosMuxAttr *attr)
{
if (attr == NULL) {
return LOS_EINVAL;
}
attr->protocol = LOS_MUX_PRIO_INHERIT;
attr->prioceiling = OS_TASK_PRIORITY_LOWEST;
attr->type = LOS_MUX_DEFAULT;
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrDestroy(LosMuxAttr *attr)
{
if (attr == NULL) {
return LOS_EINVAL;
}
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetType(const LosMuxAttr *attr, INT32 *outType)
{
INT32 type;
if ((attr == NULL) || (outType == NULL)) {
return LOS_EINVAL;
}
type = (INT32)(attr->type & MUTEXATTR_TYPE_MASK);
if ((type < LOS_MUX_NORMAL) || (type > LOS_MUX_ERRORCHECK)) {
return LOS_EINVAL;
}
*outType = type;
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetType(LosMuxAttr *attr, INT32 type)
{
if ((attr == NULL) || (type < LOS_MUX_NORMAL) || (type > LOS_MUX_ERRORCHECK)) {
return LOS_EINVAL;
}
attr->type = (UINT8)((attr->type & ~MUTEXATTR_TYPE_MASK) | (UINT32)type);
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetProtocol(const LosMuxAttr *attr, INT32 *protocol)
{
if ((attr != NULL) && (protocol != NULL)) {
*protocol = attr->protocol;
} else {
return LOS_EINVAL;
}
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetProtocol(LosMuxAttr *attr, INT32 protocol)
{
if (attr == NULL) {
return LOS_EINVAL;
}
switch (protocol) {
case LOS_MUX_PRIO_NONE:
case LOS_MUX_PRIO_INHERIT:
case LOS_MUX_PRIO_PROTECT:
attr->protocol = (UINT8)protocol;
return LOS_OK;
default:
return LOS_EINVAL;
}
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrGetPrioceiling(const LosMuxAttr *attr, INT32 *prioceiling)
{
if (attr == NULL) {
return LOS_EINVAL;
}
if (prioceiling != NULL) {
*prioceiling = attr->prioceiling;
}
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxAttrSetPrioceiling(LosMuxAttr *attr, INT32 prioceiling)
{
if ((attr == NULL) ||
(prioceiling < OS_TASK_PRIORITY_HIGHEST) ||
(prioceiling > OS_TASK_PRIORITY_LOWEST)) {
return LOS_EINVAL;
}
attr->prioceiling = (UINT8)prioceiling;
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxSetPrioceiling(LosMux *mutex, INT32 prioceiling, INT32 *oldPrioceiling)
{
INT32 ret;
INT32 retLock;
if ((mutex == NULL) ||
(prioceiling < OS_TASK_PRIORITY_HIGHEST) ||
(prioceiling > OS_TASK_PRIORITY_LOWEST)) {
return LOS_EINVAL;
}
retLock = LOS_MuxLock(mutex, LOS_WAIT_FOREVER);
if (retLock != LOS_OK) {
return retLock;
}
if (oldPrioceiling != NULL) {
*oldPrioceiling = mutex->attr.prioceiling;
}
ret = LOS_MuxAttrSetPrioceiling(&mutex->attr, prioceiling);
retLock = LOS_MuxUnlock(mutex);
if ((ret == LOS_OK) && (retLock != LOS_OK)) {
return retLock;
}
return ret;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxGetPrioceiling(const LosMux *mutex, INT32 *prioceiling)
{
if ((mutex != NULL) && (prioceiling != NULL) && (mutex->magic == OS_MUX_MAGIC)) {
*prioceiling = mutex->attr.prioceiling;
return LOS_OK;
}
return LOS_EINVAL;
}
LITE_OS_SEC_TEXT BOOL LOS_MuxIsValid(const LosMux *mutex)
{
if ((mutex != NULL) && (mutex->magic == OS_MUX_MAGIC)) {
return TRUE;
}
return FALSE;
}
STATIC UINT32 OsCheckMutexAttr(const LosMuxAttr *attr)
{
if (((INT8)(attr->type) < LOS_MUX_NORMAL) || (attr->type > LOS_MUX_ERRORCHECK)) {
return LOS_NOK;
}
if (((INT8)(attr->prioceiling) < OS_TASK_PRIORITY_HIGHEST) || (attr->prioceiling > OS_TASK_PRIORITY_LOWEST)) {
return LOS_NOK;
}
if (((INT8)(attr->protocol) < LOS_MUX_PRIO_NONE) || (attr->protocol > LOS_MUX_PRIO_PROTECT)) {
return LOS_NOK;
}
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
{
UINT32 intSave;
if (mutex == NULL) {
return LOS_EINVAL;
}
if (attr == NULL) {
(VOID)LOS_MuxAttrInit(&mutex->attr);
} else {
(VOID)memcpy_s(&mutex->attr, sizeof(LosMuxAttr), attr, sizeof(LosMuxAttr));
}
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
return LOS_EINVAL;
}
SCHEDULER_LOCK(intSave);
mutex->muxCount = 0;
mutex->owner = NULL;
LOS_ListInit(&mutex->muxList);
mutex->magic = OS_MUX_MAGIC;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxDestroy(LosMux *mutex)
{
UINT32 intSave;
if (mutex == NULL) {
return LOS_EINVAL;
}
SCHEDULER_LOCK(intSave);
if (mutex->magic != OS_MUX_MAGIC) {
SCHEDULER_UNLOCK(intSave);
return LOS_EBADF;
}
if (mutex->muxCount != 0) {
SCHEDULER_UNLOCK(intSave);
return LOS_EBUSY;
}
(VOID)memset_s(mutex, sizeof(LosMux), 0, sizeof(LosMux));
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
STATIC VOID OsMuxBitmapSet(const LosMux *mutex, const LosTaskCB *runTask, LosTaskCB *owner)
{
if ((owner->priority > runTask->priority) && (mutex->attr.protocol == LOS_MUX_PRIO_INHERIT)) {
LOS_BitmapSet(&(owner->priBitMap), owner->priority);
OsTaskPriModify(owner, runTask->priority);
}
}
VOID OsMuxBitmapRestore(const LosMux *mutex, const LosTaskCB *taskCB, LosTaskCB *owner)
{
UINT16 bitMapPri;
if (mutex->attr.protocol != LOS_MUX_PRIO_INHERIT) {
return;
}
if (owner->priority >= taskCB->priority) {
bitMapPri = LOS_LowBitGet(owner->priBitMap);
if (bitMapPri != LOS_INVALID_BIT_INDEX) {
LOS_BitmapClr(&(owner->priBitMap), bitMapPri);
OsTaskPriModify(owner, bitMapPri);
}
} else {
if (LOS_HighBitGet(owner->priBitMap) != taskCB->priority) {
LOS_BitmapClr(&(owner->priBitMap), taskCB->priority);
}
}
}
STATIC LOS_DL_LIST *OsMuxPendFindPosSub(const LosTaskCB *runTask, const LosMux *mutex)
{
LosTaskCB *pendedTask = NULL;
LOS_DL_LIST *node = NULL;
LOS_DL_LIST_FOR_EACH_ENTRY(pendedTask, &(mutex->muxList), LosTaskCB, pendList) {
if (pendedTask->priority < runTask->priority) {
continue;
} else if (pendedTask->priority > runTask->priority) {
node = &pendedTask->pendList;
break;
} else {
node = pendedTask->pendList.pstNext;
break;
}
}
return node;
}
STATIC LOS_DL_LIST *OsMuxPendFindPos(const LosTaskCB *runTask, LosMux *mutex)
{
LosTaskCB *pendedTask1 = NULL;
LosTaskCB *pendedTask2 = NULL;
LOS_DL_LIST *node = NULL;
if (LOS_ListEmpty(&mutex->muxList)) {
node = &mutex->muxList;
} else {
pendedTask1 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&mutex->muxList));
pendedTask2 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_LAST(&mutex->muxList));
if ((pendedTask1 != NULL) && (pendedTask1->priority > runTask->priority)) {
node = mutex->muxList.pstNext;
} else if ((pendedTask2 != NULL) && (pendedTask2->priority <= runTask->priority)) {
node = &mutex->muxList;
} else {
node = OsMuxPendFindPosSub(runTask, mutex);
}
}
return node;
}
STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
{
UINT32 ret;
LOS_DL_LIST *node = NULL;
LosTaskCB *owner = NULL;
if ((mutex->muxList.pstPrev == NULL) || (mutex->muxList.pstNext == NULL)) {
/* This is for mutex macro initialization. */
mutex->muxCount = 0;
mutex->owner = NULL;
LOS_ListInit(&mutex->muxList);
}
if (mutex->muxCount == 0) {
mutex->muxCount++;
mutex->owner = (VOID *)runTask;
LOS_ListTailInsert(&runTask->lockList, &mutex->holdList);
if ((runTask->priority > mutex->attr.prioceiling) && (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT)) {
LOS_BitmapSet(&runTask->priBitMap, runTask->priority);
OsTaskPriModify(runTask, mutex->attr.prioceiling);
}
return LOS_OK;
}
if (((LosTaskCB *)mutex->owner == runTask) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {
mutex->muxCount++;
return LOS_OK;
}
if (!timeout) {
return LOS_EINVAL;
}
if (!OsPreemptableInSched()) {
return LOS_EDEADLK;
}
OsMuxBitmapSet(mutex, runTask, (LosTaskCB *)mutex->owner);
owner = (LosTaskCB *)mutex->owner;
runTask->taskMux = (VOID *)mutex;
node = OsMuxPendFindPos(runTask, mutex);
ret = OsTaskWait(node, timeout, TRUE);
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
runTask->taskMux = NULL;
ret = LOS_ETIMEDOUT;
}
if (timeout != LOS_WAIT_FOREVER) {
OsMuxBitmapRestore(mutex, runTask, owner);
}
return ret;
}
UINT32 OsMuxLockUnsafe(LosMux *mutex, UINT32 timeout)
{
LosTaskCB *runTask = OsCurrTaskGet();
if (mutex->magic != OS_MUX_MAGIC) {
return LOS_EBADF;
}
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
return LOS_EINVAL;
}
if ((mutex->attr.type == LOS_MUX_ERRORCHECK) && (mutex->muxCount != 0) && (mutex->owner == (VOID *)runTask)) {
return LOS_EDEADLK;
}
return OsMuxPendOp(runTask, mutex, timeout);
}
UINT32 OsMuxTrylockUnsafe(LosMux *mutex, UINT32 timeout)
{
LosTaskCB *runTask = OsCurrTaskGet();
if (mutex->magic != OS_MUX_MAGIC) {
return LOS_EBADF;
}
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
return LOS_EINVAL;
}
if ((mutex->owner != NULL) && ((LosTaskCB *)mutex->owner != runTask)) {
return LOS_EBUSY;
}
if ((mutex->attr.type != LOS_MUX_RECURSIVE) && (mutex->muxCount != 0)) {
return LOS_EBUSY;
}
return OsMuxPendOp(runTask, mutex, timeout);
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
{
LosTaskCB *runTask = NULL;
UINT32 intSave;
UINT32 ret;
if (mutex == NULL) {
return LOS_EINVAL;
}
if (OS_INT_ACTIVE) {
return LOS_EINTR;
}
runTask = (LosTaskCB *)OsCurrTaskGet();
/* DO NOT Call blocking API in system tasks */
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
OsBackTrace();
}
SCHEDULER_LOCK(intSave);
ret = OsMuxLockUnsafe(mutex, timeout);
SCHEDULER_UNLOCK(intSave);
return ret;
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxTrylock(LosMux *mutex)
{
LosTaskCB *runTask = NULL;
UINT32 intSave;
UINT32 ret;
if (mutex == NULL) {
return LOS_EINVAL;
}
if (OS_INT_ACTIVE) {
return LOS_EINTR;
}
runTask = (LosTaskCB *)OsCurrTaskGet();
/* DO NOT Call blocking API in system tasks */
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
OsBackTrace();
}
SCHEDULER_LOCK(intSave);
ret = OsMuxTrylockUnsafe(mutex, 0);
SCHEDULER_UNLOCK(intSave);
return ret;
}
STATIC VOID OsMuxPostOpSub(LosTaskCB *taskCB, LosMux *mutex)
{
LosTaskCB *pendedTask = NULL;
UINT16 bitMapPri;
if (!LOS_ListEmpty(&mutex->muxList)) {
bitMapPri = LOS_HighBitGet(taskCB->priBitMap);
LOS_DL_LIST_FOR_EACH_ENTRY(pendedTask, (&mutex->muxList), LosTaskCB, pendList) {
if (bitMapPri != pendedTask->priority) {
LOS_BitmapClr(&taskCB->priBitMap, pendedTask->priority);
}
}
}
bitMapPri = LOS_LowBitGet(taskCB->priBitMap);
LOS_BitmapClr(&taskCB->priBitMap, bitMapPri);
OsTaskPriModify((LosTaskCB *)mutex->owner, bitMapPri);
}
STATIC UINT32 OsMuxPostOp(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
{
LosTaskCB *resumedTask = NULL;
if (LOS_ListEmpty(&mutex->muxList)) {
LOS_ListDelete(&mutex->holdList);
mutex->owner = NULL;
return LOS_OK;
}
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(mutex->muxList)));
if (mutex->attr.protocol == LOS_MUX_PRIO_INHERIT) {
if (resumedTask->priority > taskCB->priority) {
if (LOS_HighBitGet(taskCB->priBitMap) != resumedTask->priority) {
LOS_BitmapClr(&taskCB->priBitMap, resumedTask->priority);
}
} else if (taskCB->priBitMap != 0) {
OsMuxPostOpSub(taskCB, mutex);
}
}
mutex->muxCount = 1;
mutex->owner = (VOID *)resumedTask;
resumedTask->taskMux = NULL;
LOS_ListDelete(&mutex->holdList);
LOS_ListTailInsert(&resumedTask->lockList, &mutex->holdList);
OsTaskWake(resumedTask);
if (needSched != NULL) {
*needSched = TRUE;
}
return LOS_OK;
}
UINT32 OsMuxUnlockUnsafe(LosTaskCB *taskCB, LosMux *mutex, BOOL *needSched)
{
UINT16 bitMapPri;
if (mutex->magic != OS_MUX_MAGIC) {
return LOS_EBADF;
}
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
return LOS_EINVAL;
}
if (mutex->muxCount == 0) {
return LOS_EPERM;
}
if ((LosTaskCB *)mutex->owner != taskCB) {
return LOS_EPERM;
}
if ((--mutex->muxCount != 0) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {
return LOS_OK;
}
if (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT) {
bitMapPri = LOS_HighBitGet(taskCB->priBitMap);
if (bitMapPri != LOS_INVALID_BIT_INDEX) {
LOS_BitmapClr(&taskCB->priBitMap, bitMapPri);
OsTaskPriModify(taskCB, bitMapPri);
}
}
/* Whether a task block the mutex lock. */
return OsMuxPostOp(taskCB, mutex, needSched);
}
LITE_OS_SEC_TEXT UINT32 LOS_MuxUnlock(LosMux *mutex)
{
LosTaskCB *runTask = NULL;
BOOL needSched = FALSE;
UINT32 intSave;
UINT32 ret;
if (mutex == NULL) {
return LOS_EINVAL;
}
if (OS_INT_ACTIVE) {
return LOS_EINTR;
}
runTask = (LosTaskCB *)OsCurrTaskGet();
/* DO NOT Call blocking API in system tasks */
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
PRINTK("Warning: DO NOT call %s in system tasks.\n", __FUNCTION__);
OsBackTrace();
}
SCHEDULER_LOCK(intSave);
ret = OsMuxUnlockUnsafe(runTask, mutex, &needSched);
SCHEDULER_UNLOCK(intSave);
if (needSched == TRUE) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
}
return ret;
}
#endif /* (LOSCFG_BASE_IPC_MUX == YES) */
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

504
kernel/base/ipc/los_queue.c Executable file
View File

@@ -0,0 +1,504 @@
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_queue_pri.h"
#include "los_queue_debug_pri.h"
#include "los_task_pri.h"
#include "los_spinlock.h"
#include "los_mp.h"
#include "los_percpu_pri.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#if (LOSCFG_BASE_IPC_QUEUE == YES)
#if (LOSCFG_BASE_IPC_QUEUE_LIMIT <= 0)
#error "queue maxnum cannot be zero"
#endif /* LOSCFG_BASE_IPC_QUEUE_LIMIT <= 0 */
LITE_OS_SEC_BSS LosQueueCB *g_allQueue = NULL;
LITE_OS_SEC_BSS STATIC LOS_DL_LIST g_freeQueueList;
/*
* Description : queue initial
* Return : LOS_OK on success or error code on failure
*/
LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID)
{
LosQueueCB *queueNode = NULL;
UINT32 index;
UINT32 size;
size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB);
/* system resident memory, don't free */
g_allQueue = (LosQueueCB *)LOS_MemAlloc(m_aucSysMem0, size);
if (g_allQueue == NULL) {
return LOS_ERRNO_QUEUE_NO_MEMORY;
}
(VOID)memset_s(g_allQueue, size, 0, size);
LOS_ListInit(&g_freeQueueList);
for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
queueNode = ((LosQueueCB *)g_allQueue) + index;
queueNode->queueID = index;
LOS_ListTailInsert(&g_freeQueueList, &queueNode->readWriteList[OS_QUEUE_WRITE]);
}
if (OsQueueDbgInitHook() != LOS_OK) {
return LOS_ERRNO_QUEUE_NO_MEMORY;
}
return LOS_OK;
}
LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueCreate(CHAR *queueName, UINT16 len, UINT32 *queueID,
UINT32 flags, UINT16 maxMsgSize)
{
LosQueueCB *queueCB = NULL;
UINT32 intSave;
LOS_DL_LIST *unusedQueue = NULL;
UINT8 *queue = NULL;
UINT16 msgSize;
(VOID)queueName;
(VOID)flags;
if (queueID == NULL) {
return LOS_ERRNO_QUEUE_CREAT_PTR_NULL;
}
if (maxMsgSize > (OS_NULL_SHORT - sizeof(UINT32))) {
return LOS_ERRNO_QUEUE_SIZE_TOO_BIG;
}
if ((len == 0) || (maxMsgSize == 0)) {
return LOS_ERRNO_QUEUE_PARA_ISZERO;
}
msgSize = maxMsgSize + sizeof(UINT32);
/*
* Memory allocation is time-consuming, to shorten the time of disable interrupt,
* move the memory allocation to here.
*/
queue = (UINT8 *)LOS_MemAlloc(m_aucSysMem1, (UINT32)len * msgSize);
if (queue == NULL) {
return LOS_ERRNO_QUEUE_CREATE_NO_MEMORY;
}
SCHEDULER_LOCK(intSave);
if (LOS_ListEmpty(&g_freeQueueList)) {
SCHEDULER_UNLOCK(intSave);
OsQueueCheckHook();
(VOID)LOS_MemFree(m_aucSysMem1, queue);
return LOS_ERRNO_QUEUE_CB_UNAVAILABLE;
}
unusedQueue = LOS_DL_LIST_FIRST(&g_freeQueueList);
LOS_ListDelete(unusedQueue);
queueCB = GET_QUEUE_LIST(unusedQueue);
queueCB->queueLen = len;
queueCB->queueSize = msgSize;
queueCB->queueHandle = queue;
queueCB->queueState = OS_QUEUE_INUSED;
queueCB->readWriteableCnt[OS_QUEUE_READ] = 0;
queueCB->readWriteableCnt[OS_QUEUE_WRITE] = len;
queueCB->queueHead = 0;
queueCB->queueTail = 0;
LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_READ]);
LOS_ListInit(&queueCB->readWriteList[OS_QUEUE_WRITE]);
LOS_ListInit(&queueCB->memList);
OsQueueDbgUpdateHook(queueCB->queueID, OsCurrTaskGet()->taskEntry);
SCHEDULER_UNLOCK(intSave);
*queueID = queueCB->queueID;
return LOS_OK;
}
STATIC LITE_OS_SEC_TEXT UINT32 OsQueueReadParameterCheck(UINT32 queueID, const VOID *bufferAddr,
const UINT32 *bufferSize, UINT32 timeout)
{
if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
return LOS_ERRNO_QUEUE_INVALID;
}
if ((bufferAddr == NULL) || (bufferSize == NULL)) {
return LOS_ERRNO_QUEUE_READ_PTR_NULL;
}
if ((*bufferSize == 0) || (*bufferSize > (OS_NULL_SHORT - sizeof(UINT32)))) {
return LOS_ERRNO_QUEUE_READSIZE_IS_INVALID;
}
OsQueueDbgTimeUpdateHook(queueID);
if (timeout != LOS_NO_WAIT) {
if (OS_INT_ACTIVE) {
return LOS_ERRNO_QUEUE_READ_IN_INTERRUPT;
}
}
return LOS_OK;
}
STATIC LITE_OS_SEC_TEXT UINT32 OsQueueWriteParameterCheck(UINT32 queueID, const VOID *bufferAddr,
const UINT32 *bufferSize, UINT32 timeout)
{
if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
return LOS_ERRNO_QUEUE_INVALID;
}
if (bufferAddr == NULL) {
return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
}
if (*bufferSize == 0) {
return LOS_ERRNO_QUEUE_WRITESIZE_ISZERO;
}
OsQueueDbgTimeUpdateHook(queueID);
if (timeout != LOS_NO_WAIT) {
if (OS_INT_ACTIVE) {
return LOS_ERRNO_QUEUE_WRITE_IN_INTERRUPT;
}
}
return LOS_OK;
}
STATIC VOID OsQueueBufferOperate(LosQueueCB *queueCB, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize)
{
UINT8 *queueNode = NULL;
UINT32 msgDataSize;
UINT16 queuePosion;
/* get the queue position */
switch (OS_QUEUE_OPERATE_GET(operateType)) {
case OS_QUEUE_READ_HEAD:
queuePosion = queueCB->queueHead;
((queueCB->queueHead + 1) == queueCB->queueLen) ? (queueCB->queueHead = 0) : (queueCB->queueHead++);
break;
case OS_QUEUE_WRITE_HEAD:
(queueCB->queueHead == 0) ? (queueCB->queueHead = queueCB->queueLen - 1) : (--queueCB->queueHead);
queuePosion = queueCB->queueHead;
break;
case OS_QUEUE_WRITE_TAIL:
queuePosion = queueCB->queueTail;
((queueCB->queueTail + 1) == queueCB->queueLen) ? (queueCB->queueTail = 0) : (queueCB->queueTail++);
break;
default: /* read tail, reserved. */
PRINT_ERR("invalid queue operate type!\n");
return;
}
queueNode = &(queueCB->queueHandle[(queuePosion * (queueCB->queueSize))]);
if (OS_QUEUE_IS_READ(operateType)) {
if (memcpy_s(&msgDataSize, sizeof(UINT32), queueNode + queueCB->queueSize - sizeof(UINT32),
sizeof(UINT32)) != EOK) {
PRINT_ERR("get msgdatasize failed\n");
return;
}
if (memcpy_s(bufferAddr, *bufferSize, queueNode, msgDataSize) != EOK) {
PRINT_ERR("copy message to buffer failed\n");
return;
}
*bufferSize = msgDataSize;
} else {
if (memcpy_s(queueNode, queueCB->queueSize, bufferAddr, *bufferSize) != EOK) {
PRINT_ERR("store message failed\n");
return;
}
if (memcpy_s(queueNode + queueCB->queueSize - sizeof(UINT32), sizeof(UINT32), bufferSize,
sizeof(UINT32)) != EOK) {
PRINT_ERR("store message size failed\n");
return;
}
}
}
STATIC UINT32 OsQueueOperateParamCheck(const LosQueueCB *queueCB, UINT32 queueID,
UINT32 operateType, const UINT32 *bufferSize)
{
if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
return LOS_ERRNO_QUEUE_NOT_CREATE;
}
if (OS_QUEUE_IS_READ(operateType) && (*bufferSize < (queueCB->queueSize - sizeof(UINT32)))) {
return LOS_ERRNO_QUEUE_READ_SIZE_TOO_SMALL;
} else if (OS_QUEUE_IS_WRITE(operateType) && (*bufferSize > (queueCB->queueSize - sizeof(UINT32)))) {
return LOS_ERRNO_QUEUE_WRITE_SIZE_TOO_BIG;
}
return LOS_OK;
}
UINT32 OsQueueOperate(UINT32 queueID, UINT32 operateType, VOID *bufferAddr, UINT32 *bufferSize, UINT32 timeout)
{
LosQueueCB *queueCB = NULL;
LosTaskCB *resumedTask = NULL;
UINT32 ret;
UINT32 readWrite = OS_QUEUE_READ_WRITE_GET(operateType);
UINT32 intSave;
SCHEDULER_LOCK(intSave);
queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);
ret = OsQueueOperateParamCheck(queueCB, queueID, operateType, bufferSize);
if (ret != LOS_OK) {
goto QUEUE_END;
}
if (queueCB->readWriteableCnt[readWrite] == 0) {
if (timeout == LOS_NO_WAIT) {
ret = OS_QUEUE_IS_READ(operateType) ? LOS_ERRNO_QUEUE_ISEMPTY : LOS_ERRNO_QUEUE_ISFULL;
goto QUEUE_END;
}
if (!OsPreemptableInSched()) {
ret = LOS_ERRNO_QUEUE_PEND_IN_LOCK;
goto QUEUE_END;
}
ret = OsTaskWait(&queueCB->readWriteList[readWrite], timeout, TRUE);
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
ret = LOS_ERRNO_QUEUE_TIMEOUT;
goto QUEUE_END;
}
} else {
queueCB->readWriteableCnt[readWrite]--;
}
OsQueueBufferOperate(queueCB, operateType, bufferAddr, bufferSize);
if (!LOS_ListEmpty(&queueCB->readWriteList[!readWrite])) {
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&queueCB->readWriteList[!readWrite]));
OsTaskWake(resumedTask);
SCHEDULER_UNLOCK(intSave);
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
return LOS_OK;
} else {
queueCB->readWriteableCnt[!readWrite]++;
}
QUEUE_END:
SCHEDULER_UNLOCK(intSave);
return ret;
}
LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 queueID,
VOID *bufferAddr,
UINT32 *bufferSize,
UINT32 timeout)
{
UINT32 ret;
UINT32 operateType;
ret = OsQueueReadParameterCheck(queueID, bufferAddr, bufferSize, timeout);
if (ret != LOS_OK) {
return ret;
}
operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_READ, OS_QUEUE_HEAD);
return OsQueueOperate(queueID, operateType, bufferAddr, bufferSize, timeout);
}
LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHeadCopy(UINT32 queueID,
VOID *bufferAddr,
UINT32 bufferSize,
UINT32 timeout)
{
UINT32 ret;
UINT32 operateType;
ret = OsQueueWriteParameterCheck(queueID, bufferAddr, &bufferSize, timeout);
if (ret != LOS_OK) {
return ret;
}
operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_WRITE, OS_QUEUE_HEAD);
return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeout);
}
LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteCopy(UINT32 queueID,
VOID *bufferAddr,
UINT32 bufferSize,
UINT32 timeout)
{
UINT32 ret;
UINT32 operateType;
ret = OsQueueWriteParameterCheck(queueID, bufferAddr, &bufferSize, timeout);
if (ret != LOS_OK) {
return ret;
}
operateType = OS_QUEUE_OPERATE_TYPE(OS_QUEUE_WRITE, OS_QUEUE_TAIL);
return OsQueueOperate(queueID, operateType, bufferAddr, &bufferSize, timeout);
}
LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
{
return LOS_QueueReadCopy(queueID, bufferAddr, &bufferSize, timeout);
}
LITE_OS_SEC_TEXT UINT32 LOS_QueueWrite(UINT32 queueID, VOID *bufferAddr, UINT32 bufferSize, UINT32 timeout)
{
if (bufferAddr == NULL) {
return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
}
bufferSize = sizeof(CHAR *);
return LOS_QueueWriteCopy(queueID, &bufferAddr, bufferSize, timeout);
}
LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteHead(UINT32 queueID,
VOID *bufferAddr,
UINT32 bufferSize,
UINT32 timeout)
{
if (bufferAddr == NULL) {
return LOS_ERRNO_QUEUE_WRITE_PTR_NULL;
}
bufferSize = sizeof(CHAR *);
return LOS_QueueWriteHeadCopy(queueID, &bufferAddr, bufferSize, timeout);
}
LITE_OS_SEC_TEXT_INIT UINT32 LOS_QueueDelete(UINT32 queueID)
{
LosQueueCB *queueCB = NULL;
UINT8 *queue = NULL;
UINT32 intSave;
UINT32 ret;
if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
return LOS_ERRNO_QUEUE_NOT_FOUND;
}
SCHEDULER_LOCK(intSave);
queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);
if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
ret = LOS_ERRNO_QUEUE_NOT_CREATE;
goto QUEUE_END;
}
if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_READ])) {
ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
goto QUEUE_END;
}
if (!LOS_ListEmpty(&queueCB->readWriteList[OS_QUEUE_WRITE])) {
ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
goto QUEUE_END;
}
if (!LOS_ListEmpty(&queueCB->memList)) {
ret = LOS_ERRNO_QUEUE_IN_TSKUSE;
goto QUEUE_END;
}
if ((queueCB->readWriteableCnt[OS_QUEUE_WRITE] + queueCB->readWriteableCnt[OS_QUEUE_READ]) !=
queueCB->queueLen) {
ret = LOS_ERRNO_QUEUE_IN_TSKWRITE;
goto QUEUE_END;
}
queue = queueCB->queueHandle;
queueCB->queueHandle = NULL;
queueCB->queueState = OS_QUEUE_UNUSED;
queueCB->queueID = SET_QUEUE_ID(GET_QUEUE_COUNT(queueCB->queueID) + 1, GET_QUEUE_INDEX(queueCB->queueID));
OsQueueDbgUpdateHook(queueCB->queueID, NULL);
LOS_ListTailInsert(&g_freeQueueList, &queueCB->readWriteList[OS_QUEUE_WRITE]);
SCHEDULER_UNLOCK(intSave);
ret = LOS_MemFree(m_aucSysMem1, (VOID *)queue);
return ret;
QUEUE_END:
SCHEDULER_UNLOCK(intSave);
return ret;
}
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_QueueInfoGet(UINT32 queueID, QUEUE_INFO_S *queueInfo)
{
UINT32 intSave;
UINT32 ret = LOS_OK;
LosQueueCB *queueCB = NULL;
LosTaskCB *tskCB = NULL;
if (queueInfo == NULL) {
return LOS_ERRNO_QUEUE_PTR_NULL;
}
if (GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) {
return LOS_ERRNO_QUEUE_INVALID;
}
(VOID)memset_s((VOID *)queueInfo, sizeof(QUEUE_INFO_S), 0, sizeof(QUEUE_INFO_S));
SCHEDULER_LOCK(intSave);
queueCB = (LosQueueCB *)GET_QUEUE_HANDLE(queueID);
if ((queueCB->queueID != queueID) || (queueCB->queueState == OS_QUEUE_UNUSED)) {
ret = LOS_ERRNO_QUEUE_NOT_CREATE;
goto QUEUE_END;
}
queueInfo->uwQueueID = queueID;
queueInfo->usQueueLen = queueCB->queueLen;
queueInfo->usQueueSize = queueCB->queueSize;
queueInfo->usQueueHead = queueCB->queueHead;
queueInfo->usQueueTail = queueCB->queueTail;
queueInfo->usReadableCnt = queueCB->readWriteableCnt[OS_QUEUE_READ];
queueInfo->usWritableCnt = queueCB->readWriteableCnt[OS_QUEUE_WRITE];
LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->readWriteList[OS_QUEUE_READ], LosTaskCB, pendList) {
queueInfo->uwWaitReadTask |= 1ULL << tskCB->taskID;
}
LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->readWriteList[OS_QUEUE_WRITE], LosTaskCB, pendList) {
queueInfo->uwWaitWriteTask |= 1ULL << tskCB->taskID;
}
LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &queueCB->memList, LosTaskCB, pendList) {
queueInfo->uwWaitMemTask |= 1ULL << tskCB->taskID;
}
QUEUE_END:
SCHEDULER_UNLOCK(intSave);
return ret;
}
#endif /* (LOSCFG_BASE_IPC_QUEUE == YES) */
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

208
kernel/base/ipc/los_queue_debug.c Executable file
View File

@@ -0,0 +1,208 @@
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_queue_debug_pri.h"
#include "los_hw_pri.h"
#include "los_ipcdebug_pri.h"
#ifdef LOSCFG_SHELL
#include "shcmd.h"
#endif /* LOSCFG_SHELL */
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#ifdef LOSCFG_DEBUG_QUEUE
typedef struct {
TSK_ENTRY_FUNC creater; /* The task entry who created this queue */
UINT64 lastAccessTime; /* The last access time */
} QueueDebugCB;
STATIC QueueDebugCB *g_queueDebugArray = NULL;
STATIC BOOL QueueCompareValue(const IpcSortParam *sortParam, UINT32 left, UINT32 right)
{
return (*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, left)) >
*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, right)));
}
UINT32 OsQueueDbgInit(VOID)
{
UINT32 size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(QueueDebugCB);
/* system resident memory, don't free */
g_queueDebugArray = (QueueDebugCB *)LOS_MemAlloc(m_aucSysMem1, size);
if (g_queueDebugArray == NULL) {
PRINT_ERR("%s: malloc failed!\n", __FUNCTION__);
return LOS_NOK;
}
(VOID)memset_s(g_queueDebugArray, size, 0, size);
return LOS_OK;
}
VOID OsQueueDbgTimeUpdate(UINT32 queueID)
{
QueueDebugCB *queueDebug = &g_queueDebugArray[GET_QUEUE_INDEX(queueID)];
queueDebug->lastAccessTime = LOS_TickCountGet();
return;
}
VOID OsQueueDbgUpdate(UINT32 queueID, TSK_ENTRY_FUNC entry)
{
QueueDebugCB *queueDebug = &g_queueDebugArray[GET_QUEUE_INDEX(queueID)];
queueDebug->creater = entry;
queueDebug->lastAccessTime = LOS_TickCountGet();
return;
}
STATIC INLINE VOID OsQueueInfoOutPut(const LosQueueCB *node)
{
PRINTK("Queue ID <0x%x> may leak, queue len is 0x%x, "
"readable cnt:0x%x, writeable cnt:0x%x, ",
node->queueID,
node->queueLen,
node->readWriteableCnt[OS_QUEUE_READ],
node->readWriteableCnt[OS_QUEUE_WRITE]);
}
STATIC INLINE VOID OsQueueOpsOutput(const QueueDebugCB *node)
{
PRINTK("TaskEntry of creater:0x%p, Latest operation time: 0x%llx\n",
node->creater, node->lastAccessTime);
}
STATIC VOID SortQueueIndexArray(UINT32 *indexArray, UINT32 count)
{
LosQueueCB queueNode = {0};
QueueDebugCB queueDebugNode = {0};
UINT32 index, intSave;
IpcSortParam queueSortParam;
queueSortParam.buf = (CHAR *)g_queueDebugArray;
queueSortParam.ipcDebugCBSize = sizeof(QueueDebugCB);
queueSortParam.ipcDebugCBCnt = LOSCFG_BASE_IPC_SEM_LIMIT;
queueSortParam.sortElemOff = OFFSET_OF_FIELD(QueueDebugCB, lastAccessTime);
if (count > 0) {
SCHEDULER_LOCK(intSave);
OsArraySortByTime(indexArray, 0, count - 1, &queueSortParam, QueueCompareValue);
SCHEDULER_UNLOCK(intSave);
for (index = 0; index < count; index++) {
SCHEDULER_LOCK(intSave);
(VOID)memcpy_s(&queueNode, sizeof(LosQueueCB),
GET_QUEUE_HANDLE(indexArray[index]), sizeof(LosQueueCB));
(VOID)memcpy_s(&queueDebugNode, sizeof(QueueDebugCB),
&g_queueDebugArray[indexArray[index]], sizeof(QueueDebugCB));
SCHEDULER_UNLOCK(intSave);
if (queueNode.queueState == OS_QUEUE_UNUSED) {
continue;
}
OsQueueInfoOutPut(&queueNode);
OsQueueOpsOutput(&queueDebugNode);
}
}
(VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, indexArray);
}
VOID OsQueueCheck(VOID)
{
LosQueueCB queueNode = {0};
QueueDebugCB queueDebugNode = {0};
UINT32 index, intSave;
UINT32 count = 0;
/*
* This return value does not need to be judged immediately,
* and the following code logic has already distinguished the return value from null and non-empty,
* and there is no case of accessing the null pointer.
*/
UINT32 *indexArray = (UINT32 *)LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(UINT32));
for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
SCHEDULER_LOCK(intSave);
(VOID)memcpy_s(&queueNode, sizeof(LosQueueCB),
GET_QUEUE_HANDLE(index), sizeof(LosQueueCB));
(VOID)memcpy_s(&queueDebugNode, sizeof(QueueDebugCB),
&g_queueDebugArray[index], sizeof(QueueDebugCB));
SCHEDULER_UNLOCK(intSave);
if ((queueNode.queueState == OS_QUEUE_UNUSED) ||
((queueNode.queueState == OS_QUEUE_INUSED) && (queueDebugNode.creater == NULL))) {
continue;
}
if ((queueNode.queueState == OS_QUEUE_INUSED) &&
(queueNode.queueLen == queueNode.readWriteableCnt[OS_QUEUE_WRITE]) &&
LOS_ListEmpty(&queueNode.readWriteList[OS_QUEUE_READ]) &&
LOS_ListEmpty(&queueNode.readWriteList[OS_QUEUE_WRITE]) &&
LOS_ListEmpty(&queueNode.memList)) {
PRINTK("Queue ID <0x%x> may leak, No task uses it, "
"QueueLen is 0x%x, ",
queueNode.queueID,
queueNode.queueLen);
OsQueueOpsOutput(&queueDebugNode);
} else {
if (indexArray != NULL) {
*(indexArray + count) = index;
count++;
} else {
OsQueueInfoOutPut(&queueNode);
OsQueueOpsOutput(&queueDebugNode);
}
}
}
if (indexArray != NULL) {
SortQueueIndexArray(indexArray, count);
}
return;
}
#ifdef LOSCFG_SHELL_CMD_DEBUG
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdQueueInfoGet(UINT32 argc, const CHAR **argv)
{
if (argc > 0) {
PRINTK("\nUsage: queue\n");
return OS_ERROR;
}
PRINTK("used queues information: \n");
OsQueueCheck();
return LOS_OK;
}
SHELLCMD_ENTRY(queue_shellcmd, CMD_TYPE_EX, "queue", 0, (CmdCallBackFunc)OsShellCmdQueueInfoGet);
#endif /* LOSCFG_SHELL */
#endif /* LOSCFG_DEBUG_QUEUE */
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

298
kernel/base/ipc/los_sem.c Executable file
View File

@@ -0,0 +1,298 @@
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_sem_pri.h"
#include "los_sem_debug_pri.h"
#include "los_err_pri.h"
#include "los_task_pri.h"
#include "los_exc.h"
#include "los_spinlock.h"
#include "los_mp.h"
#include "los_percpu_pri.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#if (LOSCFG_BASE_IPC_SEM == YES)
#if (LOSCFG_BASE_IPC_SEM_LIMIT <= 0)
#error "sem maxnum cannot be zero"
#endif /* LOSCFG_BASE_IPC_SEM_LIMIT <= 0 */
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_unusedSemList;
LITE_OS_SEC_BSS LosSemCB *g_allSem = NULL;
/*
* Description : Initialize the semaphore doubly linked list
* Return : LOS_OK on success, or error code on failure
*/
LITE_OS_SEC_TEXT_INIT UINT32 OsSemInit(VOID)
{
LosSemCB *semNode = NULL;
UINT32 index;
LOS_ListInit(&g_unusedSemList);
/* system resident memory, don't free */
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 = SET_SEM_ID(0, index);
semNode->semStat = OS_SEM_UNUSED;
LOS_ListTailInsert(&g_unusedSemList, &semNode->semList);
}
if (OsSemDbgInitHook() != LOS_OK) {
return LOS_ERRNO_SEM_NO_MEMORY;
}
return LOS_OK;
}
/*
* Description : Create a semaphore,
* Input : count --- semaphore count,
* maxCount --- Max number of available semaphores,
* semHandle --- Index of semaphore,
* Return : LOS_OK on success ,or error code on failure
*/
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);
}
SCHEDULER_LOCK(intSave);
if (LOS_ListEmpty(&g_unusedSemList)) {
SCHEDULER_UNLOCK(intSave);
OsSemInfoGetFullDataHook();
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_ALL_BUSY);
}
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;
LOS_ListInit(&semCreated->semList);
*semHandle = semCreated->semID;
OsSemDbgUpdateHook(semCreated->semID, OsCurrTaskGet()->taskEntry, count);
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
ERR_HANDLER:
OS_RETURN_ERROR_P2(errLine, errNo);
}
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemCreate(UINT16 count, UINT32 *semHandle)
{
return OsSemCreate(count, OS_SEM_COUNT_MAX, semHandle);
}
LITE_OS_SEC_TEXT_INIT UINT32 LOS_BinarySemCreate(UINT16 count, UINT32 *semHandle)
{
return OsSemCreate(count, OS_SEM_BINARY_COUNT_MAX, semHandle);
}
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemDelete(UINT32 semHandle)
{
UINT32 intSave;
LosSemCB *semDeleted = NULL;
UINT32 errNo;
UINT32 errLine;
if (GET_SEM_INDEX(semHandle) >= (UINT32)LOSCFG_BASE_IPC_SEM_LIMIT) {
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID);
}
semDeleted = GET_SEM(semHandle);
SCHEDULER_LOCK(intSave);
if ((semDeleted->semStat == OS_SEM_UNUSED) || (semDeleted->semID != semHandle)) {
SCHEDULER_UNLOCK(intSave);
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID);
}
if (!LOS_ListEmpty(&semDeleted->semList)) {
SCHEDULER_UNLOCK(intSave);
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_PENDED);
}
LOS_ListTailInsert(&g_unusedSemList, &semDeleted->semList);
semDeleted->semStat = OS_SEM_UNUSED;
semDeleted->semID = SET_SEM_ID(GET_SEM_COUNT(semDeleted->semID) + 1, GET_SEM_INDEX(semDeleted->semID));
OsSemDbgUpdateHook(semDeleted->semID, NULL, 0);
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
ERR_HANDLER:
OS_RETURN_ERROR_P2(errLine, errNo);
}
LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
{
UINT32 intSave;
LosSemCB *semPended = GET_SEM(semHandle);
UINT32 retErr = LOS_OK;
LosTaskCB *runTask = NULL;
if (GET_SEM_INDEX(semHandle) >= (UINT32)LOSCFG_BASE_IPC_SEM_LIMIT) {
OS_RETURN_ERROR(LOS_ERRNO_SEM_INVALID);
}
if (OS_INT_ACTIVE) {
PRINT_ERR("!!!LOS_ERRNO_SEM_PEND_INTERR!!!\n");
OsBackTrace();
return LOS_ERRNO_SEM_PEND_INTERR;
}
runTask = OsCurrTaskGet();
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
OsBackTrace();
return LOS_ERRNO_SEM_PEND_IN_SYSTEM_TASK;
}
SCHEDULER_LOCK(intSave);
if ((semPended->semStat == OS_SEM_UNUSED) || (semPended->semID != semHandle)) {
retErr = LOS_ERRNO_SEM_INVALID;
goto OUT;
}
/* Update the operate time, no matter the actual Pend success or not */
OsSemDbgTimeUpdateHook(semHandle);
if (semPended->semCount > 0) {
semPended->semCount--;
goto OUT;
} else if (!timeout) {
retErr = LOS_ERRNO_SEM_UNAVAILABLE;
goto OUT;
}
if (!OsPreemptableInSched()) {
PRINT_ERR("!!!LOS_ERRNO_SEM_PEND_IN_LOCK!!!\n");
OsBackTrace();
retErr = LOS_ERRNO_SEM_PEND_IN_LOCK;
goto OUT;
}
runTask->taskSem = (VOID *)semPended;
retErr = OsTaskWait(&semPended->semList, timeout, TRUE);
if (retErr == LOS_ERRNO_TSK_TIMEOUT) {
runTask->taskSem = NULL;
retErr = LOS_ERRNO_SEM_TIMEOUT;
}
OUT:
SCHEDULER_UNLOCK(intSave);
return retErr;
}
LITE_OS_SEC_TEXT UINT32 OsSemPostUnsafe(UINT32 semHandle, BOOL *needSched)
{
LosSemCB *semPosted = NULL;
LosTaskCB *resumedTask = NULL;
if (GET_SEM_INDEX(semHandle) >= LOSCFG_BASE_IPC_SEM_LIMIT) {
return LOS_ERRNO_SEM_INVALID;
}
semPosted = GET_SEM(semHandle);
if ((semPosted->semID != semHandle) || (semPosted->semStat == OS_SEM_UNUSED)) {
return LOS_ERRNO_SEM_INVALID;
}
/* Update the operate time, no matter the actual Post success or not */
OsSemDbgTimeUpdateHook(semHandle);
if (semPosted->semCount == OS_SEM_COUNT_MAX) {
return LOS_ERRNO_SEM_OVERFLOW;
}
if (!LOS_ListEmpty(&semPosted->semList)) {
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(semPosted->semList)));
resumedTask->taskSem = NULL;
OsTaskWake(resumedTask);
if (needSched != NULL) {
*needSched = TRUE;
}
} else {
semPosted->semCount++;
}
return LOS_OK;
}
LITE_OS_SEC_TEXT UINT32 LOS_SemPost(UINT32 semHandle)
{
UINT32 intSave;
UINT32 ret;
BOOL needSched = FALSE;
SCHEDULER_LOCK(intSave);
ret = OsSemPostUnsafe(semHandle, &needSched);
SCHEDULER_UNLOCK(intSave);
if (needSched) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
}
return ret;
}
#endif /* (LOSCFG_BASE_IPC_SEM == YES) */
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

311
kernel/base/ipc/los_sem_debug.c Executable file
View File

@@ -0,0 +1,311 @@
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_sem_debug_pri.h"
#include "stdlib.h"
#include "los_typedef.h"
#include "los_task_pri.h"
#include "los_ipcdebug_pri.h"
#ifdef LOSCFG_SHELL
#include "shcmd.h"
#endif /* LOSCFG_SHELL */
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */
#define OS_ALL_SEM_MASK 0xffffffff
#if defined(LOSCFG_DEBUG_SEMAPHORE) || defined(LOSCFG_SHELL_CMD_DEBUG)
STATIC VOID OsSemPendedTaskNamePrint(LosSemCB *semNode)
{
LosTaskCB *tskCB = NULL;
CHAR *nameArr[LOSCFG_BASE_CORE_TSK_LIMIT] = {0};
UINT32 i, intSave;
UINT32 num = 0;
SCHEDULER_LOCK(intSave);
if ((semNode->semStat == OS_SEM_UNUSED) || (LOS_ListEmpty(&semNode->semList))) {
SCHEDULER_UNLOCK(intSave);
return;
}
LOS_DL_LIST_FOR_EACH_ENTRY(tskCB, &semNode->semList, LosTaskCB, pendList) {
nameArr[num++] = tskCB->taskName;
if (num == LOSCFG_BASE_CORE_TSK_LIMIT) {
break;
}
}
SCHEDULER_UNLOCK(intSave);
PRINTK("Pended task list : ");
for (i = 0; i < num; i++) {
if (i == 0) {
PRINTK("%s\n", nameArr[i]);
} else {
PRINTK(", %s", nameArr[i]);
}
}
PRINTK("\n");
}
#endif
#ifdef LOSCFG_DEBUG_SEMAPHORE
typedef struct {
UINT16 origSemCount; /* Number of orignal available semaphores */
UINT64 lastAccessTime; /* The last operation time */
TSK_ENTRY_FUNC creater; /* The task entry who created this sem */
} SemDebugCB;
STATIC SemDebugCB *g_semDebugArray = NULL;
STATIC BOOL SemCompareValue(const IpcSortParam *sortParam, UINT32 left, UINT32 right)
{
return (*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, left)) >
*((UINT64 *)(VOID *)SORT_ELEM_ADDR(sortParam, right)));
}
UINT32 OsSemDbgInit(VOID)
{
UINT32 size = LOSCFG_BASE_IPC_SEM_LIMIT * sizeof(SemDebugCB);
/* system resident memory, don't free */
g_semDebugArray = (SemDebugCB *)LOS_MemAlloc(m_aucSysMem1, size);
if (g_semDebugArray == NULL) {
PRINT_ERR("%s: malloc failed!\n", __FUNCTION__);
return LOS_NOK;
}
(VOID)memset_s(g_semDebugArray, size, 0, size);
return LOS_OK;
}
VOID OsSemDbgTimeUpdate(UINT32 semID)
{
SemDebugCB *semDebug = &g_semDebugArray[GET_SEM_INDEX(semID)];
semDebug->lastAccessTime = LOS_TickCountGet();
return;
}
VOID OsSemDbgUpdate(UINT32 semID, TSK_ENTRY_FUNC creater, UINT16 count)
{
SemDebugCB *semDebug = &g_semDebugArray[GET_SEM_INDEX(semID)];
semDebug->creater = creater;
semDebug->lastAccessTime = LOS_TickCountGet();
semDebug->origSemCount = count;
return;
}
STATIC VOID OsSemSort(UINT32 *semIndexArray, UINT32 usedCount)
{
UINT32 i, intSave;
LosSemCB *semCB = NULL;
LosSemCB semNode = {0};
SemDebugCB semDebug = {0};
IpcSortParam semSortParam;
semSortParam.buf = (CHAR *)g_semDebugArray;
semSortParam.ipcDebugCBSize = sizeof(SemDebugCB);
semSortParam.ipcDebugCBCnt = LOSCFG_BASE_IPC_SEM_LIMIT;
semSortParam.sortElemOff = OFFSET_OF_FIELD(SemDebugCB, lastAccessTime);
/* It will Print out ALL the Used Semaphore List. */
PRINTK("Used Semaphore List: \n");
PRINTK("\r\n SemID Count OriginalCount Creater(TaskEntry) LastAccessTime\n");
PRINTK(" ------ ------ ------------- ------------------ -------------- \n");
SCHEDULER_LOCK(intSave);
OsArraySortByTime(semIndexArray, 0, usedCount - 1, &semSortParam, SemCompareValue);
SCHEDULER_UNLOCK(intSave);
for (i = 0; i < usedCount; i++) {
semCB = GET_SEM(semIndexArray[i]);
SCHEDULER_LOCK(intSave);
(VOID)memcpy_s(&semNode, sizeof(LosSemCB), semCB, sizeof(LosSemCB));
(VOID)memcpy_s(&semDebug, sizeof(SemDebugCB), &g_semDebugArray[semIndexArray[i]], sizeof(SemDebugCB));
SCHEDULER_UNLOCK(intSave);
if ((semNode.semStat != OS_SEM_USED) || (semDebug.creater == NULL)) {
continue;
}
PRINTK(" 0x%-07x0x%-07u0x%-14u%-22p0x%llx\n", semNode.semID, semDebug.origSemCount,
semNode.semCount, semDebug.creater, semDebug.lastAccessTime);
if (!LOS_ListEmpty(&semNode.semList)) {
OsSemPendedTaskNamePrint(semCB);
}
}
}
UINT32 OsSemInfoGetFullData(VOID)
{
UINT32 usedSemCnt = 0;
LosSemCB *semNode = NULL;
SemDebugCB *semDebug = NULL;
UINT32 i;
UINT32 *semIndexArray = NULL;
UINT32 count, intSave;
SCHEDULER_LOCK(intSave);
/* Get the used semaphore count. */
for (i = 0; i < LOSCFG_BASE_IPC_SEM_LIMIT; i++) {
semNode = GET_SEM(i);
semDebug = &g_semDebugArray[i];
if ((semNode->semStat == OS_SEM_USED) && (semDebug->creater != NULL)) {
usedSemCnt++;
}
}
SCHEDULER_UNLOCK(intSave);
if (usedSemCnt > 0) {
semIndexArray = (UINT32 *)LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, usedSemCnt * sizeof(UINT32));
if (semIndexArray == NULL) {
PRINTK("LOS_MemAlloc failed in %s \n", __func__);
return LOS_NOK;
}
/* Fill the semIndexArray with the real index. */
count = 0;
SCHEDULER_LOCK(intSave);
for (i = 0; i < LOSCFG_BASE_IPC_SEM_LIMIT; i++) {
semNode = GET_SEM(i);
semDebug = &g_semDebugArray[i];
if ((semNode->semStat != OS_SEM_USED) || (semDebug->creater == NULL)) {
continue;
}
*(semIndexArray + count) = i;
count++;
/* if the count is touched usedSemCnt break. */
if (count >= usedSemCnt) {
break;
}
}
SCHEDULER_UNLOCK(intSave);
OsSemSort(semIndexArray, count);
/* free the index array. */
(VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, semIndexArray);
}
return LOS_OK;
}
#endif /* LOSCFG_DEBUG_SEMAPHORE */
#ifdef LOSCFG_SHELL_CMD_DEBUG
STATIC UINT32 OsSemInfoOutput(size_t semID)
{
UINT32 loop, semCnt, intSave;
LosSemCB *semCB = NULL;
LosSemCB semNode = {0};
if (semID == OS_ALL_SEM_MASK) {
for (loop = 0, semCnt = 0; loop < LOSCFG_BASE_IPC_SEM_LIMIT; loop++) {
semCB = GET_SEM(loop);
SCHEDULER_LOCK(intSave);
if (semCB->semStat == OS_SEM_USED) {
(VOID)memcpy_s(&semNode, sizeof(LosSemCB), semCB, sizeof(LosSemCB));
SCHEDULER_UNLOCK(intSave);
semCnt++;
PRINTK("\r\n SemID Count\n ---------- -----\n");
PRINTK(" 0x%08x %u\n", semNode.semID, semNode.semCount);
continue;
}
SCHEDULER_UNLOCK(intSave);
}
PRINTK(" SemUsingNum : %u\n\n", semCnt);
return LOS_OK;
} else {
if (GET_SEM_INDEX(semID) >= LOSCFG_BASE_IPC_SEM_LIMIT) {
PRINTK("\nInvalid semphore id!\n");
return LOS_OK;
}
semCB = GET_SEM(semID);
SCHEDULER_LOCK(intSave);
(VOID)memcpy_s(&semNode, sizeof(LosSemCB), semCB, sizeof(LosSemCB));
SCHEDULER_UNLOCK(intSave);
if ((semNode.semID != semID) || (semNode.semStat != OS_SEM_USED)) {
PRINTK("\nThe semphore is not in use!\n");
return LOS_OK;
}
PRINTK("\r\n SemID Count\n ---------- -----\n");
PRINTK(" 0x%08x 0x%u\n", semNode.semID, semNode.semCount);
if (LOS_ListEmpty(&semNode.semList)) {
PRINTK("No task is pended on this semphore!\n");
return LOS_OK;
} else {
OsSemPendedTaskNamePrint(semCB);
}
}
return LOS_OK;
}
LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdSemInfoGet(UINT32 argc, const CHAR **argv)
{
size_t semID;
CHAR *endPtr = NULL;
UINT32 ret;
if (argc > 1) {
#ifdef LOSCFG_DEBUG_SEMAPHORE
PRINTK("\nUsage: sem [fulldata|ID]\n");
#else
PRINTK("\nUsage: sem [ID]\n");
#endif
return OS_ERROR;
}
if (argc == 0) {
semID = OS_ALL_SEM_MASK;
} else {
#ifdef LOSCFG_DEBUG_SEMAPHORE
if (strcmp(argv[0], "fulldata") == 0) {
ret = OsSemInfoGetFullData();
return ret;
}
#endif
semID = strtoul(argv[0], &endPtr, 0);
if ((endPtr == NULL) || (*endPtr != 0)) {
PRINTK("\nsem ID can't access %s.\n", argv[0]);
return 0;
}
}
ret = OsSemInfoOutput(semID);
return ret;
}
SHELLCMD_ENTRY(sem_shellcmd, CMD_TYPE_EX, "sem", 1, (CmdCallBackFunc)OsShellCmdSemInfoGet);
#endif
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

691
kernel/base/ipc/los_signal.c Executable file
View File

@@ -0,0 +1,691 @@
/*
* Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "los_signal.h"
#include "pthread.h"
#include "los_process_pri.h"
#include "los_hw_pri.h"
#include "user_copy.h"
#ifdef LOSCFG_SECURITY_CAPABILITY
#include "capability_api.h"
#endif
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
int raise(int sig)
{
(VOID)sig;
PRINT_ERR("%s NOT SUPPORT\n", __FUNCTION__);
errno = ENOSYS;
return -1;
}
#define GETUNMASKSET(procmask, pendFlag) ((~(procmask)) & (sigset_t)(pendFlag))
#define UINT64_BIT_SIZE 64
int OsSigIsMember(const sigset_t *set, int signo)
{
int ret = LOS_NOK;
/* In musl, sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
signo -= 1;
/* Verify the signal */
if (GOOD_SIGNO(signo)) {
/* Check if the signal is in the set */
ret = ((*set & SIGNO2SET((unsigned int)signo)) != 0);
}
return ret;
}
int OsTcbDispatch(LosTaskCB *stcb, siginfo_t *info)
{
bool masked = FALSE;
sig_cb *sigcb = &stcb->sig;
OS_RETURN_IF_NULL(sigcb);
/* If signo is 0, not send signal, just check process or pthread exist */
if (info->si_signo == 0) {
return 0;
}
masked = (bool)OsSigIsMember(&sigcb->sigprocmask, info->si_signo);
if (masked) {
/* If signal is in wait list and mask list, need unblock it */
if (!LOS_ListEmpty(&sigcb->waitList) && OsSigIsMember(&sigcb->sigwaitmask, info->si_signo)) {
OsTaskWake(stcb);
OsSigEmptySet(&sigcb->sigwaitmask);
} else {
OsSigAddSet(&sigcb->sigPendFlag, info->si_signo);
}
} else {
/* unmasked signal actions */
OsSigAddSet(&sigcb->sigFlag, info->si_signo);
if (!LOS_ListEmpty(&sigcb->waitList) && OsSigIsMember(&sigcb->sigwaitmask, info->si_signo)) {
OsTaskWake(stcb);
OsSigEmptySet(&sigcb->sigwaitmask);
}
}
(void) memcpy_s(&sigcb->sigunbinfo, sizeof(siginfo_t), info, sizeof(siginfo_t));
return 0;
}
void OsSigMaskSwitch(LosTaskCB * const rtcb, sigset_t set)
{
sigset_t unmaskset;
rtcb->sig.sigprocmask = set;
unmaskset = GETUNMASKSET(rtcb->sig.sigprocmask, rtcb->sig.sigPendFlag);
if (unmaskset != NULL_SIGNAL_SET) {
/* pendlist do */
rtcb->sig.sigFlag |= unmaskset;
rtcb->sig.sigPendFlag ^= unmaskset;
}
}
int OsSigprocMask(int how, const sigset_t_l *setl, sigset_t_l *oldset)
{
LosTaskCB *spcb = NULL;
sigset_t oldSigprocmask;
int ret = LOS_OK;
unsigned int intSave;
sigset_t set;
int retVal;
if (setl != NULL) {
retVal = LOS_ArchCopyFromUser(&set, &(setl->sig[0]), sizeof(sigset_t));
if (retVal != 0) {
return -EFAULT;
}
}
SCHEDULER_LOCK(intSave);
spcb = OsCurrTaskGet();
/* If requested, copy the old mask to user. */
oldSigprocmask = spcb->sig.sigprocmask;
/* If requested, modify the current signal mask. */
if (setl != NULL) {
/* Okay, determine what we are supposed to do */
switch (how) {
/* Set the union of the current set and the signal
* set pointed to by set as the new sigprocmask.
*/
case SIG_BLOCK:
spcb->sig.sigprocmask |= set;
break;
/* Set the intersection of the current set and the
* signal set pointed to by set as the new sigprocmask.
*/
case SIG_UNBLOCK:
spcb->sig.sigprocmask &= ~(set);
break;
/* Set the signal set pointed to by set as the new sigprocmask. */
case SIG_SETMASK:
spcb->sig.sigprocmask = set;
break;
default:
ret = -EINVAL;
break;
}
/* If pending mask not in sigmask, need set sigflag. */
OsSigMaskSwitch(spcb, spcb->sig.sigprocmask);
}
SCHEDULER_UNLOCK(intSave);
if (oldset != NULL) {
retVal = LOS_ArchCopyToUser(&(oldset->sig[0]), &oldSigprocmask, sizeof(sigset_t));
if (retVal != 0) {
return -EFAULT;
}
}
return ret;
}
int OsSigProcessForeachChild(LosProcessCB *spcb, ForEachTaskCB handler, void *arg)
{
int ret;
/* Visit the main thread last (if present) */
LosTaskCB *taskCB = NULL;
LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &(spcb->threadSiblingList), LosTaskCB, threadList) {
ret = handler(taskCB, arg);
OS_RETURN_IF(ret != 0, ret);
}
return LOS_OK;
}
static int SigProcessSignalHandler(LosTaskCB *tcb, void *arg)
{
struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;
int ret;
int isMember;
if (tcb == NULL) {
return 0;
}
/* If the default tcb is not setted, then set this one as default. */
if (!info->defaultTcb) {
info->defaultTcb = tcb;
}
isMember = OsSigIsMember(&tcb->sig.sigwaitmask, info->sigInfo->si_signo);
if (isMember && (!info->awakenedTcb)) {
/* This means the task is waiting for this signal. Stop looking for it and use this tcb.
* The requirement is: if more than one task in this task group is waiting for the signal,
* then only one indeterminate task in the group will receive the signal.
*/
ret = OsTcbDispatch(tcb, info->sigInfo);
OS_RETURN_IF(ret < 0, ret);
/* set this tcb as awakenedTcb */
info->awakenedTcb = tcb;
OS_RETURN_IF(info->receivedTcb != NULL, SIG_STOP_VISIT); /* Stop search */
}
/* Is this signal unblocked on this thread? */
isMember = OsSigIsMember(&tcb->sig.sigprocmask, info->sigInfo->si_signo);
if ((!isMember) && (!info->receivedTcb) && (tcb != info->awakenedTcb)) {
/* if unblockedTcb of this signal is not setted, then set it. */
if (!info->unblockedTcb) {
info->unblockedTcb = tcb;
}
ret = OsTcbDispatch(tcb, info->sigInfo);
OS_RETURN_IF(ret < 0, ret);
/* set this tcb as receivedTcb */
info->receivedTcb = tcb;
OS_RETURN_IF(info->awakenedTcb != NULL, SIG_STOP_VISIT); /* Stop search */
}
return 0; /* Keep searching */
}
static int SigProcessKillSigHandler(LosTaskCB *tcb, void *arg)
{
struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;
if ((tcb != NULL) && (info != NULL) && (info->sigInfo != NULL)) {
sig_cb *sigcb = &tcb->sig;
if (!LOS_ListEmpty(&sigcb->waitList) && OsSigIsMember(&sigcb->sigwaitmask, info->sigInfo->si_signo)) {
OsTaskWake(tcb);
OsSigEmptySet(&sigcb->sigwaitmask);
}
}
return 0;
}
static void SigProcessLoadTcb(struct ProcessSignalInfo *info, siginfo_t *sigInfo)
{
LosTaskCB *tcb = NULL;
if (info->awakenedTcb == NULL && info->receivedTcb == NULL) {
if (info->unblockedTcb) {
tcb = info->unblockedTcb;
} else if (info->defaultTcb) {
tcb = info->defaultTcb;
} else {
return;
}
/* Deliver the signal to the selected task */
(void)OsTcbDispatch(tcb, sigInfo);
}
}
int OsSigProcessSend(LosProcessCB *spcb, siginfo_t *sigInfo)
{
int ret;
struct ProcessSignalInfo info = {
.sigInfo = sigInfo,
.defaultTcb = NULL,
.unblockedTcb = NULL,
.awakenedTcb = NULL,
.receivedTcb = NULL
};
/* visit all taskcb and dispatch signal */
if ((info.sigInfo != NULL) && (info.sigInfo->si_signo == SIGKILL)) {
(void)OsSigProcessForeachChild(spcb, SigProcessKillSigHandler, &info);
OsSigAddSet(&spcb->sigShare, info.sigInfo->si_signo);
OsWaitSignalToWakeProcess(spcb);
return 0;
} else {
ret = OsSigProcessForeachChild(spcb, SigProcessSignalHandler, &info);
}
if (ret < 0) {
return ret;
}
SigProcessLoadTcb(&info, sigInfo);
return 0;
}
int OsSigEmptySet(sigset_t *set)
{
*set = NULL_SIGNAL_SET;
return 0;
}
/* Privilege process can't send to kernel and privilege process */
static int OsSignalPermissionToCheck(const LosProcessCB *spcb)
{
UINT32 gid = spcb->group->groupID;
if (gid == OS_KERNEL_PROCESS_GROUP) {
return -EPERM;
} else if (gid == OS_USER_PRIVILEGE_PROCESS_GROUP) {
return -EPERM;
}
return 0;
}
int OsDispatch(pid_t pid, siginfo_t *info, int permission)
{
LosProcessCB *spcb = OS_PCB_FROM_PID(pid);
if (OsProcessIsUnused(spcb)) {
return -ESRCH;
}
#ifdef LOSCFG_SECURITY_CAPABILITY
LosProcessCB *current = OsCurrProcessGet();
/* If the process you want to kill had been inactive, but still exist. should return LOS_OK */
if (OsProcessIsInactive(spcb)) {
return LOS_OK;
}
/* Kernel process always has kill permission and user process should check permission */
if (OsProcessIsUserMode(current) && !(current->processStatus & OS_PROCESS_FLAG_EXIT)) {
if ((current != spcb) && (!IsCapPermit(CAP_KILL)) && (current->user->userID != spcb->user->userID)) {
return -EPERM;
}
}
#endif
if ((permission == OS_USER_KILL_PERMISSION) && (OsSignalPermissionToCheck(spcb) < 0)) {
return -EPERM;
}
return OsSigProcessSend(spcb, info);
}
int OsKill(pid_t pid, int sig, int permission)
{
siginfo_t info;
int ret;
/* Make sure that the para is valid */
if (!GOOD_SIGNO(sig) || pid < 0) {
return -EINVAL;
}
if (OsProcessIDUserCheckInvalid(pid)) {
return -ESRCH;
}
/* Create the siginfo structure */
info.si_signo = sig;
info.si_code = SI_USER;
info.si_value.sival_ptr = NULL;
/* Send the signal */
ret = OsDispatch(pid, &info, permission);
return ret;
}
int OsKillLock(pid_t pid, int sig)
{
int ret;
unsigned int intSave;
SCHEDULER_LOCK(intSave);
ret = OsKill(pid, sig, OS_USER_KILL_PERMISSION);
SCHEDULER_UNLOCK(intSave);
return ret;
}
int OsPthreadKill(UINT32 tid, int signo)
{
LosTaskCB *stcb = NULL;
siginfo_t info;
int ret;
UINT32 intSave;
/* Make sure that the signal is valid */
OS_RETURN_IF(!GOOD_SIGNO(signo), -EINVAL);
if (OS_TID_CHECK_INVALID(tid)) {
return -ESRCH;
}
/* Create the siginfo structure */
info.si_signo = signo;
info.si_code = SI_USER;
info.si_value.sival_ptr = NULL;
/* Keep things stationary through the following */
SCHEDULER_LOCK(intSave);
/* Get the TCB associated with the thread */
stcb = OsGetTaskCB(tid);
OS_GOTO_EXIT_IF(stcb == NULL, -ESRCH);
ret = OsUserTaskOperatePermissionsCheck(stcb);
OS_GOTO_EXIT_IF(ret != LOS_OK, -ret);
/* Dispatch the signal to thread, bypassing normal task group thread
* dispatch rules. */
ret = OsTcbDispatch(stcb, &info);
EXIT:
SCHEDULER_UNLOCK(intSave);
return ret;
}
int OsSigAddSet(sigset_t *set, int signo)
{
/* Verify the signal */
if (!GOOD_SIGNO(signo)) {
return -EINVAL;
} else {
/* In musl, sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
signo -= 1;
/* Add the signal to the set */
*set |= SIGNO2SET((unsigned int)signo);
return LOS_OK;
}
}
int OsSigPending(sigset_t *set)
{
LosTaskCB *tcb = NULL;
unsigned int intSave;
if (set == NULL) {
return -EFAULT;
}
SCHEDULER_LOCK(intSave);
tcb = OsCurrTaskGet();
*set = tcb->sig.sigPendFlag;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
STATIC int FindFirstSetedBit(UINT64 n)
{
int count;
if (n == 0) {
return -1;
}
for (count = 0; (count < UINT64_BIT_SIZE) && (n ^ 1ULL); n >>= 1, count++) {}
return (count < UINT64_BIT_SIZE) ? count : (-1);
}
int OsSigTimedWaitNoLock(sigset_t *set, siginfo_t *info, unsigned int timeout)
{
LosTaskCB *task = NULL;
sig_cb *sigcb = NULL;
int ret;
task = OsCurrTaskGet();
sigcb = &task->sig;
if (sigcb->waitList.pstNext == NULL) {
LOS_ListInit(&sigcb->waitList);
}
/* If pendingflag & set > 0, shound clear pending flag */
sigset_t clear = sigcb->sigPendFlag & *set;
if (clear) {
sigcb->sigPendFlag ^= clear;
ret = FindFirstSetedBit((UINT64)clear) + 1;
} else {
OsSigAddSet(set, SIGKILL);
OsSigAddSet(set, SIGSTOP);
sigcb->sigwaitmask |= *set;
ret = OsTaskWait(&sigcb->waitList, timeout, TRUE);
if (ret == LOS_ERRNO_TSK_TIMEOUT) {
ret = -EAGAIN;
}
sigcb->sigwaitmask = NULL_SIGNAL_SET;
}
if (info != NULL) {
(void) memcpy_s(info, sizeof(siginfo_t), &sigcb->sigunbinfo, sizeof(siginfo_t));
}
return ret;
}
int OsSigTimedWait(sigset_t *set, siginfo_t *info, unsigned int timeout)
{
int ret;
unsigned int intSave;
SCHEDULER_LOCK(intSave);
ret = OsSigTimedWaitNoLock(set, info, timeout);
SCHEDULER_UNLOCK(intSave);
return ret;
}
int OsPause(void)
{
LosTaskCB *spcb = NULL;
sigset_t oldSigprocmask;
spcb = OsCurrTaskGet();
oldSigprocmask = spcb->sig.sigprocmask;
return OsSigSuspend(&oldSigprocmask);
}
int OsSigSuspend(const sigset_t *set)
{
unsigned int intSave;
LosTaskCB *rtcb = NULL;
unsigned int sigTempProcMask;
sigset_t setSuspend;
int ret;
if (set == NULL) {
return -EINVAL;
}
SCHEDULER_LOCK(intSave);
rtcb = OsCurrTaskGet();
sigTempProcMask = rtcb->sig.sigprocmask;
/* Wait signal calc */
setSuspend = FULL_SIGNAL_SET & (~(*set));
/* If pending mask not in sigmask, need set sigflag */
OsSigMaskSwitch(rtcb, *set);
ret = OsSigTimedWaitNoLock(&setSuspend, NULL, LOS_WAIT_FOREVER);
if (ret < 0) {
PRINT_ERR("FUNC %s LINE = %d, ret = %x\n", __FUNCTION__, __LINE__, ret);
}
/* Restore old sigprocmask */
OsSigMaskSwitch(rtcb, sigTempProcMask);
SCHEDULER_UNLOCK(intSave);
return -EINTR;
}
int OsSigAction(int sig, const sigaction_t *act, sigaction_t *oact)
{
UINTPTR addr;
sigaction_t action;
if (!GOOD_SIGNO(sig) || sig < 1 || act == NULL) {
return -EINVAL;
}
if (LOS_ArchCopyFromUser(&action, act, sizeof(sigaction_t)) != LOS_OK) {
return -EFAULT;
}
if (sig == SIGSYS) {
addr = OsGetSigHandler();
if (addr == 0) {
OsSetSigHandler((unsigned long)(UINTPTR)action.sa_handler);
return LOS_OK;
}
return -EINVAL;
}
return LOS_OK;
}
void OsSaveSignalContext(unsigned int *sp)
{
UINTPTR sigHandler;
UINT32 intSave;
LosTaskCB *task = NULL;
LosProcessCB *process = NULL;
sig_cb *sigcb = NULL;
unsigned long cpsr;
OS_RETURN_IF_VOID(sp == NULL);
cpsr = OS_SYSCALL_GET_CPSR(sp);
OS_RETURN_IF_VOID(((cpsr & CPSR_MASK_MODE) != CPSR_USER_MODE));
SCHEDULER_LOCK(intSave);
task = OsCurrTaskGet();
process = OsCurrProcessGet();
sigcb = &task->sig;
if ((sigcb->context.count == 0) && ((sigcb->sigFlag != 0) || (process->sigShare != 0))) {
sigHandler = OsGetSigHandler();
if (sigHandler == 0) {
sigcb->sigFlag = 0;
process->sigShare = 0;
SCHEDULER_UNLOCK(intSave);
PRINT_ERR("The signal processing function for the current process pid =%d is NULL!\n", task->processID);
return;
}
/* One pthread do the share signal */
sigcb->sigFlag |= process->sigShare;
unsigned int signo = (unsigned int)FindFirstSetedBit(sigcb->sigFlag) + 1;
OsProcessExitCodeSignalSet(process, signo);
sigcb->context.CPSR = cpsr;
sigcb->context.PC = sp[REG_PC];
sigcb->context.USP = sp[REG_SP];
sigcb->context.ULR = sp[REG_LR];
sigcb->context.R0 = sp[REG_R0];
sigcb->context.R1 = sp[REG_R1];
sigcb->context.R2 = sp[REG_R2];
sigcb->context.R3 = sp[REG_R3];
sigcb->context.R7 = sp[REG_R7];
sigcb->context.R12 = sp[REG_R12];
sp[REG_PC] = sigHandler;
sp[REG_R0] = signo;
sp[REG_R1] = (unsigned int)(UINTPTR)(sigcb->sigunbinfo.si_value.sival_ptr);
/* sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
sigcb->sigFlag ^= 1ULL << (signo - 1);
sigcb->context.count++;
}
SCHEDULER_UNLOCK(intSave);
}
void OsSaveSignalContextIrq(unsigned int *sp, unsigned int r7)
{
UINTPTR sigHandler;
LosTaskCB *task = NULL;
LosProcessCB *process = NULL;
sig_cb *sigcb = NULL;
unsigned long cpsr;
UINT32 intSave;
TaskIrqContext *context = (TaskIrqContext *)(sp);
OS_RETURN_IF_VOID(sp == NULL);
cpsr = context->CPSR;
OS_RETURN_IF_VOID(((cpsr & CPSR_MASK_MODE) != CPSR_USER_MODE));
SCHEDULER_LOCK(intSave);
task = OsCurrTaskGet();
process = OsCurrProcessGet();
sigcb = &task->sig;
if ((sigcb->context.count == 0) && ((sigcb->sigFlag != 0) || (process->sigShare != 0))) {
sigHandler = OsGetSigHandler();
if (sigHandler == 0) {
sigcb->sigFlag = 0;
process->sigShare = 0;
SCHEDULER_UNLOCK(intSave);
PRINT_ERR("The current process pid =%d starts fail!\n", task->processID);
return;
}
sigcb->sigFlag |= process->sigShare;
unsigned int signo = (unsigned int)FindFirstSetedBit(sigcb->sigFlag) + 1;
OsProcessExitCodeSignalSet(process, signo);
(VOID)memcpy_s(&sigcb->context.R0, sizeof(TaskIrqDataSize), &context->R0, sizeof(TaskIrqDataSize));
sigcb->context.R7 = r7;
context->PC = sigHandler;
context->R0 = signo;
context->R1 = (UINT32)(UINTPTR)sigcb->sigunbinfo.si_value.sival_ptr;
/* sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
sigcb->sigFlag ^= 1ULL << (signo - 1);
sigcb->context.count++;
}
SCHEDULER_UNLOCK(intSave);
}
void OsRestorSignalContext(unsigned int *sp)
{
LosTaskCB *task = NULL; /* Do not adjust this statement */
LosProcessCB *process = NULL;
sig_cb *sigcb = NULL;
UINT32 intSave;
SCHEDULER_LOCK(intSave);
task = OsCurrTaskGet();
sigcb = &task->sig;
if (sigcb->context.count != 1) {
SCHEDULER_UNLOCK(intSave);
PRINT_ERR("sig error count : %d\n", sigcb->context.count);
return;
}
process = OsCurrProcessGet();
sp[REG_PC] = sigcb->context.PC;
OS_SYSCALL_SET_CPSR(sp, sigcb->context.CPSR);
sp[REG_SP] = sigcb->context.USP;
sp[REG_LR] = sigcb->context.ULR;
sp[REG_R0] = sigcb->context.R0;
sp[REG_R1] = sigcb->context.R1;
sp[REG_R2] = sigcb->context.R2;
sp[REG_R3] = sigcb->context.R3;
sp[REG_R7] = sigcb->context.R7;
sp[REG_R12] = sigcb->context.R12;
sigcb->context.count--;
process->sigShare = 0;
OsProcessExitCodeSignalClear(process);
SCHEDULER_UNLOCK(intSave);
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */