/* * Copyright (c) 2020 AIIT XUOS Lab * XiUOS is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ /** * @file: waitqueue.c * @brief: waitqueue file * @version: 1.0 * @author: AIIT XUOS Lab * @date: 2020/3/15 * */ #include #include #include #include #include /** * This function will add a waitqueue node to the wait queue list *@parm queue waitqueue descriptor *@parm work the node need to be added * */ void WqueueAdd(WaitQueueType *queue, struct WaitqueueNode *node) { x_base lock = 0; NULL_PARAM_CHECK(queue); NULL_PARAM_CHECK(node); lock = CriticalAreaLock(); DoubleLinkListInsertNodeBefore(&(queue->block_threads_list), &(node->list)); CriticalAreaUnLock(lock); } /** * This function will remove a waitqueue node from the wait queue list *@parm work the node need to be removed * */ void WqueueRemove(struct WaitqueueNode *node) { x_base lock = 0; NULL_PARAM_CHECK(node); lock = CriticalAreaLock(); DoubleLinkListRmNode(&(node->list)); CriticalAreaUnLock(lock); } /** * This function restarts the suspended task of the queue * @parm waitqueue pointer * @parm the awake key */ void WakeupWqueue(WaitQueueType *queue, void *key) { x_base lock = 0; NULL_PARAM_CHECK(queue); NULL_PARAM_CHECK(key); lock = CriticalAreaLock(); struct SysDoubleLinklistNode *node = NONE; DOUBLE_LINKLIST_FOR_EACH(node, &(queue->block_threads_list)) { struct WaitqueueNode *pEnter; pEnter = SYS_DOUBLE_LINKLIST_ENTRY(node, struct WaitqueueNode, list); if (pEnter->cb != NONE && pEnter->cb(pEnter, key) != 0) { continue; } else { KTaskWakeup(pEnter->polling_task->id.id); } } CriticalAreaUnLock(lock); if (node == &(queue->block_threads_list)) { return; } DO_KTASK_ASSIGN; } /** * This function will suspend current task and start up a timer * @parm queue waitqueue descriptor * @parm msec waiting time * */ int WqueueWait(WaitQueueType *queue, x_ticks_t tick) { NULL_PARAM_CHECK(queue); if (tick == 0) return 0; struct WaitqueueNode* pin_node = x_malloc(sizeof(struct WaitqueueNode)); // set timeout awake if (tick != WAITING_FOREVER) { pin_node->deadline_tick = CurrentTicksGain() + tick; KTaskSetDelay(GetKTaskDescriptor(), tick); } else { pin_node->deadline_tick = 0; } // init block node pin_node->polling_task = GetKTaskDescriptor(); pin_node->key = 0; pin_node->cb = NONE; pin_node->list.node_next = &pin_node->list; pin_node->list.node_prev = &pin_node->list; // start block x_base lock; lock = CriticalAreaLock(); WqueueAdd(queue, pin_node); SuspendKTask(GetKTaskDescriptor()->id.id); CriticalAreaUnLock(lock); DO_KTASK_ASSIGN; // end block, delete node WqueueRemove(pin_node); x_free(pin_node); return 0; } /** * This function will create a wait queue. * * @param queue queue waitqueue descriptor * */ void InitWqueue(WaitQueueType *queue) { NULL_PARAM_CHECK(queue); InitDoubleLinkList(&(queue->block_threads_list)); }