forked from xuos/xiuos
First commit XiUOS
This commit is contained in:
147
kernel/thread/CriticalArea.c
Normal file
147
kernel/thread/CriticalArea.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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: critical area.c
|
||||
* @brief: the critical area lock functions definitions
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CRITICAL__AREA__
|
||||
#define __CRITICAL__AREA__
|
||||
|
||||
#include <xs_isr.h>
|
||||
#include <xs_ktask_stat.h>
|
||||
#include <xs_assign.h>
|
||||
#include <xs_spinlock.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
HwSpinlock _CriticalLock;
|
||||
|
||||
/**
|
||||
* This function will do OsAssign lock.
|
||||
*
|
||||
* @return lock
|
||||
*/
|
||||
x_base CriticalAreaLock(void)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
lock = DisableLocalInterrupt();
|
||||
|
||||
if (Assign.smp_os_running_task[GetCpuId()]) {
|
||||
if (Assign.smp_os_running_task[GetCpuId()]->task_smp_info.critical_lock_cnt == 0) {
|
||||
Assign.assign_lock[GetCpuId()] ++;
|
||||
HwLockSpinlock(&_CriticalLock);
|
||||
}
|
||||
|
||||
Assign.smp_os_running_task[GetCpuId()]->task_smp_info.critical_lock_cnt ++;
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This function will do OsAssign unlock.
|
||||
*
|
||||
* @return lock
|
||||
*/
|
||||
void CriticalAreaUnLock(x_base lock)
|
||||
{
|
||||
if (Assign.smp_os_running_task[GetCpuId()]) {
|
||||
if (Assign.smp_os_running_task[GetCpuId()]->task_smp_info.critical_lock_cnt > 0) {
|
||||
Assign.smp_os_running_task[GetCpuId()]->task_smp_info.critical_lock_cnt --;
|
||||
}
|
||||
|
||||
if (Assign.smp_os_running_task[GetCpuId()]->task_smp_info.critical_lock_cnt == 0) {
|
||||
if(Assign.assign_lock[GetCpuId()] > 0)
|
||||
Assign.assign_lock[GetCpuId()]--;
|
||||
HwUnlockSpinlock(&_CriticalLock);
|
||||
}
|
||||
}
|
||||
|
||||
EnableLocalInterrupt(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get critical lock level.
|
||||
*
|
||||
* @return critical lock level
|
||||
*/
|
||||
uint16 GetOsAssignLockLevel(void)
|
||||
{
|
||||
return Assign.smp_os_running_task[GetCpuId()]->task_smp_info.critical_lock_cnt;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <xs_hook.h>
|
||||
|
||||
static int16 KTaskOsAssignLockNest;
|
||||
|
||||
/**
|
||||
* This function will get critical lock level.
|
||||
*
|
||||
* @return critical lock level
|
||||
*/
|
||||
uint16 GetOsAssignLockLevel(void) {
|
||||
return KTaskOsAssignLockNest;
|
||||
}
|
||||
|
||||
inline void ResetCriticalAreaLock(void ) {
|
||||
KTaskOsAssignLockNest = 0;
|
||||
}
|
||||
/**
|
||||
* This function will do OsAssign lock.
|
||||
*
|
||||
* @return lock
|
||||
*/
|
||||
x_base CriticalAreaLock(void) {
|
||||
x_base lock;
|
||||
|
||||
lock = DISABLE_INTERRUPT();
|
||||
|
||||
KTaskOsAssignLockNest ++;
|
||||
|
||||
return lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will do OsAssign unlock.
|
||||
*
|
||||
* @return lock
|
||||
*/
|
||||
void CriticalAreaUnLock(x_base lock) {
|
||||
if (KTaskOsAssignLockNest >= 1) {
|
||||
KTaskOsAssignLockNest --;
|
||||
}
|
||||
|
||||
ENABLE_INTERRUPT(lock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
78
kernel/thread/Makefile
Normal file
78
kernel/thread/Makefile
Normal file
@@ -0,0 +1,78 @@
|
||||
SRC_FILES := tick.c kservicetask.c zombierecycle.c init.c lock.c idle.c linklist.c isr.c console.c ktask.c id.c CriticalArea.c bitmap.c delay.c double_link.c single_link.c assignstat.c ktask_stat.c
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_SEMAPHORE),y)
|
||||
SRC_FILES += semaphore.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_MUTEX),y)
|
||||
SRC_FILES += mutex.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_EVENT),y)
|
||||
SRC_FILES += event.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_MESSAGEQUEUE),y)
|
||||
SRC_FILES += msgqueue.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_SOFTTIMER),y)
|
||||
SRC_FILES += softtimer.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_BANNER),y)
|
||||
SRC_FILES += banner.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_HOOK),y)
|
||||
SRC_FILES += hook.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_QUEUEMANAGE),y)
|
||||
SRC_FILES += queue_manager.c
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_WORKQUEUE),y)
|
||||
SRC_FILES += workqueue.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_WAITQUEUE),y)
|
||||
SRC_FILES += waitqueue.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_DATAQUEUE),y)
|
||||
SRC_FILES += data_queue.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_CIRCULAR_AREA),y)
|
||||
SRC_FILES += circular_area.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KERNEL_AVL_TREE),y)
|
||||
SRC_FILES += avl_tree.c
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(CONFIG_ARCH_SMP),y)
|
||||
SRC_FILES += smp_assign.c
|
||||
else
|
||||
SRC_FILES += assign.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_POLICY_RR),y)
|
||||
SRC_FILES += assign_roundrobin.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_POLICY_FIFO),y)
|
||||
SRC_FILES += assign_fifo.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_POLICY_RR_REMAINSLICE),y)
|
||||
SRC_FILES += assign_roundrobinremain.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USER_APPLICATION),y)
|
||||
SRC_FILES += appstartup.c
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
177
kernel/thread/appstartup.c
Normal file
177
kernel/thread/appstartup.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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: appstartup.c
|
||||
* @brief: init application userspace and create main task
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <board.h>
|
||||
#ifdef TASK_ISOLATION
|
||||
#include <xs_isolation.h>
|
||||
#endif
|
||||
|
||||
#ifdef APP_STARTUP_FROM_SDCARD
|
||||
#include <iot-vfs_posix.h>
|
||||
#endif
|
||||
|
||||
extern int main(void);
|
||||
#ifdef USER_APPLICATION
|
||||
#ifndef SEPARATE_COMPILE
|
||||
void MainKTaskFunction(void *parameter)
|
||||
{
|
||||
#if defined(__ICCARM__) || defined(__GNUC__)
|
||||
main();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will create main application
|
||||
*
|
||||
*
|
||||
*/
|
||||
void CreateMainTask(void)
|
||||
{
|
||||
int32 main = 0;
|
||||
|
||||
#ifdef SEPARATE_COMPILE
|
||||
KPrintf("Tip!!! Kernel is separated with application. main entry : 0x%08x \n",USERSPACE->us_entrypoint);
|
||||
|
||||
main = UTaskCreate("main", (void*)USERSPACE->us_entrypoint, NONE,
|
||||
MAIN_KTASK_STACK_SIZE, MAIN_KTASK_PRIORITY);
|
||||
|
||||
#else
|
||||
main = KTaskCreate("main", MainKTaskFunction, NONE,
|
||||
MAIN_KTASK_STACK_SIZE, MAIN_KTASK_PRIORITY);
|
||||
|
||||
#endif
|
||||
|
||||
if(main < 0) {
|
||||
KPrintf("main create failed ...%s %d.\n",__FUNCTION__,__LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
StartupKTask(main);
|
||||
}
|
||||
|
||||
#ifdef SEPARATE_COMPILE
|
||||
int InitUserspace(void)
|
||||
{
|
||||
#ifdef APP_STARTUP_FROM_FLASH
|
||||
uint8_t *src = NONE;
|
||||
uint8_t *dest = NONE;
|
||||
uint8_t *end = NONE;
|
||||
|
||||
dest = (uint8_t *)USERSPACE->us_bssstart;
|
||||
end = (uint8_t *)USERSPACE->us_bssend;
|
||||
while (dest != end) {
|
||||
*dest++ = 0;
|
||||
}
|
||||
|
||||
/* Initialize all of user-space .data */
|
||||
|
||||
src = (uint8_t *)USERSPACE->us_datasource;
|
||||
dest = (uint8_t *)USERSPACE->us_datastart;
|
||||
end = (uint8_t *)USERSPACE->us_dataend;
|
||||
while (dest != end) {
|
||||
*dest++ = *src++;
|
||||
}
|
||||
#ifndef TASK_ISOLATION
|
||||
src = (uint8_t *)&g_service_table_start;
|
||||
dest = (uint8_t *)SERVICE_TABLE_ADDRESS;
|
||||
end = (uint8_t *)&g_service_table_end;
|
||||
while (src != end) {
|
||||
*dest++ = *src++;
|
||||
}
|
||||
#endif
|
||||
|
||||
UserInitBoardMemory((void*)USER_MEMORY_START_ADDRESS, (void*)USER_MEMORY_END_ADDRESS);
|
||||
|
||||
#ifdef MOMERY_PROTECT_ENABLE
|
||||
if ( mem_access.Init != NONE){
|
||||
if(mem_access.Init( (void **)(&isolation)) == EOK)
|
||||
mem_access.Load(isolation);
|
||||
}
|
||||
#endif
|
||||
return EOK;
|
||||
#endif
|
||||
|
||||
#ifdef APP_STARTUP_FROM_SDCARD
|
||||
int fd = 0;
|
||||
char buf[1024] = {0};
|
||||
int len = 0;
|
||||
int len_check = 0;
|
||||
uint8_t *src = NONE;
|
||||
uint8_t *dest = NONE;
|
||||
uint8_t *end = NONE;
|
||||
#ifndef FS_VFS
|
||||
KPrintf("fs not enable!%s %d\n",__func__,__LINE__);
|
||||
CHECK(0);
|
||||
#endif
|
||||
|
||||
fd = open(BOARD_APP_NAME,O_RDONLY );
|
||||
if(fd > 0) {
|
||||
KPrintf("open app bin %s success.\n",BOARD_APP_NAME);
|
||||
|
||||
dest = (uint8_t *)USERSPACE;
|
||||
/* copy app to USERSPACE */
|
||||
while(RET_TRUE) {
|
||||
memset(buf, 0 , 1024);
|
||||
len = read(fd, buf, 1024);
|
||||
KPrintf("read app bin len %d\n",len);
|
||||
if(len > 0) {
|
||||
memcpy(dest, buf, len);
|
||||
dest = dest + len;
|
||||
len_check = len_check + len;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(len_check <= 0){
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
dest = (uint8_t *)USERSPACE->us_bssstart;
|
||||
end = (uint8_t *)USERSPACE->us_bssend;
|
||||
while (dest != end) {
|
||||
*dest++ = 0;
|
||||
}
|
||||
|
||||
src = (uint8_t *)&g_service_table_start;
|
||||
dest = (uint8_t *)SERVICE_TABLE_ADDRESS;
|
||||
end = (uint8_t *)&g_service_table_end;
|
||||
|
||||
while (src != end) {
|
||||
*dest++ = *src++;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
UserInitBoardMemory((void*)USER_MEMORY_START_ADDRESS, (void*)USER_MEMORY_END_ADDRESS);
|
||||
|
||||
return EOK;
|
||||
|
||||
} else {
|
||||
KPrintf("open app bin %s failed.\n",BOARD_APP_NAME);
|
||||
return -EEMPTY;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
389
kernel/thread/assign.c
Normal file
389
kernel/thread/assign.c
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* 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: assign.c
|
||||
* @brief: system scheduler of single cpu
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <xs_assign.h>
|
||||
#include <xs_ktask_stat.h>
|
||||
#include <xs_assign.h>
|
||||
#include <xs_hook.h>
|
||||
|
||||
struct Assign Assign;
|
||||
|
||||
static struct PriorityReadyVectorDone SingleReadyVectorDone =
|
||||
{
|
||||
OsAssignReadyVectorInit,
|
||||
KTaskInsertToReadyVector,
|
||||
KTaskOsAssignRemoveKTask,
|
||||
};
|
||||
|
||||
/**
|
||||
* task schedule function.getting the highest priority task then switching to it
|
||||
*/
|
||||
void KTaskOsAssign(void)
|
||||
{
|
||||
|
||||
x_ubase highest_prio = 0;
|
||||
int need_insert_from_task = 0;
|
||||
struct TaskDescriptor *new_task = NONE;
|
||||
struct TaskDescriptor *from_task = NONE;
|
||||
|
||||
if(GetOsAssignLockLevel() >= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( isrManager.done->isInIsr() ){
|
||||
isrManager.done->setSwitchTrigerFlag();
|
||||
return;
|
||||
}
|
||||
|
||||
/* if the bitmap is empty then do not switch */
|
||||
if(RET_TRUE == JudgeAssignReadyBitmapIsEmpty(&Assign.os_assign_read_vector)) {
|
||||
return;
|
||||
}
|
||||
|
||||
highest_prio = Assign.os_assign_read_vector.highest_prio;
|
||||
new_task = ChooseTaskWithHighestPrio(&Assign.os_assign_read_vector);
|
||||
|
||||
if(RET_TRUE != JudgeKTaskStatIsRunning(Assign.os_running_task)) {
|
||||
CHECK(NONE != new_task);
|
||||
goto SWITCH;
|
||||
}
|
||||
|
||||
/* if the running task’ priority is the highest and this task is not be yield then do not switch */
|
||||
if(highest_prio < Assign.os_running_task->task_dync_sched_member.cur_prio) {
|
||||
return;
|
||||
} else {
|
||||
need_insert_from_task = 1;
|
||||
}
|
||||
|
||||
SWITCH:
|
||||
if (new_task != Assign.os_running_task) {
|
||||
Assign.current_priority = (uint8)highest_prio;
|
||||
from_task = Assign.os_running_task;
|
||||
|
||||
HOOK(hook.assign.hook_Assign, (from_task, new_task));
|
||||
|
||||
if (need_insert_from_task) {
|
||||
Assign.ready_vector_done->insert(from_task);
|
||||
}
|
||||
|
||||
Assign.ready_vector_done->remove(new_task);
|
||||
KTaskStatSetAsRunning(new_task);
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED,
|
||||
("[%d]switch to priority#%d "
|
||||
"task:%.*s(sp:0x%08x), "
|
||||
"from task:%.*s(sp: 0x%08x)\n",
|
||||
isrManager.done->getCounter(), highest_prio,
|
||||
NAME_NUM_MAX, new_task->task_base_info.name, new_task->stack_point,
|
||||
NAME_NUM_MAX, from_task->task_base_info.name, from_task->stack_point));
|
||||
|
||||
#ifdef KERNEL_STACK_OVERFLOW_CHECK
|
||||
_KTaskOsAssignStackCheck(new_task);
|
||||
#endif
|
||||
|
||||
|
||||
SwitchKtaskContext((x_ubase)&from_task->stack_point,
|
||||
(x_ubase)&new_task->stack_point, new_task);
|
||||
|
||||
} else {
|
||||
Assign.ready_vector_done->remove(Assign.os_running_task);
|
||||
KTaskStatSetAsRunning(Assign.os_running_task);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void KTaskOsAssignDoIrqSwitch(void *context)
|
||||
{
|
||||
|
||||
x_ubase highest_prio = 0;
|
||||
int need_insert_from_task = 0;
|
||||
struct TaskDescriptor *new_task = NONE;
|
||||
struct TaskDescriptor *from_task = NONE;
|
||||
|
||||
if(GetOsAssignLockLevel() >= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( isrManager.done->getSwitchTrigerFlag() == 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
isrManager.done->clearSwitchTrigerFlag();
|
||||
/* if the bitmap is empty then do not switch */
|
||||
if(RET_TRUE == JudgeAssignReadyBitmapIsEmpty(&Assign.os_assign_read_vector)) {
|
||||
return;
|
||||
}
|
||||
|
||||
highest_prio = Assign.os_assign_read_vector.highest_prio;
|
||||
new_task = ChooseTaskWithHighestPrio(&Assign.os_assign_read_vector);
|
||||
|
||||
if(RET_TRUE != JudgeKTaskStatIsRunning(Assign.os_running_task)) {
|
||||
CHECK(NONE != new_task);
|
||||
goto SWITCH;
|
||||
}
|
||||
|
||||
/* if the running task’ priority is the highest and this task is not be yield then do not switch */
|
||||
if(highest_prio < Assign.os_running_task->task_dync_sched_member.cur_prio) {
|
||||
return;
|
||||
} else {
|
||||
need_insert_from_task = 1;
|
||||
}
|
||||
|
||||
SWITCH:
|
||||
|
||||
if (new_task != Assign.os_running_task) {
|
||||
Assign.current_priority = (uint8)highest_prio;
|
||||
from_task = Assign.os_running_task;
|
||||
|
||||
HOOK(hook.assign.hook_Assign, (from_task, new_task));
|
||||
|
||||
if (need_insert_from_task) {
|
||||
Assign.ready_vector_done->insert(from_task);
|
||||
}
|
||||
|
||||
Assign.ready_vector_done->remove(new_task);
|
||||
KTaskStatSetAsRunning(new_task);
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED,
|
||||
("[%d]switch to priority#%d "
|
||||
"task:%.*s(sp:0x%08x), "
|
||||
"from task:%.*s(sp: 0x%08x)\n",
|
||||
isrManager.done->getCounter(), highest_prio,
|
||||
NAME_NUM_MAX, new_task->task_base_info.name, new_task->stack_point,
|
||||
NAME_NUM_MAX, from_task->task_base_info.name, from_task->stack_point));
|
||||
|
||||
#ifdef KERNEL_STACK_OVERFLOW_CHECK
|
||||
_KTaskOsAssignStackCheck(new_task);
|
||||
#endif
|
||||
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED, ("switch in interrupt\n"));
|
||||
HwInterruptcontextSwitch((x_ubase)&from_task->stack_point,
|
||||
(x_ubase)&new_task->stack_point, new_task, context);
|
||||
|
||||
} else {
|
||||
Assign.ready_vector_done->remove(Assign.os_running_task);
|
||||
KTaskStatSetAsRunning(Assign.os_running_task);
|
||||
}
|
||||
}
|
||||
|
||||
void KTaskOsAssignAfterIrq(void *context)
|
||||
{
|
||||
x_base lock = 0;
|
||||
lock = DISABLE_INTERRUPT();
|
||||
KTaskOsAssignDoIrqSwitch(context);
|
||||
ENABLE_INTERRUPT(lock);
|
||||
}
|
||||
/*
|
||||
* insert a ready task to system ready table with READY state and remove it from suspend list
|
||||
*
|
||||
* @param task the task descriptor
|
||||
*
|
||||
*/
|
||||
void KTaskInsertToReadyVector(struct TaskDescriptor *task)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
lock = DISABLE_INTERRUPT();
|
||||
|
||||
KTaskStatSetAsReady(task);
|
||||
AssignPolicyInsert(task, &Assign.os_assign_read_vector);
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED, ("insert task[%.*s], the priority: %d\n",
|
||||
NAME_NUM_MAX, task->task_base_info.name, task->task_dync_sched_member.cur_prio));
|
||||
|
||||
#if KTASK_PRIORITY_MAX > 32
|
||||
MERGE_FLAG(&Assign.os_assign_read_vector.ready_vector[task->task_dync_sched_member.bitmap_offset], task->task_dync_sched_member.bitmap_row);
|
||||
#endif
|
||||
MERGE_FLAG(&Assign.os_assign_read_vector.priority_ready_group, task->task_dync_sched_member.bitmap_column);
|
||||
|
||||
ENABLE_INTERRUPT(lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* a task will be removed from ready table.
|
||||
*
|
||||
* @param task task descriptor
|
||||
*
|
||||
*/
|
||||
void KTaskOsAssignRemoveKTask(struct TaskDescriptor *task)
|
||||
{
|
||||
x_base lock = 0;
|
||||
x_ubase number = 0;
|
||||
x_ubase highest_priority = 0;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
lock = DISABLE_INTERRUPT();
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED, ("remove task[%.*s], the priority: %d\n",
|
||||
NAME_NUM_MAX, task->task_base_info.name,
|
||||
task->task_dync_sched_member.cur_prio));
|
||||
|
||||
DoubleLinkListRmNode(&(task->task_dync_sched_member.sched_link));
|
||||
|
||||
if (IsDoubleLinkListEmpty(&(Assign.os_assign_read_vector.priority_ready_vector[task->task_dync_sched_member.cur_prio]))) {
|
||||
#if KTASK_PRIORITY_MAX > 32
|
||||
CLEAR_FLAG(&Assign.os_assign_read_vector.ready_vector[task->task_dync_sched_member.bitmap_offset], task->task_dync_sched_member.bitmap_row);
|
||||
if (Assign.os_assign_read_vector.ready_vector[task->task_dync_sched_member.bitmap_offset] == 0) {
|
||||
CLEAR_FLAG(&Assign.os_assign_read_vector.priority_ready_group, task->task_dync_sched_member.bitmap_column);
|
||||
}
|
||||
number = PrioCaculate(Assign.os_assign_read_vector.priority_ready_group);
|
||||
highest_priority = (number * 8) + PrioCaculate(Assign.os_assign_read_vector.ready_vector[number]);
|
||||
#else
|
||||
CLEAR_FLAG(&Assign.os_assign_read_vector.priority_ready_group, task->task_dync_sched_member.bitmap_column);
|
||||
highest_priority = PrioCaculate(Assign.os_assign_read_vector.priority_ready_group);
|
||||
#endif
|
||||
Assign.os_assign_read_vector.highest_prio = highest_priority;
|
||||
}
|
||||
|
||||
ENABLE_INTERRUPT(lock);
|
||||
}
|
||||
|
||||
|
||||
static inline void SwitchToFirstRunningTask(struct TaskDescriptor* task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
Assign.ready_vector_done->remove(task);
|
||||
KTaskStatSetAsRunning(task);
|
||||
SwitchKtaskContextTo((x_ubase)&task->stack_point, task);
|
||||
}
|
||||
|
||||
static inline void SetSystemRunningTask(struct TaskDescriptor* task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
Assign.os_running_task = task;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will yield current task.
|
||||
*
|
||||
* @return EOK
|
||||
*/
|
||||
|
||||
x_err_t YieldOsAssign(void)
|
||||
{
|
||||
x_base lock = 0;
|
||||
x_ubase highest_prio = 0;
|
||||
struct TaskDescriptor *new_task = NONE;
|
||||
struct TaskDescriptor *from_task = NONE;
|
||||
|
||||
lock = DISABLE_INTERRUPT();
|
||||
|
||||
if(GetOsAssignLockLevel() >= 1) {
|
||||
ENABLE_INTERRUPT(lock);
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
if (isrManager.done->isInIsr()) {
|
||||
ENABLE_INTERRUPT(lock);
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* if the bitmap is empty then do not switch */
|
||||
if(RET_TRUE == JudgeAssignReadyBitmapIsEmpty(&Assign.os_assign_read_vector)) {
|
||||
ENABLE_INTERRUPT(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
highest_prio = Assign.os_assign_read_vector.highest_prio;
|
||||
new_task = ChooseTaskWithHighestPrio(&Assign.os_assign_read_vector);
|
||||
|
||||
from_task = Assign.os_running_task;
|
||||
|
||||
if(RET_TRUE != JudgeKTaskStatIsRunning(from_task)) {
|
||||
CHECK(NONE != new_task);
|
||||
} else {
|
||||
Assign.ready_vector_done->insert(from_task);
|
||||
}
|
||||
|
||||
if (new_task != from_task) {
|
||||
Assign.current_priority = (uint8)highest_prio;
|
||||
|
||||
HOOK(hook.assign.hook_Assign, (from_task, new_task));
|
||||
|
||||
Assign.ready_vector_done->remove(new_task);
|
||||
KTaskStatSetAsRunning(new_task);
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED,
|
||||
("[%d]switch to priority#%d "
|
||||
"task:%.*s(sp:0x%08x), "
|
||||
"from task:%.*s(sp: 0x%08x)\n",
|
||||
isrManager.done->getCounter(), highest_prio,
|
||||
NAME_NUM_MAX, new_task->task_base_info.name, new_task->stack_point,
|
||||
NAME_NUM_MAX, from_task->task_base_info.name, from_task->stack_point));
|
||||
|
||||
#ifdef KERNEL_STACK_OVERFLOW_CHECK
|
||||
_KTaskOsAssignStackCheck(new_task);
|
||||
#endif
|
||||
|
||||
|
||||
SwitchKtaskContext((x_ubase)&from_task->stack_point,
|
||||
(x_ubase)&new_task->stack_point, new_task);
|
||||
|
||||
ENABLE_INTERRUPT(lock);
|
||||
goto __exit;
|
||||
} else {
|
||||
Assign.ready_vector_done->remove(Assign.os_running_task);
|
||||
KTaskStatSetAsRunning(Assign.os_running_task);
|
||||
}
|
||||
|
||||
ENABLE_INTERRUPT(lock);
|
||||
|
||||
__exit:
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* OsAssign startup function
|
||||
* .
|
||||
*/
|
||||
void StartupOsAssign(void)
|
||||
{
|
||||
struct TaskDescriptor *FirstRunningTask = NONE;
|
||||
|
||||
FirstRunningTask = ChooseTaskWithHighestPrio(&Assign.os_assign_read_vector);
|
||||
|
||||
SetSystemRunningTask(FirstRunningTask);
|
||||
|
||||
SwitchToFirstRunningTask(FirstRunningTask);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* system OsAssign init function
|
||||
*/
|
||||
void SysInitOsAssign(void)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED, ("start Os Assign: max priority 0x%02x\n",
|
||||
KTASK_PRIORITY_MAX));
|
||||
|
||||
Assign.ready_vector_done = &SingleReadyVectorDone;
|
||||
Assign.ready_vector_done->init(&Assign.os_assign_read_vector);
|
||||
|
||||
ResetCriticalAreaLock();
|
||||
}
|
||||
51
kernel/thread/assign_fifo.c
Normal file
51
kernel/thread/assign_fifo.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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: assign_roundrobin.c
|
||||
* @brief: ready table and timeslice functions definitions of fifo scheduler algorithm
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
#define NO_TIMESLICE (0)
|
||||
|
||||
void FifoTaskTimesliceInit(struct TaskDescriptor *task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
task->task_dync_sched_member.origin_timeslice = NO_TIMESLICE;
|
||||
task->task_dync_sched_member.rest_timeslice = NO_TIMESLICE;
|
||||
}
|
||||
|
||||
|
||||
void FifoReadyVectorInsert(struct TaskDescriptor *task, struct OsAssignReadyVector* ready_table)
|
||||
{
|
||||
DoubleLinklistType* tail = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
NULL_PARAM_CHECK(ready_table);
|
||||
|
||||
tail = ready_table->priority_ready_vector[task->task_dync_sched_member.cur_prio].node_prev;
|
||||
DoubleLinkListInsertNodeAfter(tail, &(task->task_dync_sched_member.sched_link));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void FifoTaskTimesliceUpdate()
|
||||
{
|
||||
return;
|
||||
}
|
||||
56
kernel/thread/assign_roundrobin.c
Normal file
56
kernel/thread/assign_roundrobin.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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: assign_roundrobin.c
|
||||
* @brief: ready table and timeslice functions definitions of roundrobin scheduler algorithm
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
void RoundRobinTaskTimesliceInit(struct TaskDescriptor *task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
task->task_dync_sched_member.origin_timeslice = 10;
|
||||
task->task_dync_sched_member.rest_timeslice = 10;
|
||||
}
|
||||
|
||||
void RoundRobinReadyVectorInsert(struct TaskDescriptor *task, struct OsAssignReadyVector* ready_table)
|
||||
{
|
||||
DoubleLinklistType* tail = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
NULL_PARAM_CHECK(ready_table);
|
||||
|
||||
tail = ready_table->priority_ready_vector[task->task_dync_sched_member.cur_prio].node_prev;
|
||||
DoubleLinkListInsertNodeAfter(tail, &(task->task_dync_sched_member.sched_link));
|
||||
|
||||
}
|
||||
|
||||
void RoundRobinTaskTimesliceUpdate(struct TaskDescriptor *task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
-- task->task_dync_sched_member.rest_timeslice;
|
||||
if (task->task_dync_sched_member.rest_timeslice == 0)
|
||||
{
|
||||
task->task_dync_sched_member.rest_timeslice = task->task_dync_sched_member.origin_timeslice;
|
||||
|
||||
DO_KTASK_ASSIGN;
|
||||
}
|
||||
}
|
||||
|
||||
79
kernel/thread/assign_roundrobinremain.c
Normal file
79
kernel/thread/assign_roundrobinremain.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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: assign_roundrobin.c
|
||||
* @brief: ready table and timeslice functions definitions of remain ticks first scheduler algorithm
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
void RoundRobinRemainTaskTimesliceInit(struct TaskDescriptor *task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
task->task_dync_sched_member.origin_timeslice = 10;
|
||||
task->task_dync_sched_member.rest_timeslice = 10;
|
||||
}
|
||||
|
||||
|
||||
void RoundRobinRemainReadyVectorInsert(struct TaskDescriptor *task, struct OsAssignReadyVector* ready_table)
|
||||
{
|
||||
DoubleLinklistType* node = NONE;
|
||||
DoubleLinklistType* tail = NONE;
|
||||
struct TaskDescriptor *tmp = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
NULL_PARAM_CHECK(ready_table);
|
||||
|
||||
if ( task->task_dync_sched_member.advance_cnt < KTASK_MAX_ADVANCE_PROCESS_TIME ) {
|
||||
DOUBLE_LINKLIST_FOR_EACH(node, &ready_table->priority_ready_vector[task->task_dync_sched_member.cur_prio]) {
|
||||
tmp = SYS_DOUBLE_LINKLIST_ENTRY(node, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
||||
if (task->task_dync_sched_member.rest_timeslice < tmp->task_dync_sched_member.rest_timeslice) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( node != &ready_table->priority_ready_vector[task->task_dync_sched_member.cur_prio]) {
|
||||
DoubleLinkListInsertNodeBefore(node, &(task->task_dync_sched_member.sched_link));
|
||||
} else {
|
||||
tail = ready_table->priority_ready_vector[task->task_dync_sched_member.cur_prio].node_prev;
|
||||
DoubleLinkListInsertNodeAfter(tail, &(task->task_dync_sched_member.sched_link));
|
||||
}
|
||||
} else {
|
||||
tail = ready_table->priority_ready_vector[task->task_dync_sched_member.cur_prio].node_prev;
|
||||
DoubleLinkListInsertNodeAfter(tail, &(task->task_dync_sched_member.sched_link));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RoundRobinRemainTaskTimesliceUpdate(struct TaskDescriptor *task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
-- task->task_dync_sched_member.rest_timeslice;
|
||||
if (task->task_dync_sched_member.rest_timeslice == 0)
|
||||
{
|
||||
if ( task->task_dync_sched_member.advance_cnt < KTASK_MAX_ADVANCE_PROCESS_TIME ) {
|
||||
task->task_dync_sched_member.advance_cnt++;
|
||||
}
|
||||
|
||||
task->task_dync_sched_member.rest_timeslice = task->task_dync_sched_member.origin_timeslice;
|
||||
|
||||
DO_KTASK_ASSIGN;
|
||||
}
|
||||
}
|
||||
|
||||
112
kernel/thread/assignstat.c
Normal file
112
kernel/thread/assignstat.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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: assignstat.c
|
||||
* @brief: check system read ready and task stack
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xs_assign.h>
|
||||
|
||||
#ifdef KERNEL_STACK_OVERFLOW_CHECK
|
||||
/**
|
||||
* a task stack check function
|
||||
*
|
||||
* @param task task descriptor
|
||||
*/
|
||||
void _KTaskOsAssignStackCheck(struct TaskDescriptor *task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
if ((x_ubase)task->stack_point<= (x_ubase)task->task_base_info.stack_start ||
|
||||
(x_ubase)task->stack_point >
|
||||
(x_ubase)task->task_base_info.stack_start + (x_ubase)task->task_base_info.stack_depth) {
|
||||
|
||||
KPrintf("task name:%s id:%d stack overflow,sp %p stacktop %p stack depth 0x%x\n", task->task_base_info.name,task->id.id,task->stack_point,(uint32*)task->task_base_info.stack_start + task->task_base_info.stack_depth,task->task_base_info.stack_depth);
|
||||
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int32 JudgeAssignReadyBitmapIsEmpty(struct OsAssignReadyVector *ready_vector)
|
||||
{
|
||||
NULL_PARAM_CHECK(ready_vector);
|
||||
return ((ready_vector->priority_ready_group == 0) ? RET_TRUE: 0);
|
||||
}
|
||||
|
||||
struct TaskDescriptor * ChooseTaskWithHighestPrio(struct OsAssignReadyVector *ready_vector)
|
||||
{
|
||||
struct TaskDescriptor *TargetTask = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(ready_vector);
|
||||
|
||||
TargetTask = SYS_DOUBLE_LINKLIST_ENTRY(ready_vector->priority_ready_vector[ready_vector->highest_prio].node_next,
|
||||
struct TaskDescriptor,
|
||||
task_dync_sched_member.sched_link);
|
||||
|
||||
return TargetTask;
|
||||
}
|
||||
|
||||
void OsAssignReadyVectorInit(struct OsAssignReadyVector *ready_vector)
|
||||
{
|
||||
register x_base prio = 0;
|
||||
NULL_PARAM_CHECK(ready_vector);
|
||||
|
||||
while(prio < KTASK_PRIORITY_MAX)
|
||||
{
|
||||
InitDoubleLinkList(&ready_vector->priority_ready_vector[prio]);
|
||||
prio++;
|
||||
}
|
||||
ready_vector->highest_prio = 0;
|
||||
ready_vector->priority_ready_group = 0;
|
||||
#if KTASK_PRIORITY_MAX > 32
|
||||
memset(ready_vector->ready_vector, 0, sizeof(ready_vector->ready_vector));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will insert a task to system ready table according to sched policy(FIFO/RR/RR+remain timeslice)
|
||||
*
|
||||
* @param task task descriptor
|
||||
* @param ready_table task ready_table
|
||||
*/
|
||||
void AssignPolicyInsert(struct TaskDescriptor *task, struct OsAssignReadyVector* ready_table)
|
||||
{
|
||||
DoubleLinklistType* node = NONE;
|
||||
DoubleLinklistType* tail = NONE;
|
||||
struct TaskDescriptor *tmp = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
NULL_PARAM_CHECK(ready_table);
|
||||
|
||||
#if defined (SCHED_POLICY_FIFO)
|
||||
FifoReadyVectorInsert(task, ready_table);
|
||||
#elif defined (SCHED_POLICY_RR)
|
||||
RoundRobinReadyVectorInsert(task, ready_table);
|
||||
#elif defined (SCHED_POLICY_RR_REMAINSLICE)
|
||||
RoundRobinRemainReadyVectorInsert(task, ready_table);
|
||||
#endif
|
||||
|
||||
if(NONE == task || NONE == ready_table) {
|
||||
KPrintf("PARAM CHECK FAILED ...%s %d param is NULL.\n",__FUNCTION__,__LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if(task->task_dync_sched_member.cur_prio > ready_table->highest_prio) {
|
||||
ready_table->highest_prio = task->task_dync_sched_member.cur_prio;
|
||||
}
|
||||
}
|
||||
369
kernel/thread/avl_tree.c
Normal file
369
kernel/thread/avl_tree.c
Normal file
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* 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: avl_tree.c
|
||||
* @brief: avl_tree file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xs_avltree.h"
|
||||
#include <string.h>
|
||||
#include <xs_kdbg.h>
|
||||
#include <xs_klist.h>
|
||||
#include <xs_memory.h>
|
||||
|
||||
/**
|
||||
* This function will return the node height of the avl tree
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @return 0
|
||||
*/
|
||||
static uint32 AvlTreeGetNodeHeight(AvlNodeType avl_node)
|
||||
{
|
||||
if(avl_node) {
|
||||
return AVL_MAX(AvlTreeGetNodeHeight(avl_node->left), AvlTreeGetNodeHeight(avl_node->right)) + 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the node balance factor of the avl tree
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
*/
|
||||
static int32 AvlTreeGetNodeBalanceFactor(AvlNodeType avl_node)
|
||||
{
|
||||
if(avl_node) {
|
||||
return AvlTreeGetNodeHeight(avl_node->left) - AvlTreeGetNodeHeight(avl_node->right);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will support right rotate to balance the avl tree(eg. LL case)
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @return avl tree node
|
||||
*/
|
||||
static AvlNodeType AvlTreeSetRightRotate(AvlNodeType avl_node)
|
||||
{
|
||||
NULL_PARAM_CHECK(avl_node);
|
||||
|
||||
AvlNodeType new_node = avl_node->left;
|
||||
|
||||
avl_node->left = new_node->right;
|
||||
new_node->right = avl_node;
|
||||
|
||||
new_node->height = AVL_MAX(AvlTreeGetNodeHeight(new_node->left), AvlTreeGetNodeHeight(new_node->right)) + 1;
|
||||
avl_node->height = AVL_MAX(AvlTreeGetNodeHeight(avl_node->left), AvlTreeGetNodeHeight(avl_node->right)) + 1;
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will support left rotate to balance the avl tree(eg. RR case)
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @return avl tree node
|
||||
*/
|
||||
static AvlNodeType AvlTreeSetLeftRotate(AvlNodeType avl_node)
|
||||
{
|
||||
NULL_PARAM_CHECK(avl_node);
|
||||
|
||||
AvlNodeType new_node = avl_node->right;
|
||||
|
||||
avl_node->right = new_node->left;
|
||||
new_node->left = avl_node;
|
||||
|
||||
new_node->height = AVL_MAX(AvlTreeGetNodeHeight(new_node->left), AvlTreeGetNodeHeight(new_node->right)) + 1;
|
||||
avl_node->height = AVL_MAX(AvlTreeGetNodeHeight(avl_node->left), AvlTreeGetNodeHeight(avl_node->right)) + 1;
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will support left and right rotate to balance the avl tree(eg. LR case)
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @return avl tree node
|
||||
*/
|
||||
static AvlNodeType AvlTreeSetLRRotate(AvlNodeType avl_node)
|
||||
{
|
||||
NULL_PARAM_CHECK(avl_node);
|
||||
|
||||
AvlNodeType new_node = NONE;
|
||||
AvlNodeType left_node = avl_node->left;
|
||||
|
||||
/*step1 : Left rotate*/
|
||||
avl_node->left = AvlTreeSetLeftRotate(left_node);
|
||||
|
||||
/*step2 : Right rotate*/
|
||||
new_node = AvlTreeSetRightRotate(avl_node);
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will support right and left rotate to balance the avl tree(eg. RL case)
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @return avl tree node
|
||||
*/
|
||||
static AvlNodeType AvlTreeSetRLRotate(AvlNodeType avl_node)
|
||||
{
|
||||
NULL_PARAM_CHECK(avl_node);
|
||||
|
||||
AvlNodeType new_node = NONE;
|
||||
AvlNodeType right_node = avl_node->right;
|
||||
|
||||
/*step1 : Right rotate*/
|
||||
avl_node->right = AvlTreeSetRightRotate(right_node);
|
||||
|
||||
/*step2 : Left rotate*/
|
||||
new_node = AvlTreeSetLeftRotate(avl_node);
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will balance the avl tree when inserting or deleting node
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @return avl tree node
|
||||
*/
|
||||
static AvlNodeType AvlTreeBalance(AvlNodeType avl_node)
|
||||
{
|
||||
if(avl_node)
|
||||
{
|
||||
AvlNodeType new_node = NONE;
|
||||
uint32 avlnode_BF = AVL_ABS(AvlTreeGetNodeBalanceFactor(avl_node));
|
||||
|
||||
if(avlnode_BF > 1) {
|
||||
if(AvlTreeGetNodeBalanceFactor(avl_node->left) > 0) {
|
||||
/*LL case*/
|
||||
new_node = AvlTreeSetRightRotate(avl_node);
|
||||
} else if(AvlTreeGetNodeBalanceFactor(avl_node->left) < 0) {
|
||||
/*LR case*/
|
||||
new_node = AvlTreeSetLRRotate(avl_node);
|
||||
} else if(AvlTreeGetNodeBalanceFactor(avl_node->right) < 0) {
|
||||
/*RR case*/
|
||||
new_node = AvlTreeSetLeftRotate(avl_node);
|
||||
} else if(AvlTreeGetNodeBalanceFactor(avl_node->right) > 0) {
|
||||
/*RL case*/
|
||||
new_node = AvlTreeSetRLRotate(avl_node);
|
||||
}
|
||||
} else {
|
||||
/*the avl tree is balanced, no need to rebalance*/
|
||||
new_node = avl_node;
|
||||
}
|
||||
|
||||
return new_node;
|
||||
|
||||
} else {
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will insert data to the avl tree
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @param data input data
|
||||
*/
|
||||
AvlNodeType AvlTreeInsertNode(AvlNodeType avl_node, int32 data)
|
||||
{
|
||||
AvlNodeType new_node = NONE;
|
||||
|
||||
if(NONE == avl_node) {
|
||||
new_node = x_malloc(sizeof(struct AvlNode));
|
||||
if(NONE == new_node) {
|
||||
KPrintf("AvlTreeInsertNode malloc AvlNode failed\n");
|
||||
x_free(new_node);
|
||||
return NONE;
|
||||
}
|
||||
new_node->data = data;
|
||||
new_node->left = NONE;
|
||||
new_node->right = NONE;
|
||||
new_node->height = 1;
|
||||
avl_node = new_node;
|
||||
} else if(data == avl_node->data) {
|
||||
/*input data is already existed*/
|
||||
KPrintf("the input data is already existed. just return\n");
|
||||
return avl_node;
|
||||
} else {
|
||||
if(avl_node->data < data) {
|
||||
avl_node->right = AvlTreeInsertNode(avl_node->right, data);
|
||||
if(NONE == avl_node->right) {
|
||||
KPrintf("AvlTreeInsertNode find right avl_node data failed\n");
|
||||
return NONE;
|
||||
}
|
||||
} else {
|
||||
avl_node->left = AvlTreeInsertNode(avl_node->left, data);
|
||||
if(NONE == avl_node->left) {
|
||||
KPrintf("AvlTreeInsertNode find left avl_node data failed\n");
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AvlTreeBalance(avl_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will find the pre node of the avl_node
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @return avl tree node
|
||||
*/
|
||||
static AvlNodeType AvlTreeFindPreNode(AvlNodeType avl_node)
|
||||
{
|
||||
NULL_PARAM_CHECK(avl_node);
|
||||
|
||||
AvlNodeType pre_node = NONE;
|
||||
|
||||
if(avl_node->left) {
|
||||
if(avl_node->left->right) {
|
||||
pre_node = avl_node->left->right;
|
||||
while(pre_node->right) {
|
||||
pre_node = pre_node->right;
|
||||
}
|
||||
} else {
|
||||
pre_node = avl_node->left;
|
||||
}
|
||||
} else {
|
||||
pre_node = avl_node;
|
||||
}
|
||||
|
||||
return pre_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will delete a certain node, ultimate target is to find the leaf node
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @param data delete data
|
||||
* @return avl tree node
|
||||
*/
|
||||
static AvlNodeType AvlTreeDeleteLeafNode(AvlNodeType avl_node)
|
||||
{
|
||||
AvlNodeType pre_node = NONE;
|
||||
|
||||
if((NONE == avl_node->left) && (NONE == avl_node->right)) {
|
||||
/*Leaf Node*/
|
||||
avl_node = NONE;
|
||||
x_free(avl_node);
|
||||
} else if(NONE == avl_node->left) {
|
||||
/*Right child is Leaf Node*/
|
||||
avl_node->data = avl_node->right->data;
|
||||
avl_node->right = NONE;
|
||||
x_free(avl_node->right);
|
||||
} else if(NONE == avl_node->right) {
|
||||
/*Left child is Leaf Node*/
|
||||
avl_node->data = avl_node->left->data;
|
||||
avl_node->left = NONE;
|
||||
x_free(avl_node->left);
|
||||
} else {
|
||||
/*Find the pre node to replace the avl node, then delete the pre node*/
|
||||
pre_node = AvlTreeFindPreNode(avl_node);
|
||||
if(pre_node) {
|
||||
avl_node->data = pre_node->data;
|
||||
avl_node->left = AvlTreeDeleteNode(avl_node->left, pre_node->data);
|
||||
}
|
||||
}
|
||||
|
||||
return avl_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will delete data from the avl tree
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @param data delete data
|
||||
*/
|
||||
AvlNodeType AvlTreeDeleteNode(AvlNodeType avl_node, int32 data)
|
||||
{
|
||||
if(avl_node) {
|
||||
if(data == avl_node->data) {
|
||||
avl_node = AvlTreeDeleteLeafNode(avl_node);
|
||||
} else {
|
||||
if(avl_node->data < data) {
|
||||
avl_node->right = AvlTreeDeleteNode(avl_node->right, data);
|
||||
} else {
|
||||
avl_node->left = AvlTreeDeleteNode(avl_node->left, data);
|
||||
}
|
||||
}
|
||||
|
||||
return AvlTreeBalance(avl_node);
|
||||
} else {
|
||||
KPrintf("AvlTreeDeleteNode cannot find the delete data\n");
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will modify certain data of the avl tree
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @param src_data src data
|
||||
* @param dst_data dst data
|
||||
*/
|
||||
AvlNodeType AvlNodeModifyNode(AvlNodeType avl_node, int32 src_data, int32 dst_data)
|
||||
{
|
||||
AvlNodeType dst_node = NONE;
|
||||
|
||||
if(avl_node) {
|
||||
/*Step1 : delete the src data node*/
|
||||
avl_node = AvlTreeDeleteNode(avl_node, src_data);
|
||||
|
||||
/*Step2 : insert the dst data node*/
|
||||
dst_node = AvlTreeInsertNode(avl_node, dst_data);
|
||||
|
||||
} else {
|
||||
KPrintf("AvlNodeModifyNode cannot find the src data node\n");
|
||||
return NONE;
|
||||
}
|
||||
|
||||
return dst_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the avl node which has the data
|
||||
*
|
||||
* @param avl_node avl tree node descriptor
|
||||
* @param data data
|
||||
*/
|
||||
AvlNodeType AvlNodeSearchNode(AvlNodeType avl_node, int32 data)
|
||||
{
|
||||
AvlNodeType dst_node = NONE;
|
||||
|
||||
if(avl_node) {
|
||||
if(data == avl_node->data) {
|
||||
dst_node = avl_node;
|
||||
KPrintf("AvlNodeSearchNode %d is existed return the node\n", avl_node->data);
|
||||
} else if(avl_node->data < data) {
|
||||
dst_node = AvlNodeSearchNode(avl_node->right, data);
|
||||
} else {
|
||||
dst_node = AvlNodeSearchNode(avl_node->left, data);
|
||||
}
|
||||
} else {
|
||||
KPrintf("AvlNodeSearchNode avl_node is NONE.\n");
|
||||
return NONE;
|
||||
}
|
||||
|
||||
return dst_node;
|
||||
}
|
||||
50
kernel/thread/banner.c
Normal file
50
kernel/thread/banner.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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: banner.c
|
||||
* @brief: system banner
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/4/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xs_banner.h>
|
||||
|
||||
/**
|
||||
* This function will show the version of XiUOS
|
||||
*/
|
||||
void ShowBanner(void)
|
||||
{
|
||||
KPrintf("*********************************************************************************************\n");
|
||||
KPrintf("AAAAAAA AAAAAAA IIIIIIII IIIIIIII IIIIIIIII TTTTTTTTTTTTTTT \n");
|
||||
KPrintf("A:::::A A:::::A I::::::I I::::::I II:::::::::II TT:::::::::::::::T \n");
|
||||
KPrintf("A:::::A A:::::A iiii I::::::I I::::::I II:::::::::::::II T:::::TTTTTT::::::T \n");
|
||||
KPrintf("A::::::A A::::::A i::::i II:::::I I:::::III:::::::III:::::::IT:::::T TTTTTTT\n");
|
||||
KPrintf("AAA:::::A A:::::AAA iiii I:::::I I:::::I I::::::I I::::::IT:::::T \n");
|
||||
KPrintf(" A:::::A A:::::A I:::::I I:::::I I:::::I I:::::IT:::::T \n");
|
||||
KPrintf(" A:::::A:::::A iiiiiii I:::::I I:::::I I:::::I I:::::I T::::TTTT \n");
|
||||
KPrintf(" A:::::::::A i:::::i I:::::I I:::::I I:::::I I:::::I TT::::::TTTTT \n");
|
||||
KPrintf(" A:::::::::A i::::i I:::::I I:::::I I:::::I I:::::I TTT::::::::TT \n");
|
||||
KPrintf(" A:::::A:::::A i::::i I:::::I I:::::I I:::::I I:::::I TTTTTT::::T \n");
|
||||
KPrintf(" A:::::A A:::::A i::::i I:::::I I:::::I I:::::I I:::::I T:::::T\n");
|
||||
KPrintf("AAA:::::A A:::::AAA i::::i I::::::I I::::::I I::::::I I::::::I T:::::T\n");
|
||||
KPrintf("A::::::A A::::::A i::::i I:::::::III:::::::I I:::::::III:::::::ITTTTTTT T:::::T\n");
|
||||
KPrintf("A:::::A A:::::A i::::i II:::::::::::::II II:::::::::::::II T::::::TTTTTT:::::T \n");
|
||||
KPrintf("A:::::A A:::::A i::::::i II:::::::::II II:::::::::II T:::::::::::::::TT \n");
|
||||
KPrintf("AAAAAAA AAAAAAA iiiiiiii IIIIIIIII IIIIIIIII TTTTTTTTTTTTTTT \n");
|
||||
KPrintf("*********************************************************************************************\n");
|
||||
KPrintf("*********************-----X Industrial Ubiquitous Operating System-----**********************\n");
|
||||
KPrintf("***************************2021 Copyright AIIT Ubiquitous-OS Team****************************\n");
|
||||
KPrintf("*********************************************************************************************\n");
|
||||
}
|
||||
66
kernel/thread/bitmap.c
Normal file
66
kernel/thread/bitmap.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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: bitmap.c
|
||||
* @brief: calculate the highest priority
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xs_assign.h>
|
||||
|
||||
const uint8 LeaderZeroCount[] =
|
||||
{
|
||||
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
int PrioCaculate(uint32 bitmap)
|
||||
{
|
||||
if (bitmap & 0xff000000)
|
||||
{
|
||||
return 31 - LeaderZeroCount[(bitmap & 0xff000000) >> 24];
|
||||
}
|
||||
else if (bitmap & 0xff0000)
|
||||
{
|
||||
return 23 - LeaderZeroCount[(bitmap & 0xff0000) >> 16];
|
||||
}
|
||||
else if (bitmap & 0xff00)
|
||||
{
|
||||
return 15 - LeaderZeroCount[(bitmap & 0xff00) >> 8];
|
||||
}
|
||||
else if (bitmap & 0xff)
|
||||
{
|
||||
return 7 - LeaderZeroCount[bitmap & 0xff];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
279
kernel/thread/circular_area.c
Normal file
279
kernel/thread/circular_area.c
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* 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: circular_area.c
|
||||
* @brief: circular area file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include "xs_circular_area.h"
|
||||
#include <string.h>
|
||||
#include <xs_kdbg.h>
|
||||
#include <xs_klist.h>
|
||||
#include <xs_memory.h>
|
||||
|
||||
/**
|
||||
* This function will return whether the circular_area is full or not
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
*/
|
||||
x_bool CircularAreaIsFull(CircularAreaType circular_area)
|
||||
{
|
||||
NULL_PARAM_CHECK(circular_area);
|
||||
|
||||
if((circular_area->readidx == circular_area->writeidx) && (circular_area->b_status)) {
|
||||
KPrintf("the circular area is full\n");
|
||||
return RET_TRUE;
|
||||
} else {
|
||||
return RET_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return whether the circular_area is empty or not
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
*/
|
||||
x_bool CircularAreaIsEmpty(CircularAreaType circular_area)
|
||||
{
|
||||
NULL_PARAM_CHECK(circular_area);
|
||||
|
||||
if((circular_area->readidx == circular_area->writeidx) && (!circular_area->b_status)) {
|
||||
KPrintf("the circular area is empty\n");
|
||||
return RET_TRUE;
|
||||
} else {
|
||||
return RET_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will reset the circular_area and set the descriptor to default
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
*/
|
||||
void CircularAreaReset(CircularAreaType circular_area)
|
||||
{
|
||||
circular_area->writeidx = 0;
|
||||
circular_area->readidx = 0;
|
||||
circular_area->b_status = RET_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will release the circular_area descriptor and free the memory
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
*/
|
||||
void CircularAreaRelease(CircularAreaType circular_area)
|
||||
{
|
||||
circular_area->readidx = 0;
|
||||
circular_area->writeidx = 0;
|
||||
circular_area->p_head = NONE;
|
||||
circular_area->p_tail = NONE;
|
||||
circular_area->b_status = RET_FALSE;
|
||||
circular_area->area_length = 0;
|
||||
|
||||
x_free(circular_area->data_buffer);
|
||||
x_free(circular_area);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get the circual_area max length
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
*/
|
||||
uint32 CircularAreaGetMaxLength(CircularAreaType circular_area)
|
||||
{
|
||||
NULL_PARAM_CHECK(circular_area);
|
||||
|
||||
return circular_area->area_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get the data length of the circular_area
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
*/
|
||||
uint32 CircularAreaGetDataLength(CircularAreaType circular_area)
|
||||
{
|
||||
NULL_PARAM_CHECK(circular_area);
|
||||
|
||||
if(CircularAreaIsFull(circular_area)) {
|
||||
return circular_area->area_length;
|
||||
} else {
|
||||
return (circular_area->writeidx - circular_area->readidx + circular_area->area_length) % circular_area->area_length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return whether it is need to divide the read data into two parts or not
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
* @param data_length output data length
|
||||
*/
|
||||
static uint32 CircularAreaDivideRdData(CircularAreaType circular_area, uint32 data_length)
|
||||
{
|
||||
NULL_PARAM_CHECK(circular_area);
|
||||
|
||||
if(circular_area->readidx + data_length <= circular_area->area_length) {
|
||||
return RET_FALSE;
|
||||
} else {
|
||||
return RET_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return whether it is need to divide the write data into two parts or not
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
* @param data_length input data length
|
||||
*/
|
||||
static uint32 CircularAreaDivideWrData(CircularAreaType circular_area, uint32 data_length)
|
||||
{
|
||||
NULL_PARAM_CHECK(circular_area);
|
||||
|
||||
if(circular_area->writeidx + data_length <= circular_area->area_length) {
|
||||
return RET_FALSE;
|
||||
} else {
|
||||
return RET_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will read data from the circular_area
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
* @param output_buffer output data buffer poniter
|
||||
* @param data_length output data length
|
||||
*/
|
||||
uint32 CircularAreaRead(CircularAreaType circular_area, uint8 *output_buffer, uint32 data_length)
|
||||
{
|
||||
NULL_PARAM_CHECK(circular_area);
|
||||
NULL_PARAM_CHECK(output_buffer);
|
||||
CHECK(data_length > 0);
|
||||
|
||||
if(CircularAreaIsEmpty(circular_area)) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
data_length = (data_length > CircularAreaGetDataLength(circular_area)) ? CircularAreaGetDataLength(circular_area) : data_length;
|
||||
|
||||
if(CircularAreaDivideRdData(circular_area, data_length)) {
|
||||
uint32 read_len_up = circular_area->area_length - circular_area->readidx;
|
||||
uint32 read_len_down = data_length - read_len_up;
|
||||
|
||||
memcpy(output_buffer, &circular_area->data_buffer[circular_area->readidx], read_len_up);
|
||||
memcpy(output_buffer + read_len_up, circular_area->p_head, read_len_down);
|
||||
|
||||
circular_area->readidx = read_len_down;
|
||||
} else {
|
||||
memcpy(output_buffer, &circular_area->data_buffer[circular_area->readidx], data_length);
|
||||
circular_area->readidx = (circular_area->readidx + data_length) % circular_area->area_length;
|
||||
}
|
||||
|
||||
circular_area->b_status = RET_FALSE;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will write data to the circular_area
|
||||
*
|
||||
* @param circular_area CircularArea descriptor
|
||||
* @param input_buffer input data buffer poniter
|
||||
* @param data_length input data length
|
||||
* @param b_force whether to force to write data disregard the length limit
|
||||
*/
|
||||
uint32 CircularAreaWrite(CircularAreaType circular_area, uint8 *input_buffer, uint32 data_length, x_bool b_force)
|
||||
{
|
||||
NULL_PARAM_CHECK(circular_area);
|
||||
NULL_PARAM_CHECK(input_buffer);
|
||||
CHECK(data_length > 0);
|
||||
|
||||
if(CircularAreaIsFull(circular_area) && (!b_force)) {
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
uint32 write_data_length = circular_area->area_length - CircularAreaGetDataLength(circular_area);
|
||||
data_length = (data_length > write_data_length) ? write_data_length : data_length;
|
||||
|
||||
if(CircularAreaDivideWrData(circular_area, data_length)) {
|
||||
uint32 write_len_up = circular_area->area_length - circular_area->writeidx;
|
||||
uint32 write_len_down = data_length - write_len_up;
|
||||
|
||||
memcpy(&circular_area->data_buffer[circular_area->writeidx], input_buffer, write_len_up);
|
||||
memcpy(circular_area->p_head, input_buffer + write_len_up, write_len_down);
|
||||
|
||||
circular_area->writeidx = write_len_down;
|
||||
} else {
|
||||
memcpy(&circular_area->data_buffer[circular_area->writeidx], input_buffer, data_length);
|
||||
circular_area->writeidx = (circular_area->writeidx + data_length) % circular_area->area_length;
|
||||
}
|
||||
|
||||
circular_area->b_status = RET_TRUE;
|
||||
|
||||
if(b_force) {
|
||||
circular_area->readidx = circular_area->writeidx;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static struct CircularAreaOps CircularAreaOperations =
|
||||
{
|
||||
CircularAreaRead,
|
||||
CircularAreaWrite,
|
||||
CircularAreaRelease,
|
||||
CircularAreaReset,
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will initialize the circular_area
|
||||
*
|
||||
* @param circular_area_length circular_area length
|
||||
*/
|
||||
CircularAreaType CircularAreaInit(uint32 circular_area_length)
|
||||
{
|
||||
CHECK(circular_area_length > 0);
|
||||
|
||||
circular_area_length = ALIGN_MEN_DOWN(circular_area_length, MEM_ALIGN_SIZE);
|
||||
|
||||
CircularAreaType circular_area = x_malloc(sizeof(struct CircularArea));
|
||||
if(NONE == circular_area) {
|
||||
KPrintf("CircularAreaInit malloc struct circular_area failed\n");
|
||||
x_free(circular_area);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
CircularAreaReset(circular_area);
|
||||
|
||||
circular_area->data_buffer = x_malloc(circular_area_length);
|
||||
if(NONE == circular_area->data_buffer) {
|
||||
KPrintf("CircularAreaInit malloc circular_area data_buffer failed\n");
|
||||
x_free(circular_area->data_buffer);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
circular_area->p_head = circular_area->data_buffer;
|
||||
circular_area->p_tail = circular_area->data_buffer + circular_area_length;
|
||||
circular_area->area_length = circular_area_length;
|
||||
|
||||
KPrintf("CircularAreaInit done p_head %8p p_tail %8p length %u\n",
|
||||
circular_area->p_head, circular_area->p_tail, circular_area->area_length);
|
||||
|
||||
circular_area->CircularAreaOperations = &CircularAreaOperations;
|
||||
|
||||
return circular_area;
|
||||
}
|
||||
685
kernel/thread/console.c
Normal file
685
kernel/thread/console.c
Normal file
@@ -0,0 +1,685 @@
|
||||
/*
|
||||
* 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: console.c
|
||||
* @brief: console file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <device.h>
|
||||
|
||||
#if defined(KERNEL_CONSOLE)
|
||||
static HardwareDevType _console = NONE;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Obtain the console
|
||||
*
|
||||
*/
|
||||
HardwareDevType ObtainConsole(void)
|
||||
{
|
||||
#if defined(KERNEL_CONSOLE)
|
||||
return _console;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a console
|
||||
*
|
||||
*
|
||||
* @param name console device name
|
||||
*
|
||||
*/
|
||||
HardwareDevType InstallConsole(const char *bus_name, const char *drv_name, const char *dev_name)
|
||||
{
|
||||
#if defined(KERNEL_CONSOLE)
|
||||
BusType console_bus;
|
||||
DriverType console_drv = NONE;
|
||||
HardwareDevType console = NONE;
|
||||
struct SerialDevParam *serial_dev_param = NONE;
|
||||
struct SerialCfgParam serial_cfg;
|
||||
struct BusConfigureInfo configure_info;
|
||||
|
||||
NULL_PARAM_CHECK(bus_name);
|
||||
NULL_PARAM_CHECK(drv_name);
|
||||
NULL_PARAM_CHECK(dev_name);
|
||||
|
||||
console_bus = BusFind(bus_name);
|
||||
console_drv = BusFindDriver(console_bus, drv_name);
|
||||
console = BusFindDevice(console_bus, dev_name);
|
||||
|
||||
if (console != NONE) {
|
||||
if (_console != NONE) {
|
||||
BusDevClose(_console);
|
||||
}
|
||||
|
||||
configure_info.configure_cmd = OPE_INT;
|
||||
memset(&serial_cfg, 0, sizeof(struct SerialCfgParam));
|
||||
configure_info.private_data = &serial_cfg;
|
||||
BusDrvConfigure(console_drv, &configure_info);
|
||||
console_bus->match(console_drv, console);
|
||||
|
||||
serial_dev_param = (struct SerialDevParam *)console->private_data;
|
||||
serial_dev_param->serial_set_mode = 0;
|
||||
serial_dev_param->serial_stream_mode = SIGN_OPER_STREAM;
|
||||
BusDevOpen(console);
|
||||
_console = console;
|
||||
} else {
|
||||
console = _console;
|
||||
}
|
||||
|
||||
return console;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(KERNEL_CONSOLE)
|
||||
|
||||
static __inline x_bool IsDigit(char c)
|
||||
{
|
||||
return ((unsigned)((c) - '0') < 10);
|
||||
}
|
||||
|
||||
static __inline unsigned int CharToNum(const char **s)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
while (IsDigit(**s)) {
|
||||
i = i * 10 + **s - '0';
|
||||
++ *s;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#define ZEROPAD (1 << 0)
|
||||
#define LEFT (1 << 1)
|
||||
#define SIGN (1 << 2)
|
||||
#define SPACE (1 << 3)
|
||||
#define HASH (1 << 4)
|
||||
|
||||
#define PRINTLONG (1 << 5)
|
||||
#define PRINTLONGLONG (1 << 6)
|
||||
#define PRINTSHORT (1 << 7)
|
||||
#define PRINTCHAR (1 << 8)
|
||||
|
||||
#define CAPITAL (1 << 9)
|
||||
|
||||
static size_t LongToChar(char* str, unsigned long value, uint32 flags, int32 precision, uint8 base, int32 width, x_bool minus, int32 pointer, int32 size)
|
||||
{
|
||||
char buff[KERNEL_CONSOLEBUF_SIZE/4] = {0};
|
||||
int32 length = 0;
|
||||
|
||||
if(!value)
|
||||
flags &= ~HASH;
|
||||
|
||||
if(!(precision > 0) || value) {
|
||||
do {
|
||||
const char number = (char)(value % base);
|
||||
if(number < 10) {
|
||||
buff[length] = number + '0';
|
||||
} else {
|
||||
if(flags & CAPITAL)
|
||||
buff[length] = 'A' + number - 10;
|
||||
else
|
||||
buff[length] = 'a' + number - 10;
|
||||
}
|
||||
++ length;
|
||||
value /= base;
|
||||
} while (value && (length < KERNEL_CONSOLEBUF_SIZE/4));
|
||||
}
|
||||
|
||||
if(!(flags & LEFT)) {
|
||||
if(width && (minus || (flags & (SIGN | SPACE | ZEROPAD))))
|
||||
-- width;
|
||||
while((length < precision) && (length < KERNEL_CONSOLEBUF_SIZE/4))
|
||||
buff[length++] = '0';
|
||||
while((length < width) && (flags & ZEROPAD) && (length < KERNEL_CONSOLEBUF_SIZE/4))
|
||||
buff[length++] = '0';
|
||||
}
|
||||
|
||||
if((flags & HASH) && ((base == 8) || (base == 16))) {
|
||||
if(!(precision > 0) && length && ((length == precision) || (length == width))) {
|
||||
-- length;
|
||||
if(length && (base == 16))
|
||||
-- length;
|
||||
}
|
||||
switch (base) {
|
||||
case 8:
|
||||
buff[length++] = '0';
|
||||
break;
|
||||
|
||||
case 16:
|
||||
if(flags & CAPITAL)
|
||||
{
|
||||
buff[length++] = 'X';
|
||||
buff[length++] = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
buff[length++] = 'x';
|
||||
buff[length++] = '0';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(length < KERNEL_CONSOLEBUF_SIZE/4) {
|
||||
if(minus)
|
||||
buff[length++] = '-';
|
||||
else if(flags & SIGN)
|
||||
buff[length++] = '+';
|
||||
else if(flags & SPACE)
|
||||
buff[length++] = ' ';
|
||||
}
|
||||
|
||||
const int32 index = pointer;
|
||||
|
||||
if(!(flags & LEFT) && !(flags & ZEROPAD) && (length < width)) {
|
||||
for(int32 i = length; i < width; i++) {
|
||||
str[pointer++] = ' ';
|
||||
if(pointer >= size) {
|
||||
str[size - 1] = '\0';
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (length) {
|
||||
str[pointer++] = buff[--length];
|
||||
if(pointer >= size) {
|
||||
str[size - 1] = '\0';
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
if(flags & LEFT) {
|
||||
while (pointer - index < width) {
|
||||
str[pointer++] = ' ';
|
||||
if(pointer >= size) {
|
||||
str[size - 1] = '\0';
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
static size_t LonglongToChar(char* str, unsigned long long value, uint32 flags, int32 precision, uint8 base, int32 width, x_bool minus, int32 pointer, int32 size)
|
||||
{
|
||||
char buff[KERNEL_CONSOLEBUF_SIZE/4] = {0};
|
||||
int32 length = 0;
|
||||
|
||||
if(!value)
|
||||
flags &= ~HASH;
|
||||
|
||||
if(!(precision > 0) || value){
|
||||
do {
|
||||
const char number = (char)(value % base);
|
||||
if(number < 10) {
|
||||
buff[length] = number + '0';
|
||||
} else {
|
||||
if(flags & CAPITAL)
|
||||
buff[length] = 'A' + number - 10;
|
||||
else
|
||||
buff[length] = 'a' + number - 10;
|
||||
}
|
||||
++ length;
|
||||
value /= base;
|
||||
} while (value && (length < KERNEL_CONSOLEBUF_SIZE/4));
|
||||
}
|
||||
|
||||
if(!(flags & LEFT)) {
|
||||
if(width && (minus || (flags & (SIGN | SPACE | ZEROPAD))))
|
||||
-- width;
|
||||
while((length < precision) && (length < KERNEL_CONSOLEBUF_SIZE/4))
|
||||
buff[length++] = '0';
|
||||
while((length < width) && (flags & ZEROPAD) && (length < KERNEL_CONSOLEBUF_SIZE/4))
|
||||
buff[length++] = '0';
|
||||
}
|
||||
|
||||
if((flags & HASH) && ((base == 8) || (base == 16))) {
|
||||
if(!(precision > 0) && length && ((length == precision) || (length == width))) {
|
||||
-- length;
|
||||
if(length && (base == 16))
|
||||
-- length;
|
||||
}
|
||||
switch (base) {
|
||||
case 8:
|
||||
buff[length++] = '0';
|
||||
break;
|
||||
|
||||
case 16:
|
||||
if(flags & CAPITAL) {
|
||||
buff[length++] = 'X';
|
||||
buff[length++] = '0';
|
||||
} else {
|
||||
buff[length++] = 'x';
|
||||
buff[length++] = '0';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(length < KERNEL_CONSOLEBUF_SIZE/4) {
|
||||
if(minus)
|
||||
buff[length++] = '-';
|
||||
else if(flags & SIGN)
|
||||
buff[length++] = '+';
|
||||
else if(flags & SPACE)
|
||||
buff[length++] = ' ';
|
||||
}
|
||||
|
||||
const int32 index = pointer;
|
||||
|
||||
if(!(flags & LEFT) && !(flags & ZEROPAD) && (length < width)) {
|
||||
for(int32 i = length; i < width; i++) {
|
||||
str[pointer++] = ' ';
|
||||
if(pointer >= size) {
|
||||
str[size - 1] = '\0';
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (length) {
|
||||
str[pointer++] = buff[--length];
|
||||
if(pointer >= size) {
|
||||
str[size - 1] = '\0';
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
if(flags & LEFT) {
|
||||
while (pointer - index < width) {
|
||||
str[pointer++] = ' ';
|
||||
if(pointer >= size) {
|
||||
str[size - 1] = '\0';
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
int VsnPrintf(char *buf, int32 size, const char *fmt, va_list args)
|
||||
{
|
||||
NULL_PARAM_CHECK(buf);
|
||||
|
||||
int32 pointer = 0;
|
||||
int32 len = 0;
|
||||
int32 i = 0;
|
||||
int32 width = 0;
|
||||
int32 precision = 0;
|
||||
uint32 flags = 0;
|
||||
uint8 base = 0;
|
||||
char c = 0;
|
||||
char *str = NONE;
|
||||
char *s = NONE;
|
||||
|
||||
pointer = 0;
|
||||
str = buf;
|
||||
|
||||
while(*fmt) {
|
||||
if (*fmt != '%') {
|
||||
buf[pointer++] = *fmt;
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
++ fmt;
|
||||
continue;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
uint8 CheckFlags = 1;
|
||||
|
||||
while (CheckFlags) {
|
||||
++ fmt;
|
||||
switch (*fmt) {
|
||||
case '0':
|
||||
flags |= ZEROPAD;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
flags |= LEFT;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
flags |= SIGN;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
flags |= SPACE;
|
||||
break;
|
||||
|
||||
case '#':
|
||||
flags |= HASH;
|
||||
break;
|
||||
|
||||
default:
|
||||
CheckFlags = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
width = -1;
|
||||
if (IsDigit(*fmt))
|
||||
width = CharToNum(&fmt);
|
||||
else if (*fmt == '*') {
|
||||
width = va_arg(args, int);
|
||||
if (width < 0) {
|
||||
width = -width;
|
||||
flags |= LEFT;
|
||||
}
|
||||
++ fmt;
|
||||
}
|
||||
|
||||
precision = -1;
|
||||
if (*fmt == '.') {
|
||||
++ fmt;
|
||||
if (IsDigit(*fmt))
|
||||
precision = CharToNum(&fmt);
|
||||
else if (*fmt == '*') {
|
||||
precision = va_arg(args, int);
|
||||
++ fmt;
|
||||
}
|
||||
if (precision < 0)
|
||||
precision = 0;
|
||||
}
|
||||
|
||||
if (*fmt == 'l') {
|
||||
++ fmt;
|
||||
if (*fmt == 'l') {
|
||||
flags |= PRINTLONGLONG;
|
||||
++ fmt;
|
||||
}
|
||||
else
|
||||
flags |= PRINTLONG;
|
||||
}
|
||||
else if(*fmt == 'h') {
|
||||
++ fmt;
|
||||
if (*fmt == 'h') {
|
||||
flags |= PRINTCHAR;
|
||||
++ fmt;
|
||||
}
|
||||
else
|
||||
flags |= PRINTSHORT;
|
||||
}
|
||||
|
||||
base = 10;
|
||||
|
||||
switch (*fmt) {
|
||||
case 'c':
|
||||
if (!(flags & LEFT)) {
|
||||
while (--width > 0) {
|
||||
buf[pointer++] = ' ';
|
||||
if(pointer >= size)
|
||||
{
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c = (char)va_arg(args, int);
|
||||
buf[pointer++] = c;
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
|
||||
while (--width > 0) {
|
||||
buf[pointer++] = ' ';
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
s = va_arg(args, char *);
|
||||
if (!s)
|
||||
s = "(NULL)";
|
||||
|
||||
len = strlen(s);
|
||||
if (precision > 0 && len > precision)
|
||||
len = precision;
|
||||
|
||||
if (!(flags & LEFT)) {
|
||||
while (len < width--) {
|
||||
buf[pointer++] = ' ';
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++ i) {
|
||||
buf[pointer++] = *s;
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
++ s;
|
||||
}
|
||||
|
||||
while (len < width--) {
|
||||
buf[pointer++] = ' ';
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
width = sizeof(void *) * 2;
|
||||
flags |= ZEROPAD | CAPITAL;
|
||||
/* Determine the machine word length */
|
||||
if(sizeof(long) == sizeof(long long))
|
||||
pointer = LonglongToChar(buf, (unsigned long long)va_arg(args, void*), flags, precision, 16, width, 0, pointer, size);
|
||||
else
|
||||
pointer = LongToChar(buf, (unsigned long)va_arg(args, void*), flags, precision, 16, width, 0, pointer, size);
|
||||
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '%':
|
||||
buf[pointer] = '%';
|
||||
++ pointer;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
flags &= ~SIGN;
|
||||
base = 8;
|
||||
if(flags & PRINTLONGLONG)
|
||||
pointer = LonglongToChar(buf, va_arg(args, unsigned long long), flags, precision, base, width, 0, pointer, size);
|
||||
else if(flags & PRINTLONG)
|
||||
pointer = LongToChar(buf, va_arg(args, unsigned long), flags, precision, base, width, 0, pointer, size);
|
||||
else {
|
||||
if(flags & PRINTSHORT) {
|
||||
const unsigned int value = (unsigned short int)va_arg(args, unsigned int);
|
||||
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
|
||||
} else if(flags & PRINTCHAR) {
|
||||
const unsigned int value = (unsigned char)va_arg(args, unsigned int);
|
||||
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
|
||||
} else {
|
||||
const unsigned int value = va_arg(args, unsigned int);
|
||||
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
|
||||
}
|
||||
}
|
||||
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
flags |= CAPITAL;
|
||||
case 'x':
|
||||
flags &= ~SIGN;
|
||||
base = 16;
|
||||
|
||||
if(flags & PRINTLONGLONG)
|
||||
pointer = LonglongToChar(buf, va_arg(args, unsigned long long), flags, precision, base, width, 0, pointer, size);
|
||||
else if(flags & PRINTLONG)
|
||||
pointer = LongToChar(buf, va_arg(args, unsigned long), flags, precision, base, width, 0, pointer, size);
|
||||
else {
|
||||
if(flags & PRINTSHORT) {
|
||||
const unsigned int value = (unsigned short int)va_arg(args, unsigned int);
|
||||
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
|
||||
} else if(flags & PRINTCHAR) {
|
||||
const unsigned int value = (unsigned char)va_arg(args, unsigned int);
|
||||
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
|
||||
} else {
|
||||
const unsigned int value = va_arg(args, unsigned int);
|
||||
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
|
||||
}
|
||||
}
|
||||
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
flags &= ~SIGN;
|
||||
base = 10;
|
||||
flags &= ~HASH;
|
||||
if(flags & PRINTLONGLONG)
|
||||
pointer = LonglongToChar(buf, va_arg(args, unsigned long long), flags, precision, base, width, 0, pointer, size);
|
||||
else if(flags & PRINTLONG)
|
||||
pointer = LongToChar(buf, va_arg(args, unsigned long), flags, precision, base, width, 0, pointer, size);
|
||||
else {
|
||||
if(flags & PRINTSHORT) {
|
||||
const unsigned int value = (unsigned short int)va_arg(args, unsigned int);
|
||||
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
|
||||
} else if(flags & PRINTCHAR) {
|
||||
const unsigned int value = (unsigned char)va_arg(args, unsigned int);
|
||||
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
|
||||
} else {
|
||||
const unsigned int value = va_arg(args, unsigned int);
|
||||
pointer = LongToChar(buf, value, flags, precision, base, width, 0, pointer, size);
|
||||
}
|
||||
}
|
||||
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
base = 10;
|
||||
flags &= ~HASH;
|
||||
if(flags & PRINTLONGLONG) {
|
||||
const long long value = va_arg(args, long long);
|
||||
pointer = LonglongToChar(buf, (unsigned long long)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
|
||||
} else if(flags & PRINTLONG) {
|
||||
const long value = va_arg(args, long);
|
||||
pointer = LongToChar(buf, (unsigned long)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
|
||||
} else {
|
||||
if(flags & PRINTSHORT) {
|
||||
const int value = (short int)va_arg(args, int);
|
||||
pointer = LongToChar(buf, (unsigned int)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
|
||||
} else if(flags & PRINTCHAR) {
|
||||
const int value = (char)va_arg(args, int);
|
||||
pointer = LongToChar(buf, (unsigned int)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
|
||||
} else {
|
||||
const int value = va_arg(args, int);
|
||||
pointer = LongToChar(buf, (unsigned int)(value > 0 ? value : 0 - value), flags, precision, base, width, (value < 0 ? 1 : 0), pointer, size);
|
||||
}
|
||||
}
|
||||
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
buf[pointer++] = '%';
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
|
||||
if (*fmt) {
|
||||
buf[pointer++] = *fmt;
|
||||
if(pointer >= size) {
|
||||
buf[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
} else {
|
||||
-- fmt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
++ fmt;
|
||||
}
|
||||
|
||||
if(pointer > size)
|
||||
pointer = size - 1;
|
||||
buf[pointer] = '\0';
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void KPrintf(const char *fmt, ...)
|
||||
{
|
||||
#ifdef KERNEL_CONSOLE
|
||||
if(_console != NONE) {
|
||||
va_list args;
|
||||
x_size_t length = 0;
|
||||
static char logbuf[KERNEL_CONSOLEBUF_SIZE] = {0};
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
length = VsnPrintf(logbuf, sizeof(logbuf) - 1, fmt, args);
|
||||
if (length > KERNEL_CONSOLEBUF_SIZE - 1)
|
||||
length = KERNEL_CONSOLEBUF_SIZE - 1;
|
||||
|
||||
struct BusBlockWriteParam write_param;
|
||||
write_param.pos = 0;
|
||||
write_param.buffer = (void *)logbuf;
|
||||
write_param.size = length;
|
||||
BusDevWriteData(_console, (void *)&write_param);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
233
kernel/thread/data_queue.c
Normal file
233
kernel/thread/data_queue.c
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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: data_queue.c
|
||||
* @brief: data queue file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <device.h>
|
||||
|
||||
/**
|
||||
* This function allocates dynamic memory from dynamic buddy memory.
|
||||
*
|
||||
* @param p_queue dataqueue structure
|
||||
* @param NodeNumber the number of dataqueue
|
||||
*
|
||||
* @return EOK on success; ERROR on failure
|
||||
*/
|
||||
x_err_t InitDataqueue(DataQueueType *p_queue, uint16 NodeNumber)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(p_queue);
|
||||
|
||||
KPrintf("InitDataqueue\n");
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
do {
|
||||
memset(p_queue, 0, sizeof(DataQueueType));
|
||||
p_queue->front = p_queue->rear = 0;
|
||||
p_queue->max_len = NodeNumber;
|
||||
p_queue->base = (DataElemType *)x_malloc(p_queue->max_len * sizeof(DataElemType));
|
||||
if (!p_queue->base) {
|
||||
break;
|
||||
}
|
||||
|
||||
// The semaphore is initialized to len-1, because the full condition of the loop queue is real + 1 = = front,
|
||||
// a vacancy is always wasted
|
||||
p_queue->sem_blank = KSemaphoreCreate( p_queue->max_len - 1);
|
||||
if (!p_queue->sem_blank) {
|
||||
break;
|
||||
}
|
||||
|
||||
p_queue->sem_data = KSemaphoreCreate( 0);
|
||||
if (!p_queue->sem_data) {
|
||||
break;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
return EOK;
|
||||
} while (0);
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
DeInitDataqueue(p_queue);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function realses all dataqueue resource.
|
||||
*
|
||||
* @param p_queue dataqueue structure
|
||||
*
|
||||
*/
|
||||
|
||||
void DeInitDataqueue(DataQueueType *p_queue)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(p_queue);
|
||||
|
||||
KPrintf("DeInitDataqueue\n");
|
||||
|
||||
lock = DISABLE_INTERRUPT();
|
||||
|
||||
if (p_queue->base) {
|
||||
x_free(p_queue->base);
|
||||
p_queue->base = NONE;
|
||||
}
|
||||
|
||||
if (p_queue->sem_blank) {
|
||||
KSemaphoreDelete(p_queue->sem_blank);
|
||||
p_queue->sem_blank = NONE;
|
||||
}
|
||||
|
||||
if (p_queue->sem_data) {
|
||||
KSemaphoreDelete(p_queue->sem_data);
|
||||
p_queue->sem_data = NONE;
|
||||
}
|
||||
ENABLE_INTERRUPT(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will push a data into dataqueue .
|
||||
*
|
||||
* @param p_queue dataqueue structure
|
||||
* @param StartAddr the data needed to be pushed
|
||||
* @param DataSize data size
|
||||
* @param timeout timeout
|
||||
*
|
||||
* @return EOK on success; ERROR on failure
|
||||
*/
|
||||
x_err_t PushDataqueue(DataQueueType *p_queue, const void *StartAddr, x_size_t DataSize, int32 timeout)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(p_queue);
|
||||
NULL_PARAM_CHECK(StartAddr);
|
||||
|
||||
KPrintf("PushDataqueue\n");
|
||||
|
||||
do {
|
||||
if (WAITING_FOREVER == timeout) {
|
||||
// block
|
||||
KSemaphoreObtain(p_queue->sem_blank, WAITING_FOREVER);
|
||||
break;
|
||||
} else if (0 == timeout) {
|
||||
// Nonblocking
|
||||
if (EOK == KSemaphoreObtain(p_queue->sem_blank, 0)) {
|
||||
break;
|
||||
} else {
|
||||
return -ERROR;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
if ((p_queue->rear + 1) % p_queue->max_len != p_queue->front) {
|
||||
DataElemType *pElem = &(p_queue->base[p_queue->rear]);
|
||||
pElem->data = StartAddr;
|
||||
pElem->length = DataSize;
|
||||
p_queue->rear = (p_queue->rear + 1) % p_queue->max_len;
|
||||
}
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
KSemaphoreAbandon(p_queue->sem_data);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will pop a data from dataqueue .
|
||||
*
|
||||
* @param p_queue dataqueue structure
|
||||
* @param StartAddr the data needed to be popped
|
||||
* @param DataSize data size
|
||||
* @param timeout timeout
|
||||
*
|
||||
* @return EOK on success; ERROR on failure
|
||||
*/
|
||||
x_err_t PopDataqueue(DataQueueType *p_queue, const void **StartAddr, x_size_t *size, int32 timeout)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(p_queue);
|
||||
|
||||
KPrintf("PopDataqueue\n");
|
||||
|
||||
do {
|
||||
if (WAITING_FOREVER == timeout) {
|
||||
// block
|
||||
KSemaphoreObtain(p_queue->sem_data, WAITING_FOREVER);
|
||||
break;
|
||||
} else if (0 == timeout) {
|
||||
// Nonblocking
|
||||
if (EOK == KSemaphoreObtain(p_queue->sem_data, 0)) {
|
||||
// Get success
|
||||
break;
|
||||
} else {
|
||||
// Get failed, exit directly
|
||||
return -ERROR;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
// Semaphore surplus, read data directly
|
||||
if (p_queue->front != p_queue->rear) {
|
||||
DataElemType *pElem = &(p_queue->base[p_queue->front]);
|
||||
*StartAddr = pElem->data;
|
||||
*size = pElem->length;
|
||||
p_queue->front = (p_queue->front + 1) % p_queue->max_len;
|
||||
}
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
// Release data semaphore
|
||||
KSemaphoreAbandon(p_queue->sem_blank);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get the first data of dataqueue .
|
||||
*
|
||||
* @param p_queue dataqueue structure
|
||||
* @param StartAddr the data needed to be popped
|
||||
* @param size data size
|
||||
*
|
||||
* @return EOK on success; ERROR on failure
|
||||
*/
|
||||
x_err_t DataqueuePeak(DataQueueType *p_queue, const void **StartAddr, x_size_t *size)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(p_queue);
|
||||
|
||||
KPrintf("DataqueuePeak\n");
|
||||
|
||||
if (p_queue->front != p_queue->rear) {
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
DataElemType *pElem = &(p_queue->base[p_queue->front]);
|
||||
*StartAddr = pElem->data;
|
||||
*size = pElem->length;
|
||||
CriticalAreaUnLock(lock);
|
||||
return EOK;
|
||||
} else {
|
||||
return -ERROR;
|
||||
}
|
||||
}
|
||||
150
kernel/thread/delay.c
Normal file
150
kernel/thread/delay.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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: delay.c
|
||||
* @brief: set task delay and check the timeout
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xs_klist.h>
|
||||
#include<string.h>
|
||||
#include<xs_isr.h>
|
||||
#include <xs_ktask.h>
|
||||
#include <xs_memory.h>
|
||||
#include<xs_ktick.h>
|
||||
#include<xiuos.h>
|
||||
|
||||
DoubleLinklistType xiaoshan_delay_head = {&xiaoshan_delay_head, &xiaoshan_delay_head};
|
||||
|
||||
/**
|
||||
* This function will delay a task with sone ticks.
|
||||
*
|
||||
* @param task the task needed to be delayed
|
||||
* @param ticks delay timeout
|
||||
*
|
||||
* @return EOK on success; ENOMEMORY on failure
|
||||
*/
|
||||
x_err_t KTaskSetDelay(KTaskDescriptorType task, x_ticks_t ticks)
|
||||
{
|
||||
x_base lock = 0;
|
||||
struct Delay *delay = NONE;
|
||||
struct Delay *dnode = NONE;
|
||||
DoubleLinklistType *nodelink = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
if (task->task_dync_sched_member.delay == NONE) {
|
||||
delay = (struct Delay *)x_malloc(sizeof(struct Delay));
|
||||
if (delay == NONE)
|
||||
{
|
||||
return -ENOMEMORY;
|
||||
}
|
||||
memset(delay, 0x0, sizeof(struct Delay));
|
||||
task->task_dync_sched_member.delay = delay;
|
||||
} else {
|
||||
delay = task->task_dync_sched_member.delay;
|
||||
lock = CriticalAreaLock();
|
||||
if(delay->status == TASK_DELAY_ACTIVE){
|
||||
delay->status = TASK_DELAY_INACTIVE;
|
||||
DoubleLinkListRmNode(&(delay->link));
|
||||
}
|
||||
CriticalAreaUnLock(lock);
|
||||
}
|
||||
|
||||
delay->ticks = CurrentTicksGain() + ticks;
|
||||
delay->task = task;
|
||||
delay->status = TASK_DELAY_ACTIVE;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
DOUBLE_LINKLIST_FOR_EACH(nodelink, &xiaoshan_delay_head) {
|
||||
dnode =CONTAINER_OF(nodelink, struct Delay, link);
|
||||
if (delay->ticks < dnode->ticks) {
|
||||
DoubleLinkListInsertNodeBefore(nodelink, &delay->link);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodelink == &xiaoshan_delay_head) {
|
||||
DoubleLinkListInsertNodeBefore(&xiaoshan_delay_head, &(delay->link));
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will wakeup a task from delay list.
|
||||
*
|
||||
* @param task the task needed to be wakeup
|
||||
*
|
||||
* @return EOK
|
||||
*/
|
||||
x_err_t KTaskUnSetDelay(KTaskDescriptorType task)
|
||||
{
|
||||
x_base lock = 0;
|
||||
struct Delay *delay = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
delay = task->task_dync_sched_member.delay;
|
||||
|
||||
if( delay != NONE && delay->status == TASK_DELAY_ACTIVE) {
|
||||
lock = CriticalAreaLock();
|
||||
delay->status = TASK_DELAY_INACTIVE;
|
||||
DoubleLinkListRmNode(&(delay->link));
|
||||
CriticalAreaUnLock(lock);
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
|
||||
void CheckTaskDelay(void)
|
||||
{
|
||||
x_base level = 0;
|
||||
x_ticks_t current_tick = 0;
|
||||
struct Delay *node = NONE;
|
||||
|
||||
SYS_KDEBUG_LOG(0, ("delay check enter\n"));
|
||||
|
||||
current_tick = CurrentTicksGain();
|
||||
|
||||
level = CriticalAreaLock();
|
||||
|
||||
while (!IsDoubleLinkListEmpty(&xiaoshan_delay_head))
|
||||
{
|
||||
node = SYS_DOUBLE_LINKLIST_ENTRY(xiaoshan_delay_head.node_next,
|
||||
struct Delay, link);
|
||||
|
||||
if ((current_tick - node->ticks) < TICK_SIZE_MAX / 2)
|
||||
{
|
||||
current_tick = CurrentTicksGain();
|
||||
SYS_KDEBUG_LOG(KDBG_SOFTTIMER, ("current tick: %d\n", current_tick));
|
||||
KTaskUnSetDelay(node->task);
|
||||
CriticalAreaUnLock(level);
|
||||
KTaskTimeout(node->task);
|
||||
level = CriticalAreaLock();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(level);
|
||||
|
||||
SYS_KDEBUG_LOG(0, ("delay check leave\n"));
|
||||
}
|
||||
132
kernel/thread/double_link.c
Normal file
132
kernel/thread/double_link.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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: double_link.c
|
||||
* @brief: functions definition of double linklist
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <xs_klist.h>
|
||||
|
||||
/**
|
||||
* This function will init a linklist.
|
||||
*
|
||||
* @param linklist_head linklist node
|
||||
*/
|
||||
void InitDoubleLinkList(DoubleLinklistType *linklist_head)
|
||||
{
|
||||
linklist_head->node_next = linklist_head;
|
||||
linklist_head->node_prev = linklist_head;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will insert a node into list after the node.
|
||||
*
|
||||
* @param linklist linklist node
|
||||
* @param linklist_node the node needed to inserted
|
||||
*/
|
||||
void DoubleLinkListInsertNodeAfter(DoubleLinklistType *linklist, DoubleLinklistType *linklist_node)
|
||||
{
|
||||
linklist->node_next->node_prev = linklist_node;
|
||||
linklist_node->node_next = linklist->node_next;
|
||||
|
||||
linklist->node_next = linklist_node;
|
||||
linklist_node->node_prev = linklist;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will insert a node into list after the node.
|
||||
*
|
||||
* @param linklist linklist node
|
||||
* @param linklist_node the node needed to inserted
|
||||
*/
|
||||
void DoubleLinkListInsertNodeBefore(DoubleLinklistType *linklist, DoubleLinklistType *linklist_node)
|
||||
{
|
||||
linklist->node_prev->node_next = linklist_node;
|
||||
linklist_node->node_prev = linklist->node_prev;
|
||||
|
||||
linklist->node_prev = linklist_node;
|
||||
linklist_node->node_next = linklist;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will remove a node from the list.
|
||||
*
|
||||
* @param linklist_node the node needed to removed
|
||||
*/
|
||||
void DoubleLinkListRmNode(DoubleLinklistType *linklist_node)
|
||||
{
|
||||
linklist_node->node_next->node_prev = linklist_node->node_prev;
|
||||
linklist_node->node_prev->node_next = linklist_node->node_next;
|
||||
|
||||
linklist_node->node_next = linklist_node;
|
||||
linklist_node->node_prev = linklist_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will judge the list is empty.
|
||||
*
|
||||
* @param linklist the list head
|
||||
* @return true
|
||||
*/
|
||||
int IsDoubleLinkListEmpty(const DoubleLinklistType *linklist)
|
||||
{
|
||||
return linklist->node_next == linklist;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get the head of the list.
|
||||
*
|
||||
* @param linklist list head
|
||||
* @return list head
|
||||
*/
|
||||
struct SysDoubleLinklistNode *DoubleLinkListGetHead(const DoubleLinklistType *linklist)
|
||||
{
|
||||
return IsDoubleLinkListEmpty(linklist) ? NONE : linklist->node_next;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get the next node of the list head.
|
||||
*
|
||||
* @param linklist list head
|
||||
* @param linklist_node list head
|
||||
* @return next node of the list head
|
||||
*/
|
||||
struct SysDoubleLinklistNode *DoubleLinkListGetNext(const DoubleLinklistType *linklist,
|
||||
const struct SysDoubleLinklistNode *linklist_node)
|
||||
{
|
||||
return linklist_node->node_next == linklist ? NONE : linklist_node->node_next;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get length of the list.
|
||||
*
|
||||
* @param linklist list head
|
||||
* @return length
|
||||
*/
|
||||
unsigned int DoubleLinkListLenGet(const DoubleLinklistType *linklist)
|
||||
{
|
||||
unsigned int linklist_length = 0;
|
||||
const DoubleLinklistType *tmp_node = linklist;
|
||||
while (tmp_node->node_next != linklist)
|
||||
{
|
||||
tmp_node = tmp_node->node_next;
|
||||
linklist_length ++;
|
||||
}
|
||||
|
||||
return linklist_length;
|
||||
}
|
||||
302
kernel/thread/event.c
Normal file
302
kernel/thread/event.c
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* 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: event.c
|
||||
* @brief: event file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
DECLARE_ID_MANAGER(k_event_id_manager, ID_NUM_MAX);
|
||||
DoubleLinklistType k_event_list ={&k_event_list, &k_event_list};
|
||||
|
||||
static int32 _EventCreate(uint32 options)
|
||||
{
|
||||
int32 id = 0;
|
||||
x_base lock = 0;
|
||||
struct Event *event = NONE;
|
||||
|
||||
event = (struct Event *)x_malloc(sizeof(struct Event));
|
||||
if (event == NONE)
|
||||
return -ENOMEMORY;
|
||||
|
||||
memset(event, 0, sizeof(struct Event));
|
||||
lock = CriticalAreaLock();
|
||||
id = IdInsertObj(&k_event_id_manager, &event->id);
|
||||
if (id < 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
x_free(event);
|
||||
return -ENOMEMORY;
|
||||
}
|
||||
|
||||
event->options = options;
|
||||
InitDoubleLinkList(&event->pend_list);
|
||||
|
||||
DoubleLinkListInsertNodeAfter(&k_event_list, &event->link);
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void _EventDelete(struct Event *event)
|
||||
{
|
||||
int resched = 0;
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(event);
|
||||
|
||||
if (!IsDoubleLinkListEmpty(&event->pend_list)) {
|
||||
resched = 1;
|
||||
LinklistResumeAll(&event->pend_list);
|
||||
}
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
IdRemoveObj(&k_event_id_manager, event->id.id);
|
||||
|
||||
DoubleLinkListRmNode(&event->link);
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
x_free(event);
|
||||
|
||||
if (resched)
|
||||
DO_KTASK_ASSIGN;
|
||||
}
|
||||
|
||||
static int32 _EventTrigger(struct Event *event, uint32 events)
|
||||
{
|
||||
x_bool resched;
|
||||
x_ubase lock = 0;
|
||||
x_base status = 0;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
struct SysDoubleLinklistNode *n = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(event);
|
||||
|
||||
if (events == 0)
|
||||
return -ERROR;
|
||||
|
||||
resched = RET_FALSE;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
event->events |= events;
|
||||
|
||||
if (IsDoubleLinkListEmpty(&event->pend_list)) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
n = event->pend_list.node_next;
|
||||
while (n != &(event->pend_list)) {
|
||||
task = SYS_DOUBLE_LINKLIST_ENTRY(n, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
||||
status = -ERROR;
|
||||
if (task->event_mode & EVENT_AND) {
|
||||
if ((task->event_id_trigger & (event->events & EVENT_EVENTS_MASK)) == task->event_id_trigger)
|
||||
status = EOK;
|
||||
} else if (task->event_mode & EVENT_OR) {
|
||||
if (task->event_id_trigger & (event->events & EVENT_EVENTS_MASK)) {
|
||||
task->event_id_trigger = task->event_id_trigger & (event->events & EVENT_EVENTS_MASK);
|
||||
status = EOK;
|
||||
}
|
||||
}
|
||||
|
||||
n = n->node_next;
|
||||
|
||||
if (status == EOK) {
|
||||
if (task->event_mode & EVENT_AUTOCLEAN)
|
||||
event->events &= ~task->event_id_trigger;
|
||||
|
||||
KTaskWakeup(task->id.id);
|
||||
|
||||
resched = RET_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
if (resched == RET_TRUE)
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int32 _EventProcess(struct Event *event, uint32 events, uint32 options, int32 msec, uint32 *processed)
|
||||
{
|
||||
|
||||
x_ubase lock = 0;
|
||||
x_base status = 0;
|
||||
int32 timeout = 0;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
KDEBUG_IN_KTASK_CONTEXT;
|
||||
|
||||
NULL_PARAM_CHECK(event);
|
||||
|
||||
if (events == 0)
|
||||
return -ERROR;
|
||||
|
||||
status = -ERROR;
|
||||
task = GetKTaskDescriptor();
|
||||
task->exstatus = EOK;
|
||||
|
||||
timeout = CalculteTickFromTimeMs(msec);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
if (options & EVENT_AND) {
|
||||
if ((event->events & events) == events)
|
||||
status = EOK;
|
||||
} else if (options & EVENT_OR) {
|
||||
if (event->events & events)
|
||||
status = EOK;
|
||||
} else {
|
||||
CHECK(0);
|
||||
}
|
||||
|
||||
if (status == EOK) {
|
||||
if (processed)
|
||||
*processed = (event->events & events);
|
||||
|
||||
if (options & EVENT_AUTOCLEAN)
|
||||
event->events &= ~events;
|
||||
} else if (timeout == 0) {
|
||||
task->exstatus = -ETIMEOUT;
|
||||
} else {
|
||||
task->event_id_trigger = (events & EVENT_EVENTS_MASK);
|
||||
task->event_mode = (options & EVENT_OPTIONS_MASK);
|
||||
|
||||
LinklistSuspend(&(event->pend_list), task, event->options);
|
||||
|
||||
if (timeout > 0)
|
||||
KTaskSetDelay(task,timeout);
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
if (task->exstatus != EOK)
|
||||
return task->exstatus;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
if (processed)
|
||||
*processed = task->event_id_trigger;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return task->exstatus;
|
||||
}
|
||||
|
||||
static EventDoneType done = {
|
||||
.EventCreate = _EventCreate,
|
||||
.EventDelete = _EventDelete,
|
||||
.EventTrigger = _EventTrigger,
|
||||
.EventProcess = _EventProcess,
|
||||
};
|
||||
|
||||
static struct Event *FindEventById(int32 id)
|
||||
{
|
||||
x_base lock = 0;
|
||||
struct IdNode *idnode = NONE;
|
||||
struct Event *event = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return NONE;
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_event_id_manager, id);
|
||||
if (idnode == NONE) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
event = CONTAINER_OF(idnode, struct Event, id);
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will create a event.
|
||||
*
|
||||
* @param options the trigger way of event.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
int32 KEventCreate(uint32 options)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
return done.EventCreate(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will delete a event.
|
||||
*
|
||||
* @param id the id number of event.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
void KEventDelete(int32 id)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
struct Event *event = FindEventById(id);
|
||||
|
||||
if (event == NONE)
|
||||
return;
|
||||
|
||||
done.EventDelete(event);
|
||||
}
|
||||
/**
|
||||
* This function will trigger the event
|
||||
*
|
||||
* @param id the id number of event
|
||||
* @param events trigger way & events flag
|
||||
*
|
||||
* @return EOK on success.
|
||||
*/
|
||||
int32 KEventTrigger(int32 id, uint32 events)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
struct Event *event = FindEventById(id);
|
||||
|
||||
if (event == NONE)
|
||||
return -ERROR;
|
||||
|
||||
return done.EventTrigger(event, events);
|
||||
}
|
||||
/**
|
||||
* This function will get the event and process this event
|
||||
*
|
||||
* @param id the id number of event
|
||||
* @param events events flag
|
||||
* @param options trigger way
|
||||
* @param msec timeout
|
||||
* @processed event processed flag
|
||||
*
|
||||
* @return EOK on success.
|
||||
*/
|
||||
int32 KEventProcess(int32 id, uint32 events, uint32 options, int32 msec, uint32 *processed)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
struct Event *event = FindEventById(id);
|
||||
|
||||
return done.EventProcess(event, events, options, msec, processed);
|
||||
}
|
||||
216
kernel/thread/hook.c
Normal file
216
kernel/thread/hook.c
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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: hook.c
|
||||
* @brief: the general interface functions of hook
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/20
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xs_kdbg.h>
|
||||
#include <xs_hook.h>
|
||||
|
||||
struct KernelHook hook;
|
||||
|
||||
/**
|
||||
* a hook function, it will run when switch task
|
||||
*
|
||||
* @param from task descriptor
|
||||
* @param to task descriptor
|
||||
*/
|
||||
void AssignHook(KTaskDescriptorType from, KTaskDescriptorType to)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], from task: %s, to task:%s\n",__func__,from->task_base_info.name,to->task_base_info.name));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This hook function will be run after task inited .
|
||||
*
|
||||
* @param task task descripter
|
||||
*
|
||||
* @note no blocked or suspend function.
|
||||
*/
|
||||
void TaskCreatehook(KTaskDescriptorType task)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Create task: %s\n",__func__,task->task_base_info.name));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This hook function will be run after task suspended .
|
||||
*
|
||||
* @param task descripter
|
||||
*
|
||||
* @note no blocked or suspend function.
|
||||
*/
|
||||
void TaskSuspendhook(KTaskDescriptorType task)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Suspend task: %s\n",__func__,task->task_base_info.name));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This hook function will be run after task resumed .
|
||||
*
|
||||
* @param task descripter
|
||||
*
|
||||
* @note no blocked or suspend function.
|
||||
*/
|
||||
void TaskResumehook(KTaskDescriptorType task)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Resume task: %s\n",__func__,task->task_base_info.name));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
/**
|
||||
* a MallocHook function. The MallocHook function will be run before a memory block is allocated from buddy-memory.
|
||||
*
|
||||
* @param ptr alloc mem point
|
||||
* @param size alloc mem size
|
||||
*/
|
||||
void MemMallochook(void *ptr, x_size_t size)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Malloc memory: ptr:%p, size: %d\n",__func__,ptr,size));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
/**
|
||||
* a FreeHook function. The FreeHook function will be run after a memory block is freed to buddy-memory.
|
||||
*
|
||||
* @param ptr free mem point
|
||||
*/
|
||||
void MemFreehook(void *ptr)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Free memory: ptr:%p\n",__func__,ptr));
|
||||
/* add your code */
|
||||
}
|
||||
#ifdef KERNEL_MEMBLOCK
|
||||
/**
|
||||
* a allocation hook function before a gatherblock allocation.
|
||||
*
|
||||
* @param gm the alloc hook function
|
||||
* @param date_ptr mem point
|
||||
*/
|
||||
void GmAllocHook(struct MemGather *gm, void *date_ptr)
|
||||
{
|
||||
/* add your code */
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* a free hook function after a gatherblock release.
|
||||
*
|
||||
* @param gm the free hook function
|
||||
* @param date_ptr mem point
|
||||
*/
|
||||
void GmFreeHook(struct MemGather *gm, void *date_ptr)
|
||||
{
|
||||
/* add your code */
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* this hook function will run when the system interrupt
|
||||
*
|
||||
* @note no blocked or suspend.
|
||||
*/
|
||||
void IsrEnterHook(void)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Enter Isr\n",__func__));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
/**
|
||||
* this hook function will run when the system leave interrupt
|
||||
*
|
||||
* @note no blocked or suspend.
|
||||
*/
|
||||
void IsrLeaveHook(void)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Leave Isr\n",__func__));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
void TimerEnterHook(struct Timer *timer)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Timer Enter\n",__func__));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
void TimerExitHook(struct Timer *timer)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Timer Exit\n",__func__));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
void IdleTaskHook(void)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s], Idle0 \n",__func__));
|
||||
/* add your code */
|
||||
}
|
||||
|
||||
|
||||
|
||||
void testhook(const char *str)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_HOOK,
|
||||
("HOOK: Function[%s],Test: %s\n",__func__,str));
|
||||
/* add your code */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int hook_init(void)
|
||||
{
|
||||
REGISTER_HOOK(hook.assign.hook_Assign,AssignHook);
|
||||
|
||||
REGISTER_HOOK(hook.task.hook_TaskCreate,TaskCreatehook);
|
||||
REGISTER_HOOK(hook.task.hook_TaskSuspend,TaskSuspendhook);
|
||||
REGISTER_HOOK(hook.task.hook_TaskResume,TaskResumehook);
|
||||
|
||||
REGISTER_HOOK(hook.mem.hook_Malloc,MemMallochook);
|
||||
REGISTER_HOOK(hook.mem.hook_Free,MemFreehook);
|
||||
|
||||
#ifdef KERNEL_MEMBLOCK
|
||||
REGISTER_HOOK(hook.mem.hook_GmAlloc,GmAllocHook);
|
||||
REGISTER_HOOK(hook.mem.hook_GmFree,GmFreeHook);
|
||||
#endif
|
||||
|
||||
REGISTER_HOOK(hook.timer.hook_TimerEnter,TimerEnterHook);
|
||||
REGISTER_HOOK(hook.timer.hook_TimerExit,TimerExitHook);
|
||||
|
||||
REGISTER_HOOK(hook.idle.hook_Idle,IdleTaskHook);
|
||||
//REGISTER_HOOK(hook.idle[1].hook_Idle,IdleTask1Hook);
|
||||
|
||||
REGISTER_HOOK(hook.isr.hook_IsrEnter,IsrEnterHook);
|
||||
REGISTER_HOOK(hook.isr.hook_IsrLeave,IsrLeaveHook);
|
||||
REGISTER_HOOK(hook.test.hook_test,testhook);
|
||||
return EOK;
|
||||
}
|
||||
142
kernel/thread/id.c
Normal file
142
kernel/thread/id.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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: id.c
|
||||
* @brief: the management with id for all kernel object
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/4/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
static int AllocId(struct IdManager *manager)
|
||||
{
|
||||
int index = 0;
|
||||
int end = 0;
|
||||
int id = 0;
|
||||
uint8 entry = 0;
|
||||
|
||||
NULL_PARAM_CHECK(manager);
|
||||
|
||||
end = (manager->id_max + 7) / 8;
|
||||
|
||||
for (index = 0; index < end; index++)
|
||||
if (manager->id_map[index] != 0xff)
|
||||
break;
|
||||
if (index == end)
|
||||
return -1;
|
||||
|
||||
id = index * 8;
|
||||
entry = manager->id_map[index];
|
||||
while (entry & 0x1) {
|
||||
id++;
|
||||
entry >>= 1;
|
||||
}
|
||||
if (id >= manager->id_max)
|
||||
return -1;
|
||||
|
||||
manager->id_map[index] |= (0x1 << (id % 8));
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void FreeId(struct IdManager *manager, uint16 id)
|
||||
{
|
||||
NULL_PARAM_CHECK(manager);
|
||||
|
||||
manager->id_map[id / 8] &= ~(0x1 << (id % 8));
|
||||
}
|
||||
|
||||
static void InsertObj(struct IdManager *manager, struct IdNode *idnode)
|
||||
{
|
||||
NULL_PARAM_CHECK(manager);
|
||||
NULL_PARAM_CHECK(idnode);
|
||||
|
||||
DoubleLinklistType *head = &manager->htable[idnode->id % manager->hoffset];
|
||||
|
||||
if (head->node_prev == NONE)
|
||||
InitDoubleLinkList(head);
|
||||
|
||||
DoubleLinkListInsertNodeAfter(head, &idnode->link);
|
||||
}
|
||||
|
||||
static struct IdNode *GetObj(struct IdManager *manager, uint16 id)
|
||||
{
|
||||
NULL_PARAM_CHECK(manager);
|
||||
|
||||
DoubleLinklistType *head = &manager->htable[id % manager->hoffset];
|
||||
DoubleLinklistType *node = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
if (head->node_prev == NONE) {
|
||||
InitDoubleLinkList(head);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
DOUBLE_LINKLIST_FOR_EACH(node, head) {
|
||||
idnode =CONTAINER_OF(node, struct IdNode, link);
|
||||
if (idnode->id == id)
|
||||
break;
|
||||
idnode = NONE;
|
||||
}
|
||||
|
||||
return idnode;
|
||||
}
|
||||
|
||||
static struct IdNode *RemoveObj(struct IdManager *manager, struct IdNode *idnode)
|
||||
{
|
||||
NULL_PARAM_CHECK(manager);
|
||||
NULL_PARAM_CHECK(idnode);
|
||||
|
||||
DoubleLinkListRmNode(&idnode->link);
|
||||
}
|
||||
|
||||
int IdInsertObj(struct IdManager *manager, struct IdNode *idnode)
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
NULL_PARAM_CHECK(manager);
|
||||
NULL_PARAM_CHECK(idnode);
|
||||
|
||||
if ((id = AllocId(manager)) < 0)
|
||||
return -1;
|
||||
|
||||
idnode->id = id;
|
||||
InsertObj(manager, idnode);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
struct IdNode *IdGetObj(struct IdManager *manager, uint16 id)
|
||||
{
|
||||
if (manager == NONE || id >= manager->id_max)
|
||||
return NONE;
|
||||
|
||||
return GetObj(manager, id);
|
||||
}
|
||||
|
||||
void IdRemoveObj(struct IdManager *manager, uint16 id)
|
||||
{
|
||||
NULL_PARAM_CHECK(manager);
|
||||
|
||||
struct IdNode *idnode = IdGetObj(manager, id);
|
||||
|
||||
if (idnode == NONE)
|
||||
return;
|
||||
|
||||
FreeId(manager, idnode->id);
|
||||
RemoveObj(manager, idnode);
|
||||
idnode->id = -1;
|
||||
}
|
||||
105
kernel/thread/idle.c
Normal file
105
kernel/thread/idle.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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: idle.c
|
||||
* @brief: idle file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <xs_hook.h>
|
||||
#include <xs_spinlock.h>
|
||||
|
||||
#if defined (KERNEL_HOOK)
|
||||
#ifndef KERNEL_IDLE_HOOK
|
||||
#define KERNEL_IDLE_HOOK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef IDLE_KTASK_STACKSIZE
|
||||
#define IDLE_KTASK_STACKSIZE 256
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
#define CORE_NUM CPU_NUMBERS
|
||||
#else
|
||||
#define CORE_NUM 1
|
||||
#endif
|
||||
|
||||
|
||||
static int32 idle[CORE_NUM];
|
||||
__attribute__((aligned(MEM_ALIGN_SIZE)))
|
||||
|
||||
void RunningIntoLowPowerMode()
|
||||
{
|
||||
#ifdef ARCH_ARM
|
||||
__asm volatile("WFI");
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_RISCV
|
||||
asm volatile ("wfi");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void IdleKTaskEntry(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
#ifdef KERNEL_IDLE_HOOK
|
||||
HOOK(hook.idle.hook_Idle,());
|
||||
#endif
|
||||
RunningIntoLowPowerMode();
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* init system idle task,then startup the idle task
|
||||
*
|
||||
*/
|
||||
void InitIdleKTask(void)
|
||||
{
|
||||
uint8 coreid = 0;
|
||||
char ktaskidle[NAME_NUM_MAX] = {0};
|
||||
|
||||
for (coreid = 0; coreid < CORE_NUM; coreid++) {
|
||||
sprintf(ktaskidle, "ktaskidle%d", coreid);
|
||||
|
||||
idle[coreid] = KTaskCreate(ktaskidle,IdleKTaskEntry,NONE,IDLE_KTASK_STACKSIZE,KTASK_LOWEST_PRIORITY);
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
KTaskCoreCombine(idle[coreid], coreid);
|
||||
#endif
|
||||
StartupKTask(idle[coreid]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This function will return the idle task descriptor
|
||||
*
|
||||
*/
|
||||
KTaskDescriptorType GetIdleKTaskDescripter(void)
|
||||
{
|
||||
KTaskDescriptorType idle_p = NONE;
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
register int id = GetCpuId();
|
||||
#else
|
||||
register int id = 0;
|
||||
#endif
|
||||
|
||||
idle_p = CONTAINER_OF(&idle[id], struct TaskDescriptor, id);
|
||||
return idle_p;
|
||||
}
|
||||
260
kernel/thread/init.c
Normal file
260
kernel/thread/init.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* 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: init.c
|
||||
* @brief: init file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <xs_assign.h>
|
||||
#include <xs_init.h>
|
||||
#include <xs_spinlock.h>
|
||||
#include <xs_workqueue.h>
|
||||
#include <stdlib.h>
|
||||
#include <board.h>
|
||||
|
||||
#ifdef BSP_USING_USBH
|
||||
#include "connect_usb.h"
|
||||
#endif
|
||||
|
||||
#ifdef KERNEL_USER_MAIN
|
||||
#ifndef MAIN_KTASK_STACK_SIZE
|
||||
#define MAIN_KTASK_STACK_SIZE 2048
|
||||
#endif
|
||||
#ifndef MAIN_KTASK_PRIORITY
|
||||
#define MAIN_KTASK_PRIORITY (KTASK_PRIORITY_MAX / 3)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern void CreateKServiceKTask(void);
|
||||
extern int main(void);
|
||||
void InitBoardHardware(void);
|
||||
extern int hook_init(void);
|
||||
int cplusplus_system_init(void);
|
||||
|
||||
#ifdef KERNEL_COMPONENTS_INIT
|
||||
#ifdef USER_APPLICATION
|
||||
extern void CreateMainTask(void);
|
||||
#ifdef SEPARATE_COMPILE
|
||||
int InitUserspace(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ENV_INIT_KTASK_STACK_SIZE
|
||||
#define ENV_INIT_KTASK_STACK_SIZE 8192
|
||||
#endif
|
||||
|
||||
struct InitSequenceDesc prev_cmpts_init[] =
|
||||
{
|
||||
#ifdef FS_VFS
|
||||
{ "vfs", VfsInit },
|
||||
#endif
|
||||
#ifdef LIB_CPLUSPLUS
|
||||
{ "cplusplus_system", cplusplus_system_init },
|
||||
#endif
|
||||
#ifdef KERNEL_HOOK
|
||||
{ "hook", hook_init },
|
||||
#endif
|
||||
{ " NONE ", NONE },
|
||||
};
|
||||
struct InitSequenceDesc device_init[] =
|
||||
{
|
||||
#ifdef KERNEL_WORKQUEUE
|
||||
{ "work sys workqueue", WorkSysWorkQueueInit },
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_ARM
|
||||
#ifdef RESOURCES_SPI_SFUD
|
||||
{ "W25Qxx_spi", FlashW25qxxSpiDeviceInit},
|
||||
#endif
|
||||
#endif
|
||||
{ " NONE ", NONE },
|
||||
};
|
||||
struct InitSequenceDesc components_init[] =
|
||||
{
|
||||
#ifdef CONNECTION_AT_SAL_USING_TLS
|
||||
{"sal_mbedtls_proto", sal_mbedtls_proto_init},
|
||||
#endif
|
||||
#ifdef FS_VFS_FATFS
|
||||
{ "fatfs", FatfsInit },
|
||||
#endif
|
||||
#ifdef FS_CH376
|
||||
{ "ch376", Ch376fsInit },
|
||||
#endif
|
||||
{ "libc_system", LibcSystemInit },
|
||||
#ifdef CONNECTION_AT_OS_USING_SAL
|
||||
// { "sal_init", sal_init },
|
||||
#endif
|
||||
#ifdef RTC_SYNC_USING_NTP
|
||||
{ "rtc_ntp_sync",RtcNtpSyncInit},
|
||||
#endif
|
||||
{ " NONE ", NONE },
|
||||
};
|
||||
struct InitSequenceDesc env_init[] =
|
||||
{
|
||||
#ifdef ARCH_RISCV
|
||||
#if defined (RESOURCES_SPI_SD)|| defined(RESOURCES_SDIO )
|
||||
{ "MountSDCard", MountSDCard },
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FS_VFS_MNTTABLE
|
||||
{ "dfs_mount_table", dfs_mount_table },
|
||||
#endif
|
||||
#ifdef TOOL_SHELL
|
||||
{ "letter-shell system", userShellInit },
|
||||
#endif
|
||||
{ " NONE ", NONE },
|
||||
};
|
||||
struct InitSequenceDesc communication_init[] =
|
||||
{
|
||||
// #ifdef BSP_USING_SDIO
|
||||
// { "stm32_sdcard_mount",stm32_sdcard_mount },
|
||||
// #endif
|
||||
#ifdef BSP_USING_USBH
|
||||
{ "STM32USBHostRegister", STM32USBHostRegister },
|
||||
{ "hw usb", Stm32HwUsbInit },
|
||||
#endif
|
||||
{ " NONE ", NONE },
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will init sub components
|
||||
* @parm sub_components components type
|
||||
*
|
||||
*/
|
||||
void _InitSubCmpts(struct InitSequenceDesc sub_cmpts[])
|
||||
{
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
for( i = 0; sub_cmpts[i].fn != NONE; i++ ) {
|
||||
ret = sub_cmpts[i].fn();
|
||||
KPrintf("initialize %s %s\n",sub_cmpts[i].fn_name, ret == 0 ? "success" : "failed");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef KERNEL_COMPONENTS_INIT
|
||||
void EnvInitKTask(void *parameter)
|
||||
{
|
||||
x_base lock = 0;
|
||||
lock = DISABLE_INTERRUPT();
|
||||
_InitSubCmpts(prev_cmpts_init);
|
||||
_InitSubCmpts(device_init);
|
||||
_InitSubCmpts(components_init);
|
||||
_InitSubCmpts(env_init);
|
||||
ENABLE_INTERRUPT(lock);
|
||||
|
||||
_InitSubCmpts(communication_init);
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
StartupSecondaryCpu();
|
||||
#endif
|
||||
|
||||
#ifdef USER_APPLICATION
|
||||
#ifdef SEPARATE_COMPILE
|
||||
if(InitUserspace() == EOK) {
|
||||
CreateMainTask();
|
||||
}
|
||||
#else
|
||||
CreateMainTask();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void CreateEnvInitTask(void)
|
||||
{
|
||||
int32 env_init = 0;
|
||||
|
||||
env_init = KTaskCreate("env_init", EnvInitKTask, NONE,
|
||||
ENV_INIT_KTASK_STACK_SIZE, KTASK_PRIORITY_MAX - 1);
|
||||
if(env_init < 0) {
|
||||
KPrintf("env_init create failed ...%s %d.\n",__FUNCTION__,__LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
StartupKTask(env_init);
|
||||
}
|
||||
#endif /* KERNEL_COMPONENTS_INIT */
|
||||
|
||||
|
||||
/**
|
||||
* kernel startup function
|
||||
*
|
||||
*
|
||||
*/
|
||||
int XiUOSStartup(void)
|
||||
{
|
||||
DISABLE_INTERRUPT();
|
||||
|
||||
#ifdef KERNEL_QUEUEMANAGE
|
||||
queuemanager_done_register();
|
||||
#endif
|
||||
|
||||
#ifdef KERNEL_BANNER
|
||||
ShowBanner();
|
||||
#endif
|
||||
|
||||
SysInitOsAssign();
|
||||
|
||||
CreateKServiceKTask();
|
||||
|
||||
#ifdef KERNEL_COMPONENTS_INIT
|
||||
CreateEnvInitTask();
|
||||
#else
|
||||
|
||||
#ifdef TOOL_SHELL
|
||||
extern int userShellInit(void);
|
||||
userShellInit();
|
||||
#endif
|
||||
|
||||
#ifdef USER_APPLICATION
|
||||
extern void CreateMainTask(void);
|
||||
#ifdef SEPARATE_COMPILE
|
||||
extern int InitUserspace(void);
|
||||
|
||||
if(InitUserspace() == EOK) {
|
||||
CreateMainTask();
|
||||
}
|
||||
#else
|
||||
CreateMainTask();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
HwLockSpinlock(&AssignSpinLock);
|
||||
#endif
|
||||
|
||||
StartupOsAssign();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* system entry */
|
||||
int entry(void)
|
||||
{
|
||||
DISABLE_INTERRUPT();
|
||||
|
||||
/* system irq table must be inited before initialization of Hardware irq */
|
||||
SysInitIsrManager();
|
||||
|
||||
InitBoardHardware();
|
||||
XiUOSStartup();
|
||||
return 0;
|
||||
}
|
||||
218
kernel/thread/isr.c
Normal file
218
kernel/thread/isr.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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: isr.c
|
||||
* @brief: the general management of system isr
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <xs_hook.h>
|
||||
|
||||
struct InterruptServiceRoutines isrManager = { 0} ;
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
extern int GetCpuId(void);
|
||||
#endif
|
||||
/**
|
||||
* This functionwill get the isr nest level.
|
||||
*
|
||||
* @return isr nest level
|
||||
*/
|
||||
uint16 GetIsrCounter()
|
||||
{
|
||||
uint16 ret = 0;
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
ret = isrManager.isr_count[GetCpuId()];
|
||||
#else
|
||||
ret = isrManager.isr_count;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void incIsrCounter()
|
||||
{
|
||||
#ifdef ARCH_SMP
|
||||
isrManager.isr_count[GetCpuId()] ++ ;
|
||||
#else
|
||||
isrManager.isr_count ++;
|
||||
#endif
|
||||
return ;
|
||||
}
|
||||
|
||||
void decIsrCounter()
|
||||
{
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
isrManager.isr_count[GetCpuId()] -- ;
|
||||
#else
|
||||
isrManager.isr_count --;
|
||||
#endif
|
||||
return ;
|
||||
}
|
||||
|
||||
x_bool Is_InIsr()
|
||||
{
|
||||
#ifdef ARCH_SMP
|
||||
return ( isrManager.isr_count[GetCpuId()] != 0 ? RET_TRUE : RET_FALSE ) ;
|
||||
#else
|
||||
return ( isrManager.isr_count != 0 ? RET_TRUE : RET_FALSE ) ;
|
||||
#endif
|
||||
|
||||
}
|
||||
/**
|
||||
* This function will register a new irq.
|
||||
*
|
||||
* @param irq_num the number of the irq
|
||||
* @param handler the callback of the interrupt
|
||||
* @param arg param of thge callback
|
||||
*
|
||||
* @return EOK on success; ERROR on failure
|
||||
*/
|
||||
int32 RegisterHwIrq(uint32 irq_num, IsrHandlerType handler, void *arg)
|
||||
{
|
||||
if (irq_num >= ARCH_MAX_IRQ_NUM )
|
||||
return -ERROR;
|
||||
|
||||
struct IrqDesc *desc = &isrManager.irq_table[irq_num];
|
||||
|
||||
desc->handler = handler;
|
||||
desc->param = arg;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
/**
|
||||
* This function will free a irq.
|
||||
*
|
||||
* @param irq_num the number of the irq
|
||||
*
|
||||
* @return EOK on success; ERROR on failure
|
||||
*/
|
||||
int32 FreeHwIrq(uint32 irq_num)
|
||||
{
|
||||
if (irq_num >= ARCH_MAX_IRQ_NUM )
|
||||
return -ERROR;
|
||||
|
||||
memset(&isrManager.irq_table[irq_num], 0, sizeof(struct IrqDesc));
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will enable a irq.
|
||||
*
|
||||
* @param irq_num the number of the irq
|
||||
*
|
||||
* @return EOK on success; ERROR on failure
|
||||
*/
|
||||
int32 EnableHwIrq(uint32 irq_num)
|
||||
{
|
||||
if (irq_num >= ARCH_MAX_IRQ_NUM )
|
||||
return -ERROR;
|
||||
|
||||
return ArchEnableHwIrq(irq_num);
|
||||
}
|
||||
/**
|
||||
* This function will disable a irq.
|
||||
*
|
||||
* @param irq_num the number of the irq
|
||||
*
|
||||
* @return EOK on success; ERROR on failure
|
||||
*/
|
||||
|
||||
int32 DisableHwIrq(uint32 irq_num)
|
||||
{
|
||||
if (irq_num >= ARCH_MAX_IRQ_NUM )
|
||||
return -ERROR;
|
||||
|
||||
return ArchDisableHwIrq(irq_num);
|
||||
}
|
||||
|
||||
/* called from arch-specific ISR wrapper */
|
||||
void IsrCommon(uint32 irq_num)
|
||||
{
|
||||
struct IrqDesc *desc = &isrManager.irq_table[irq_num];
|
||||
|
||||
if (desc->handler == NONE) {
|
||||
SYS_KDEBUG_LOG(KDBG_IRQ, ("Spurious interrupt: IRQ No. %d\n", irq_num));
|
||||
while (1) {}
|
||||
}
|
||||
desc->handler(irq_num, desc->param);
|
||||
|
||||
}
|
||||
|
||||
void setIsrSwitchTrigerFlag()
|
||||
{
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
isrManager.isr_switch_trigger_flag[GetCpuId()] = 1;
|
||||
#else
|
||||
isrManager.isr_switch_trigger_flag = 1;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void clearIsrSwitchTrigerFlag()
|
||||
{
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
isrManager.isr_switch_trigger_flag[GetCpuId()] = 0;
|
||||
#else
|
||||
isrManager.isr_switch_trigger_flag = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 getIsrSwitchTrigerFlag()
|
||||
{
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
return isrManager.isr_switch_trigger_flag[GetCpuId()];
|
||||
#else
|
||||
return isrManager.isr_switch_trigger_flag ;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
struct IsrDone isrDone = {
|
||||
Is_InIsr,
|
||||
RegisterHwIrq ,
|
||||
FreeHwIrq,
|
||||
EnableHwIrq,
|
||||
DisableHwIrq,
|
||||
IsrCommon,
|
||||
GetIsrCounter,
|
||||
incIsrCounter,
|
||||
decIsrCounter,
|
||||
getIsrSwitchTrigerFlag,
|
||||
setIsrSwitchTrigerFlag,
|
||||
clearIsrSwitchTrigerFlag
|
||||
} ;
|
||||
|
||||
void SysInitIsrManager()
|
||||
{
|
||||
extern int __isrtbl_idx_start;
|
||||
extern int __isrtbl_start;
|
||||
extern int __isrtbl_end;
|
||||
memset(&isrManager,0,sizeof(struct InterruptServiceRoutines));
|
||||
isrManager.done = &isrDone;
|
||||
|
||||
uint32 *index = (uint32 *)&__isrtbl_idx_start;
|
||||
struct IrqDesc *desc = (struct IrqDesc *)&__isrtbl_start;
|
||||
|
||||
while (desc != (struct IrqDesc *)&__isrtbl_end)
|
||||
isrManager.irq_table[*index++] = *desc++;
|
||||
}
|
||||
46
kernel/thread/kservicetask.c
Normal file
46
kernel/thread/kservicetask.c
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
/*
|
||||
* 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: kservicetask.c
|
||||
* @brief: create service task for system
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
extern void ZombieTaskRecycleInit(void);
|
||||
extern void InitIdleKTask(void);
|
||||
void KSerciveKTaskIdle(void)
|
||||
{
|
||||
InitIdleKTask();
|
||||
}
|
||||
|
||||
void xz_KServiceKTaskRecycle()
|
||||
{
|
||||
ZombieTaskRecycleInit();
|
||||
}
|
||||
|
||||
void CreateKServiceKTask(void)
|
||||
{
|
||||
/* create zombie recycle task */
|
||||
xz_KServiceKTaskRecycle();
|
||||
|
||||
/* create idle task */
|
||||
KSerciveKTaskIdle();
|
||||
|
||||
}
|
||||
|
||||
1125
kernel/thread/ktask.c
Normal file
1125
kernel/thread/ktask.c
Normal file
File diff suppressed because it is too large
Load Diff
105
kernel/thread/ktask_stat.c
Normal file
105
kernel/thread/ktask_stat.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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: ktask_stat.c
|
||||
* @brief: the stat function definition of task
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef XS_KTASK_STAT_H
|
||||
#define XS_KTASK_STAT_H
|
||||
|
||||
#include <xs_kdbg.h>
|
||||
#include <xs_base.h>
|
||||
#include <xs_ktask.h>
|
||||
#include <stdbool.h>
|
||||
#include <xs_ktask_stat.h>
|
||||
|
||||
void KTaskStateSet(KTaskDescriptorType task, uint8 stat)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
task->task_dync_sched_member.stat = stat | (task->task_dync_sched_member.stat & ~KTASK_STAT_MASK);
|
||||
}
|
||||
|
||||
void KTaskStatSetAsInit(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
KTaskStateSet(task, KTASK_INIT);
|
||||
}
|
||||
|
||||
void KTaskStatSetAsReady(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
KTaskStateSet(task, KTASK_READY);
|
||||
}
|
||||
|
||||
void KTaskStatSetAsSuspend(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
KTaskStateSet(task, KTASK_SUSPEND);
|
||||
}
|
||||
|
||||
void KTaskStatSetAsRunning(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
KTaskStateSet(task, KTASK_RUNNING);
|
||||
}
|
||||
|
||||
void KTaskStatSetAsClose(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
KTaskStateSet(task, KTASK_CLOSE);
|
||||
}
|
||||
|
||||
uint8 KTaskStatGet(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
return task->task_dync_sched_member.stat & KTASK_STAT_MASK;
|
||||
}
|
||||
|
||||
bool JudgeKTaskStatIsInit(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
return ((task->task_dync_sched_member.stat & KTASK_STAT_MASK) == KTASK_INIT);
|
||||
}
|
||||
|
||||
bool JudgeKTaskStatIsReady(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
return ((task->task_dync_sched_member.stat & KTASK_STAT_MASK) == KTASK_READY);
|
||||
}
|
||||
|
||||
bool JudgeKTaskStatIsSuspend(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
return ((task->task_dync_sched_member.stat & KTASK_STAT_MASK) == KTASK_SUSPEND);
|
||||
}
|
||||
|
||||
bool JudgeKTaskStatIsRunning(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
return ((task->task_dync_sched_member.stat & KTASK_STAT_MASK) == KTASK_RUNNING);
|
||||
}
|
||||
|
||||
bool JudgeKTaskStatIsClose(KTaskDescriptorType task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
return ((task->task_dync_sched_member.stat & KTASK_STAT_MASK) == KTASK_CLOSE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
132
kernel/thread/linklist.c
Normal file
132
kernel/thread/linklist.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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: linklist.c
|
||||
* @brief: suspend and wakeup function of task
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
/**
|
||||
* a task will be suspended to a pend list
|
||||
*
|
||||
* @param list suspend task list
|
||||
* @param task the task descriptor need to be suspended
|
||||
* @param flag suspend flag
|
||||
*
|
||||
*/
|
||||
x_err_t LinklistSuspend(DoubleLinklistType *list,
|
||||
struct TaskDescriptor *task,
|
||||
uint8 flag)
|
||||
{
|
||||
int32 ret = EOK;
|
||||
x_ubase lock = 0;
|
||||
DoubleLinklistType *node = NONE;
|
||||
DoubleLinklistType *tail = NONE;
|
||||
struct TaskDescriptor *tmp_task = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(list);
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
SuspendKTask(task->id.id);
|
||||
switch (flag)
|
||||
{
|
||||
case LINKLIST_FLAG_FIFO:
|
||||
DoubleLinkListInsertNodeBefore(list, &(task->task_dync_sched_member.sched_link));
|
||||
break;
|
||||
|
||||
case LINKLIST_FLAG_PRIO:
|
||||
DOUBLE_LINKLIST_FOR_EACH(node,list)
|
||||
{
|
||||
tmp_task = SYS_DOUBLE_LINKLIST_ENTRY(node, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
||||
if (task->task_dync_sched_member.cur_prio < tmp_task->task_dync_sched_member.cur_prio)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node != list) {
|
||||
DoubleLinkListInsertNodeBefore(&(tmp_task->task_dync_sched_member.sched_link), &(task->task_dync_sched_member.sched_link));
|
||||
} else {
|
||||
tail = list->node_prev;
|
||||
DoubleLinkListInsertNodeAfter(tail,&(task->task_dync_sched_member.sched_link));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVALED;
|
||||
break;
|
||||
}
|
||||
CriticalAreaUnLock(lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* resume the first task in the suspend list
|
||||
*
|
||||
* @param list task list
|
||||
*
|
||||
*/
|
||||
x_err_t LinklistResume(DoubleLinklistType *list)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(list);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
task = SYS_DOUBLE_LINKLIST_ENTRY(list->node_next, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("resume task:%s\n", task->task_base_info.name));
|
||||
|
||||
KTaskWakeup(task->id.id);
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* wakeup all the task in the suspend list
|
||||
*
|
||||
* @param list task list
|
||||
*
|
||||
*/
|
||||
x_err_t LinklistResumeAll(DoubleLinklistType *list)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
DoubleLinklistType *node = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(list);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
for(;;) {
|
||||
node = list->node_next;
|
||||
if(node != list) {
|
||||
task = SYS_DOUBLE_LINKLIST_ENTRY(node, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
||||
task->exstatus = -ERROR;
|
||||
KTaskWakeup(task->id.id);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
110
kernel/thread/lock.c
Normal file
110
kernel/thread/lock.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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: lock.c
|
||||
* @brief: system spinlock file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xs_spinlock.h>
|
||||
#include <xiuos.h>
|
||||
#include <xs_assign.h>
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
struct Spin_Lockfileops spinlock;
|
||||
/*
|
||||
* lock scheduler
|
||||
*/
|
||||
static void DisablePreempt(void)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
lock = DisableLocalInterrupt();
|
||||
Assign.assign_lock[GetCpuId()] ++;
|
||||
EnableLocalInterrupt(lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* enable scheduler
|
||||
*/
|
||||
static void EnablePreempt(void)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
lock = DisableLocalInterrupt();
|
||||
Assign.assign_lock[GetCpuId()] --;
|
||||
DO_KTASK_ASSIGN;
|
||||
EnableLocalInterrupt(lock);
|
||||
}
|
||||
|
||||
void InitSpinLock( struct Spin_Lockfileops * spinlock)
|
||||
{
|
||||
InitHwSpinlock(&spinlock->node_lock.lock);
|
||||
spinlock->SPinLock = _SpinLock;
|
||||
spinlock->UnlockSpinLock =_UnlockSpinLock;
|
||||
spinlock->UnlockSpinLockIrqRestore = _UnlockSpinLockIrqRestore;
|
||||
spinlock->SpinLockIrqSave = _SpinLockIrqSave;
|
||||
|
||||
}
|
||||
|
||||
void _SpinLock(struct Spin_Lockfileops * spinlock)
|
||||
{
|
||||
DisablePreempt();
|
||||
HwLockSpinlock(&spinlock->node_lock.lock);
|
||||
}
|
||||
|
||||
void _UnlockSpinLock(struct Spin_Lockfileops * spinlock)
|
||||
{
|
||||
HwUnlockSpinlock(&spinlock->node_lock.lock);
|
||||
EnablePreempt();
|
||||
}
|
||||
|
||||
x_base _SpinLockIrqSave(struct Spin_Lockfileops * spinlock)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
DisablePreempt();
|
||||
|
||||
lock = DisableLocalInterrupt();
|
||||
HwLockSpinlock(&spinlock->node_lock.lock);
|
||||
|
||||
return lock;
|
||||
}
|
||||
|
||||
void _UnlockSpinLockIrqRestore(struct Spin_Lockfileops * spinlock, x_base lock)
|
||||
{
|
||||
HwUnlockSpinlock(&spinlock->node_lock.lock);
|
||||
EnableLocalInterrupt(lock);
|
||||
|
||||
EnablePreempt();
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* This function will restore the scheduler lock status
|
||||
*
|
||||
*/
|
||||
void RestoreCpusLockStatus(struct TaskDescriptor *task)
|
||||
{
|
||||
#ifdef ARCH_SMP
|
||||
Assign.smp_os_running_task[GetCpuId()] = task;
|
||||
HwUnlockSpinlock(&AssignSpinLock);
|
||||
#else
|
||||
Assign.os_running_task = task;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
496
kernel/thread/msgqueue.c
Normal file
496
kernel/thread/msgqueue.c
Normal file
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* 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: msgqueue.c
|
||||
* @brief: msgqueue file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <xs_delay.h>
|
||||
|
||||
DECLARE_ID_MANAGER(k_mq_id_manager, ID_NUM_MAX);
|
||||
DoubleLinklistType k_mq_list = {&k_mq_list, &k_mq_list};
|
||||
|
||||
struct mq_message
|
||||
{
|
||||
struct mq_message *next;
|
||||
};
|
||||
|
||||
static struct MsgQueue *GetMsgQueueById(int32 id)
|
||||
{
|
||||
x_base lock = 0;
|
||||
struct MsgQueue *mq = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
if (id < 0 )
|
||||
return NONE;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_mq_id_manager, id);
|
||||
if (idnode == NONE){
|
||||
CriticalAreaUnLock(lock);
|
||||
return NONE;
|
||||
}
|
||||
mq = CONTAINER_OF(idnode, struct MsgQueue, id);
|
||||
CriticalAreaUnLock(lock);
|
||||
return mq;
|
||||
}
|
||||
|
||||
static x_err_t _InitMsgQueue( struct MsgQueue *mq ,x_size_t msg_size,
|
||||
x_size_t max_msgs )
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
|
||||
mq->max_msgs = max_msgs;
|
||||
mq->num_msgs = 0;
|
||||
mq->each_len = ALIGN_MEN_UP(msg_size, MEM_ALIGN_SIZE);
|
||||
mq->index = 0;
|
||||
|
||||
InitDoubleLinkList(&mq->send_pend_list);
|
||||
InitDoubleLinkList(&(mq->recv_pend_list));
|
||||
|
||||
mq->msg_buf = x_malloc( mq->each_len * mq->max_msgs);
|
||||
if (mq->msg_buf == NONE) {
|
||||
lock = CriticalAreaLock();
|
||||
DoubleLinkListRmNode(&(mq->link));
|
||||
CriticalAreaUnLock(lock);
|
||||
KERNEL_FREE(mq);
|
||||
return -ENOMEMORY;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _MsgQueueSend(struct MsgQueue *mq,
|
||||
const void *buffer,
|
||||
x_size_t size,
|
||||
int32 msec)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
uint32 tick_delta = 0;
|
||||
int32 timeout = 0;
|
||||
uint8 *msg = NONE;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
NULL_PARAM_CHECK(buffer);
|
||||
|
||||
if (size > mq->each_len)
|
||||
return -ERROR;
|
||||
|
||||
tick_delta = 0;
|
||||
task = GetKTaskDescriptor();
|
||||
timeout = CalculteTickFromTimeMs(msec);
|
||||
lock = CriticalAreaLock();
|
||||
if (mq->num_msgs >= mq->max_msgs && timeout == 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -EFULL;
|
||||
}
|
||||
|
||||
while(mq->num_msgs >= mq->max_msgs ) {
|
||||
|
||||
task->exstatus = EOK;
|
||||
if (timeout == 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -EFULL;
|
||||
}
|
||||
KDEBUG_IN_KTASK_CONTEXT;
|
||||
LinklistSuspend(&(mq->send_pend_list), task, LINKLIST_FLAG_FIFO);
|
||||
|
||||
if (timeout > 0) {
|
||||
tick_delta = CurrentTicksGain();
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("mq_send_wait: start timer of task:%s\n",
|
||||
task->task_base_info.name));
|
||||
KTaskSetDelay(task,timeout);
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
if (task->exstatus != EOK) {
|
||||
return task->exstatus;
|
||||
}
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
if (timeout > 0) {
|
||||
tick_delta = CurrentTicksGain() - tick_delta;
|
||||
timeout -= tick_delta;
|
||||
if (timeout < 0)
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
msg = mq->msg_buf + ( ( mq->index + mq->num_msgs ) % mq->max_msgs ) * mq->each_len ;
|
||||
memcpy(msg, buffer, size);
|
||||
mq->num_msgs ++;
|
||||
if (!IsDoubleLinkListEmpty(&mq->recv_pend_list)) {
|
||||
LinklistResume(&(mq->recv_pend_list));
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _MsgQueueUrgentSend(struct MsgQueue *mq, const void *buffer, x_size_t size)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
uint8 *msg = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
NULL_PARAM_CHECK(buffer);
|
||||
|
||||
if (size > mq->each_len)
|
||||
return -ERROR;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
if (mq->num_msgs >= mq->max_msgs) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -EFULL;
|
||||
}
|
||||
|
||||
mq->index --;
|
||||
if (mq->index < 0)
|
||||
mq->index += mq->max_msgs;
|
||||
|
||||
msg = mq->msg_buf + ( ( mq->index + mq->num_msgs ) % mq->max_msgs ) * mq->each_len ;
|
||||
memcpy(msg , buffer, size);
|
||||
mq->num_msgs ++;
|
||||
if (!IsDoubleLinkListEmpty(&mq->send_pend_list)) {
|
||||
LinklistResume(&(mq->send_pend_list));
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _MsgQueueRecv(struct MsgQueue *mq,
|
||||
void *buffer,
|
||||
x_size_t size,
|
||||
int32 msec)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
uint32 tick_delta = 0;
|
||||
int32 timeout = 0;
|
||||
struct mq_message *msg = NONE;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
NULL_PARAM_CHECK(buffer);
|
||||
|
||||
tick_delta = 0;
|
||||
task = GetKTaskDescriptor();
|
||||
timeout = CalculteTickFromTimeMs(msec);
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
if (mq->index == 0 && timeout == 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ETIMEOUT;
|
||||
}
|
||||
|
||||
for( ; mq->num_msgs <= 0 ; ) {
|
||||
KDEBUG_IN_KTASK_CONTEXT;
|
||||
|
||||
task->exstatus = EOK;
|
||||
if (timeout == 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
task->exstatus = -ETIMEOUT;
|
||||
return -ETIMEOUT;
|
||||
}
|
||||
|
||||
LinklistSuspend(&(mq->recv_pend_list),
|
||||
task,
|
||||
LINKLIST_FLAG_FIFO);
|
||||
|
||||
if (timeout > 0) {
|
||||
tick_delta = CurrentTicksGain();
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("set task:%s to timer list\n",
|
||||
task->task_base_info.name));
|
||||
KTaskSetDelay(task,timeout);
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
if (task->exstatus != EOK) {
|
||||
return task->exstatus;
|
||||
}
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
if (timeout > 0) {
|
||||
tick_delta = CurrentTicksGain() - tick_delta;
|
||||
timeout -= tick_delta;
|
||||
if (timeout < 0)
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
msg = mq->msg_buf + mq->index * mq->each_len;
|
||||
mq->index = (mq->index + 1) % mq->max_msgs;
|
||||
memcpy(buffer, msg , size > mq->each_len ? mq->each_len : size);
|
||||
mq->num_msgs --;
|
||||
|
||||
if (!IsDoubleLinkListEmpty(&(mq->send_pend_list))) {
|
||||
LinklistResume(&(mq->send_pend_list));
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
DO_KTASK_ASSIGN;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _MsgQueueReinit(struct MsgQueue *mq)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
LinklistResumeAll(&mq->send_pend_list);
|
||||
LinklistResumeAll(&(mq->recv_pend_list));
|
||||
mq->index = 0;
|
||||
mq->num_msgs = 0;
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _DeleteMsgQueue(struct MsgQueue *mq)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
|
||||
LinklistResumeAll(&(mq->send_pend_list));
|
||||
LinklistResumeAll(&(mq->recv_pend_list));
|
||||
KERNEL_FREE(mq->msg_buf);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
DoubleLinkListRmNode(&(mq->link));
|
||||
CriticalAreaUnLock(lock);
|
||||
KERNEL_FREE(mq);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static struct MsgQueueDone Done = {
|
||||
.init = _InitMsgQueue ,
|
||||
.urgensend = _MsgQueueUrgentSend,
|
||||
.send = _MsgQueueSend,
|
||||
.recv = _MsgQueueRecv,
|
||||
.reinit = _MsgQueueReinit,
|
||||
.Delete = _DeleteMsgQueue
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will create a msg queue.
|
||||
*
|
||||
* @param msg_size the length of the msg queue.
|
||||
* @param max_msgs the max length of the msg queue.
|
||||
*
|
||||
* @return id on success;ENOMEMORY/ERROR on failure
|
||||
*/
|
||||
int32 KCreateMsgQueue(x_size_t msg_size,
|
||||
x_size_t max_msgs)
|
||||
{
|
||||
int32 id = 0;
|
||||
x_base temp = 0;
|
||||
x_base lock = 0;
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
mq = (struct MsgQueue *)x_malloc(sizeof(struct MsgQueue));
|
||||
if (mq == NONE)
|
||||
return -ENOMEMORY;
|
||||
memset(mq,0x0,sizeof(struct MsgQueue));
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
id = IdInsertObj(&k_mq_id_manager, &mq->id);
|
||||
CriticalAreaUnLock(lock);
|
||||
if (id < 0) {
|
||||
x_free(mq);
|
||||
return -ENOMEMORY;
|
||||
}
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
DoubleLinkListInsertNodeAfter(&k_mq_list, &mq->link);
|
||||
CriticalAreaUnLock(lock);
|
||||
mq->Done = &Done;
|
||||
if( mq->Done->init(mq, msg_size,max_msgs) == EOK )
|
||||
return mq->id.id;
|
||||
else
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will reset a event.
|
||||
*
|
||||
* @param id the id number of event.
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*/
|
||||
x_err_t KMsgQueueReinit(int32 id)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->reinit(mq);
|
||||
else
|
||||
return -EINVALED;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* receive message with some waiting time
|
||||
*
|
||||
* @param id the message id
|
||||
* @param buffer message info
|
||||
* @param size the size of buffer
|
||||
* @param timeout time needed waiting
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KMsgQueueRecv(int32 id,
|
||||
void *buffer,
|
||||
x_size_t size,
|
||||
int32 timeout)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->recv(mq,buffer,size,timeout);
|
||||
else
|
||||
return -EINVALED;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* a dynamic messagequeue will be deleted from the manage list
|
||||
*
|
||||
* @param id the message id
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KDeleteMsgQueue(int32 id)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->Delete(mq);
|
||||
else
|
||||
return -EINVALED;
|
||||
}
|
||||
|
||||
/**
|
||||
* send urgent message without waiting time, this message will be inserted to the head of the queue
|
||||
*
|
||||
* @param id the message id
|
||||
* @param buffer message info
|
||||
* @param size the size of buffer
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KMsgQueueUrgentSend(int32 id, const void *buffer, x_size_t size)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->urgensend(mq,buffer,size);
|
||||
else
|
||||
return -EINVALED;
|
||||
}
|
||||
|
||||
/**
|
||||
* send message without waiting time,current suspend task will be resumed
|
||||
*
|
||||
* @param id the message id
|
||||
* @param buffer message info
|
||||
* @param size the size of buffer
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KMsgQueueSend(int32 id, const void *buffer, x_size_t size)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->send(mq,buffer,size,0);
|
||||
else
|
||||
return -EINVALED;
|
||||
}
|
||||
/**
|
||||
* send message with waiting time,current suspend task will be resumed
|
||||
*
|
||||
* @param id the message id
|
||||
* @param buffer message info
|
||||
* @param size the size of buffer
|
||||
* @param timeout waiting time
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KMsgQueueSendwait(int32 id, const void *buffer, x_size_t size,int32 timeout)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->send(mq,buffer,size,timeout);
|
||||
else
|
||||
return -EINVALED;
|
||||
}
|
||||
315
kernel/thread/mutex.c
Normal file
315
kernel/thread/mutex.c
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* 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: mutex.c
|
||||
* @brief: mutex file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
DECLARE_ID_MANAGER(k_mutex_id_manager, ID_NUM_MAX);
|
||||
DoubleLinklistType k_mutex_list ={&k_mutex_list, &k_mutex_list}; ///< global mutex manage list
|
||||
|
||||
static int32 _MutexCreate()
|
||||
{
|
||||
int32 id = 0;
|
||||
x_base lock = 0;
|
||||
struct Mutex *mutex = NONE;
|
||||
|
||||
mutex = x_malloc(sizeof(struct Mutex));
|
||||
if (mutex == NONE) {
|
||||
return -ENOMEMORY;
|
||||
}
|
||||
|
||||
memset(mutex, 0x0, sizeof(struct Mutex));
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
id = IdInsertObj(&k_mutex_id_manager, &mutex->id);
|
||||
if (id < 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
x_free(mutex);
|
||||
return -ENOMEMORY;
|
||||
}
|
||||
|
||||
InitDoubleLinkList(&mutex->pend_list);
|
||||
|
||||
mutex->val = 1;
|
||||
mutex->holder = NONE;
|
||||
mutex->origin_prio = 0xFF;
|
||||
mutex->recursive_cnt = 0;
|
||||
|
||||
DoubleLinkListInsertNodeAfter(&k_mutex_list, &mutex->link);
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void _MutexDelete(struct Mutex *mutex)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(mutex);
|
||||
|
||||
LinklistResumeAll(&mutex->pend_list);
|
||||
lock = CriticalAreaLock();
|
||||
IdRemoveObj(&k_mutex_id_manager, mutex->id.id);
|
||||
|
||||
DoubleLinkListRmNode(&(mutex->link));
|
||||
CriticalAreaUnLock(lock);
|
||||
x_free(mutex);
|
||||
}
|
||||
|
||||
static int32 _MutexObtain(struct Mutex *mutex, int32 msec)
|
||||
{
|
||||
x_base lock = 0;
|
||||
int32 wait_time = 0;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(mutex);
|
||||
|
||||
task = GetKTaskDescriptor();
|
||||
wait_time = CalculteTickFromTimeMs(msec);
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_IPC,
|
||||
("mutex_take: current task %s, mutex value: %d, hold: %d\n",
|
||||
task->task_base_info.name, mutex->val, mutex->recursive_cnt));
|
||||
|
||||
task->exstatus = EOK;
|
||||
|
||||
if (mutex->holder == task) {
|
||||
mutex->recursive_cnt++;
|
||||
} else {
|
||||
if (mutex->val > 0) {
|
||||
mutex->val--;
|
||||
mutex->holder = task;
|
||||
mutex->origin_prio = task->task_dync_sched_member.cur_prio;
|
||||
mutex->recursive_cnt++;
|
||||
} else {
|
||||
if (wait_time == 0) {
|
||||
task->exstatus = -ETIMEOUT;
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ETIMEOUT;
|
||||
} else {
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("mutex_take: suspend task: %s\n",
|
||||
task->task_base_info.name));
|
||||
|
||||
if (task->task_dync_sched_member.cur_prio > mutex->holder->task_dync_sched_member.cur_prio)
|
||||
{
|
||||
KTaskPrioSet(mutex->holder->id.id, task->task_dync_sched_member.cur_prio);
|
||||
}
|
||||
|
||||
LinklistSuspend(&(mutex->pend_list), task, LINKLIST_FLAG_PRIO);
|
||||
|
||||
if (wait_time > 0) {
|
||||
SYS_KDEBUG_LOG(KDBG_IPC,
|
||||
("mutex_take: start the timer of task:%s\n",
|
||||
task->task_base_info.name));
|
||||
KTaskSetDelay(task,wait_time);
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
if (task->exstatus != EOK) {
|
||||
return task->exstatus;
|
||||
} else {
|
||||
lock = CriticalAreaLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int32 _MutexAbandon(struct Mutex *mutex)
|
||||
{
|
||||
int resched = 0;
|
||||
x_base lock = 0;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(mutex);
|
||||
|
||||
task = GetKTaskDescriptor();
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_IPC,
|
||||
("mutex_release:current task %s, mutex value: %d, hold: %d\n",
|
||||
task->task_base_info.name, mutex->val, mutex->recursive_cnt));
|
||||
|
||||
if (task != mutex->holder) {
|
||||
task->exstatus = -ERROR;
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
mutex->recursive_cnt --;
|
||||
if (mutex->recursive_cnt == 0) {
|
||||
if (mutex->origin_prio != mutex->holder->task_dync_sched_member.cur_prio)
|
||||
{
|
||||
KTaskPrioSet(mutex->holder->id.id, mutex->origin_prio);
|
||||
}
|
||||
|
||||
if (!IsDoubleLinkListEmpty(&mutex->pend_list)) {
|
||||
task = SYS_DOUBLE_LINKLIST_ENTRY(mutex->pend_list.node_next, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("mutex_release: resume task: %s\n",
|
||||
task->task_base_info.name));
|
||||
|
||||
mutex->holder = task;
|
||||
mutex->origin_prio = task->task_dync_sched_member.cur_prio;
|
||||
mutex->recursive_cnt++;
|
||||
|
||||
LinklistResume(&(mutex->pend_list));
|
||||
|
||||
resched = RET_TRUE;
|
||||
} else {
|
||||
mutex->val++;
|
||||
mutex->holder = NONE;
|
||||
mutex->origin_prio = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
if (resched == RET_TRUE)
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static MutexDoneType done = {
|
||||
.MutexCreate = _MutexCreate,
|
||||
.MutexDelete = _MutexDelete,
|
||||
.MutexObtain = _MutexObtain,
|
||||
.MutexAbandon = _MutexAbandon,
|
||||
};
|
||||
|
||||
/**
|
||||
* a mutex will be inited in static way,then this mutex will be inserted to the manage list
|
||||
*
|
||||
* @param mutex the mutex descriptor
|
||||
* @param name mutex name
|
||||
* @param flag mutex flag
|
||||
*
|
||||
* @return EOK on success
|
||||
*
|
||||
*/
|
||||
int32 KMutexCreate()
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
return done.MutexCreate();
|
||||
}
|
||||
|
||||
/**
|
||||
* a dynamic mutex will be deleted from the manage list
|
||||
*
|
||||
* @param mutex mutex descriptor
|
||||
*
|
||||
*/
|
||||
void KMutexDelete(int32 id)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
x_base lock = 0;
|
||||
struct Mutex *mutex = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_mutex_id_manager, id);
|
||||
if (idnode == NONE) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex =CONTAINER_OF(idnode, struct Mutex, id);
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
done.MutexDelete(mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* a mutex will be taken when mutex is available
|
||||
*
|
||||
* @param mutex mutex descriptor
|
||||
* @param msec the time needed waiting
|
||||
*
|
||||
* @return EOK on success;ERROR on failure
|
||||
*
|
||||
*/
|
||||
int32 KMutexObtain(int32 id, int32 msec)
|
||||
{
|
||||
KDEBUG_IN_KTASK_CONTEXT;
|
||||
|
||||
x_base lock = 0;
|
||||
struct Mutex *mutex = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -ERROR;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_mutex_id_manager, id);
|
||||
if (idnode == NONE){
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
|
||||
mutex =CONTAINER_OF(idnode, struct Mutex, id);
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return done.MutexObtain(mutex, msec);
|
||||
}
|
||||
|
||||
/**
|
||||
* release the mutex and resume corresponding suspended task
|
||||
*
|
||||
* @param mutex mutex descriptor
|
||||
*
|
||||
* @return EOK on success;ERROR on failure
|
||||
*/
|
||||
int32 KMutexAbandon(int32 id)
|
||||
{
|
||||
KDEBUG_IN_KTASK_CONTEXT;
|
||||
|
||||
x_base lock = 0;
|
||||
struct Mutex *mutex = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -ERROR;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_mutex_id_manager, id);
|
||||
if (idnode == NONE) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
mutex = CONTAINER_OF(idnode, struct Mutex, id);
|
||||
CriticalAreaUnLock(lock);
|
||||
return done.MutexAbandon(mutex);
|
||||
}
|
||||
56
kernel/thread/queue_manager.c
Normal file
56
kernel/thread/queue_manager.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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: queue_manager.c
|
||||
* @brief: Unified management of queue
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xs_queue_manager.h>
|
||||
#include <xs_dataqueue.h>
|
||||
#include <xs_workqueue.h>
|
||||
#include <xs_waitqueue.h>
|
||||
|
||||
#include <xs_memory.h>
|
||||
|
||||
void* g_queue_done[QUEUE_MAX];
|
||||
|
||||
void queuemanager_done_register()
|
||||
{
|
||||
DataQueueDoneType* pdata_queue_done = (DataQueueDoneType*)x_malloc(sizeof(DataQueueDoneType));
|
||||
pdata_queue_done->InitDataqueue = InitDataqueue;
|
||||
pdata_queue_done->PushDataqueue = PushDataqueue;
|
||||
pdata_queue_done->PopDataqueue = PopDataqueue;
|
||||
pdata_queue_done->DataqueuePeak = DataqueuePeak;
|
||||
pdata_queue_done->DeInitDataqueue = DeInitDataqueue;
|
||||
|
||||
WorkQueueDoneType* pwork_queue_done = (WorkQueueDoneType*)x_malloc(sizeof(WorkQueueDoneType));
|
||||
pwork_queue_done->CreateWorkQueue = CreateWorkQueue;
|
||||
pwork_queue_done->WorkInit = WorkInit;
|
||||
pwork_queue_done->WorkSubmit = WorkSubmit;
|
||||
pwork_queue_done->WorkSubmit_immediate = WorkSubmit_immediate;
|
||||
|
||||
WaitQueueDoneType* pwait_queue_done = (WaitQueueDoneType*)x_malloc(sizeof(WaitQueueDoneType));
|
||||
pwait_queue_done->InitWqueue = InitWqueue;
|
||||
pwait_queue_done->WqueueAdd = WqueueAdd;
|
||||
pwait_queue_done->WqueueRemove = WqueueRemove;
|
||||
pwait_queue_done->WqueueWait = WqueueWait;
|
||||
pwait_queue_done->WakeupWqueue = WakeupWqueue;
|
||||
|
||||
g_queue_done[DATA_QUEUE] = pdata_queue_done;
|
||||
g_queue_done[WORK_QUEUE] = pwork_queue_done;
|
||||
g_queue_done[WAIT_QUEUE] = pwait_queue_done;
|
||||
}
|
||||
327
kernel/thread/semaphore.c
Normal file
327
kernel/thread/semaphore.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* 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: semaphore.c
|
||||
* @brief: semaphore file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
#ifdef KDEBUG_NOT_IN_INTERRUPT
|
||||
#undef KDEBUG_NOT_IN_INTERRUPT
|
||||
#endif
|
||||
|
||||
#define KDEBUG_NOT_IN_INTERRUPT
|
||||
|
||||
DECLARE_ID_MANAGER(k_sem_id_manager, ID_NUM_MAX);
|
||||
DoubleLinklistType k_sem_list = {&k_sem_list, &k_sem_list};
|
||||
|
||||
static int32 _SemaphoreCreate(uint16 val)
|
||||
{
|
||||
int32 id = 0;
|
||||
x_base lock = 0;
|
||||
struct Semaphore *sem = NONE;
|
||||
|
||||
sem = (struct Semaphore *)x_malloc(sizeof(struct Semaphore));
|
||||
if (sem == NONE)
|
||||
return -ENOMEMORY;
|
||||
|
||||
memset(sem, 0, sizeof(struct Semaphore));
|
||||
lock = CriticalAreaLock();
|
||||
id = IdInsertObj(&k_sem_id_manager, &sem->id);
|
||||
if (id < 0) {
|
||||
x_free(sem);
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ENOMEMORY;
|
||||
}
|
||||
|
||||
sem->value = val;
|
||||
InitDoubleLinkList(&sem->pend_list);
|
||||
|
||||
|
||||
DoubleLinkListInsertNodeAfter(&k_sem_list, &sem->link);
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("created semaphore: id %d, value %d\n", id, (int)val));
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void _SemaphoreDelete(struct Semaphore *sem)
|
||||
{
|
||||
int resched = 0;
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(sem);
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("deleted semaphore: id %d\n", (int)sem->id.id));
|
||||
lock = CriticalAreaLock();
|
||||
if (!IsDoubleLinkListEmpty(&sem->pend_list)) {
|
||||
resched = 1;
|
||||
LinklistResumeAll(&sem->pend_list);
|
||||
}
|
||||
|
||||
IdRemoveObj(&k_sem_id_manager, sem->id.id);
|
||||
DoubleLinkListRmNode(&sem->link);
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
x_free(sem);
|
||||
|
||||
if (resched){
|
||||
DO_KTASK_ASSIGN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int32 _SemaphoreObtain(struct Semaphore *sem, int32 msec)
|
||||
{
|
||||
int lock = 0;
|
||||
int32 wait_time = 0;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(sem);
|
||||
|
||||
wait_time = CalculteTickFromTimeMs(msec);
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("obtain semaphore: id %d, value %d, by task %s\n",
|
||||
(int)sem->id.id, (int)sem->value, GetKTaskDescriptor()->task_base_info.name));
|
||||
|
||||
if (sem->value > 0) {
|
||||
sem->value--;
|
||||
CriticalAreaUnLock(lock);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
if (wait_time == 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ETIMEOUT;
|
||||
}
|
||||
|
||||
task = GetKTaskDescriptor();
|
||||
task->exstatus = EOK;
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("obtain semaphore: suspending task %s\n",
|
||||
GetKTaskDescriptor()->task_base_info.name));
|
||||
|
||||
LinklistSuspend(&sem->pend_list, task, LINKLIST_FLAG_PRIO);
|
||||
|
||||
if (wait_time > 0) {
|
||||
KTaskSetDelay(task, wait_time);
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
return task->exstatus;
|
||||
}
|
||||
|
||||
static int32 _SemaphoreAbandon(struct Semaphore *sem)
|
||||
{
|
||||
int lock = 0;
|
||||
int resched = 0;
|
||||
|
||||
NULL_PARAM_CHECK(sem);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("abandon semaphore: id %d, value %d, by task %s\n",
|
||||
(int)sem->id.id, (int)sem->value, GetKTaskDescriptor()->task_base_info.name));
|
||||
|
||||
if (!IsDoubleLinkListEmpty(&sem->pend_list)) {
|
||||
resched = 1;
|
||||
LinklistResume(&sem->pend_list);
|
||||
} else {
|
||||
sem->value++;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
if (resched){
|
||||
DO_KTASK_ASSIGN;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int32 _SemaphoreSetValue(struct Semaphore *sem, uint16 val)
|
||||
{
|
||||
int lock = 0;
|
||||
int resched = 0;
|
||||
|
||||
NULL_PARAM_CHECK(sem);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("set semaphore value: id %d, old value %d, new value %d, by task %s\n",
|
||||
(int)sem->id.id, (int)sem->value, (int)val, GetKTaskDescriptor()->task_base_info.name));
|
||||
|
||||
if (sem->value == val) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
if (!IsDoubleLinkListEmpty(&sem->pend_list)) {
|
||||
resched = 1;
|
||||
LinklistResumeAll(&sem->pend_list);
|
||||
}
|
||||
sem->value = val;
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
if (resched)
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static SemaphoreDoneType done = {
|
||||
.SemaphoreCreate = _SemaphoreCreate,
|
||||
.SemaphoreDelete = _SemaphoreDelete,
|
||||
.SemaphoreObtain = _SemaphoreObtain,
|
||||
.SemaphoreAbandon = _SemaphoreAbandon,
|
||||
.SemaphoreSetValue = _SemaphoreSetValue,
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new semaphore with specified initial value.
|
||||
*
|
||||
* @param val initial value
|
||||
* @return id of the semaphore
|
||||
*/
|
||||
int32 KSemaphoreCreate(uint16 val)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
return done.SemaphoreCreate(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a semaphore and wakeup all pending tasks on it.
|
||||
*
|
||||
* @param id id of the semaphore to be deleted
|
||||
*/
|
||||
void KSemaphoreDelete(int32 id)
|
||||
{
|
||||
x_base lock = 0;
|
||||
struct Semaphore *sem = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
if (id < 0)
|
||||
return;
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_sem_id_manager, id);
|
||||
if (idnode == NONE){
|
||||
CriticalAreaUnLock(lock);
|
||||
return;
|
||||
}
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
sem = CONTAINER_OF(idnode, struct Semaphore, id);
|
||||
done.SemaphoreDelete(sem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a semaphore when its value is greater than 0; pend on it otherwise.
|
||||
*
|
||||
* @param id id of the semaphore to be obtained
|
||||
* @param msec wait time in millisecond
|
||||
* @return EOK on success, error code on failure
|
||||
*/
|
||||
int32 KSemaphoreObtain(int32 id, int32 msec)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
x_base lock = 0;
|
||||
struct Semaphore *sem = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -ERROR;
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_sem_id_manager, id);
|
||||
if (idnode == NONE){
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
sem =CONTAINER_OF(idnode, struct Semaphore, id);
|
||||
CriticalAreaUnLock(lock);
|
||||
return done.SemaphoreObtain(sem, msec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abandon a semaphore and wakeup a pending task if any.
|
||||
*
|
||||
* @param id id of the semaphore to be abandoned
|
||||
* @return EOK on success, error code on failure
|
||||
*/
|
||||
int32 KSemaphoreAbandon(int32 id)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
x_base lock = 0;
|
||||
struct Semaphore *sem = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -ERROR;
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_sem_id_manager, id);
|
||||
if (idnode == NONE) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
sem =CONTAINER_OF(idnode, struct Semaphore, id);
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return done.SemaphoreAbandon(sem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a semaphore, wakeup all pending tasks if new value is positive.
|
||||
*
|
||||
* @param id id of the semaphore for which to set value
|
||||
* @param val new value
|
||||
* @return EOK on success, error code on failure
|
||||
*/
|
||||
int32 KSemaphoreSetValue(int32 id, uint16 val)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
x_base lock = 0;
|
||||
struct Semaphore *sem = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -ERROR;
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_sem_id_manager, id);
|
||||
if (idnode == NONE) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
sem = CONTAINER_OF(idnode, struct Semaphore, id);
|
||||
CriticalAreaUnLock(lock);
|
||||
return done.SemaphoreSetValue(sem, val);
|
||||
}
|
||||
142
kernel/thread/single_link.c
Normal file
142
kernel/thread/single_link.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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: single_link.c
|
||||
* @brief: functions definition of single linklist
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xs_klist.h>
|
||||
|
||||
/**
|
||||
* This function will init a linklist.
|
||||
*
|
||||
* @param linklist_head linklist node
|
||||
*/
|
||||
void InitSingleLinkList(SysSingleLinklistType *linklist)
|
||||
{
|
||||
linklist->node_next = NONE;
|
||||
}
|
||||
|
||||
void AppendSingleLinkList(SysSingleLinklistType *linklist, SysSingleLinklistType *linklist_node)
|
||||
{
|
||||
struct SingleLinklistNode *node;
|
||||
|
||||
node = linklist;
|
||||
while (node->node_next) node = node->node_next;
|
||||
|
||||
node->node_next = linklist_node;
|
||||
linklist_node->node_next = NONE;
|
||||
}
|
||||
/**
|
||||
* This function will insert a node into list after the node.
|
||||
*
|
||||
* @param linklist linklist node
|
||||
* @param linklist_node the node needed to inserted
|
||||
*/
|
||||
|
||||
void SingleLinkListNodeInsert(SysSingleLinklistType *linklist, SysSingleLinklistType *linklist_node)
|
||||
{
|
||||
linklist_node->node_next = linklist->node_next;
|
||||
linklist->node_next = linklist_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get length of the list.
|
||||
*
|
||||
* @param linklist list head
|
||||
* @return length
|
||||
*/
|
||||
|
||||
unsigned int SingleLinkListGetLen(const SysSingleLinklistType *linklist)
|
||||
{
|
||||
unsigned int length = 0;
|
||||
const SysSingleLinklistType *tmp_list = linklist->node_next;
|
||||
while (tmp_list != NONE)
|
||||
{
|
||||
tmp_list = tmp_list->node_next;
|
||||
length ++;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will remove a node from the list.
|
||||
*
|
||||
* @param linklist_node the node needed to removed
|
||||
*/
|
||||
|
||||
SysSingleLinklistType *SingleLinkListRmNode(SysSingleLinklistType *linklist, SysSingleLinklistType *linklist_node)
|
||||
{
|
||||
struct SingleLinklistNode *node = linklist;
|
||||
while (node->node_next && node->node_next != linklist_node) node = node->node_next;
|
||||
|
||||
if (node->node_next != (SysSingleLinklistType *)0){
|
||||
node->node_next = node->node_next->node_next;
|
||||
}
|
||||
|
||||
return linklist;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get the head of the list.
|
||||
*
|
||||
* @param linklist list head
|
||||
* @return list head
|
||||
*/
|
||||
SysSingleLinklistType *SingleLinkListGetFirstNode(SysSingleLinklistType *linklist)
|
||||
{
|
||||
return linklist->node_next;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get the tail node of the list.
|
||||
*
|
||||
* @param linklist list head
|
||||
* @return list taile node
|
||||
*/
|
||||
SysSingleLinklistType *SingleLinkListGetTailNode(SysSingleLinklistType *linklist)
|
||||
{
|
||||
while (linklist->node_next) linklist = linklist->node_next;
|
||||
|
||||
return linklist;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get the next node of the list head.
|
||||
*
|
||||
* @param linklist list head
|
||||
* @param linklist_node list head
|
||||
* @return next node of the list head
|
||||
*/
|
||||
|
||||
SysSingleLinklistType *SingleLinkListGetNextNode(SysSingleLinklistType *linklist_node)
|
||||
{
|
||||
return linklist_node->node_next;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will judge the list is empty.
|
||||
*
|
||||
* @param linklist the list head
|
||||
* @return true
|
||||
*/
|
||||
|
||||
int IsSingleLinkListEmpty(SysSingleLinklistType *linklist)
|
||||
{
|
||||
return linklist->node_next == NONE;
|
||||
}
|
||||
487
kernel/thread/smp_assign.c
Normal file
487
kernel/thread/smp_assign.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* 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: smp_assign.c
|
||||
* @brief: system scheduler of multiple cpu
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xs_isr.h>
|
||||
#include <xs_spinlock.h>
|
||||
#include <xs_ktask_stat.h>
|
||||
#include <xs_assign.h>
|
||||
#include <xs_hook.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct Assign Assign;
|
||||
HwSpinlock AssignSpinLock;
|
||||
|
||||
static struct PriorityReadyVectorDone ready_vector_done =
|
||||
{
|
||||
OsAssignReadyVectorInit,
|
||||
KTaskInsertToReadyVector,
|
||||
KTaskOsAssignRemoveKTask,
|
||||
};
|
||||
|
||||
static inline x_ubase SmpGetReadyVectorHighestPrio(void)
|
||||
{
|
||||
uint8 coreid = GetCpuId();
|
||||
|
||||
return ((Assign.os_assign_read_vector.highest_prio > Assign.smp_os_assign_ready_rector[coreid].highest_prio) ? Assign.os_assign_read_vector.highest_prio : Assign.smp_os_assign_ready_rector[coreid].highest_prio);
|
||||
}
|
||||
|
||||
/*
|
||||
* get target highest priority task in ready queue
|
||||
*/
|
||||
static inline struct TaskDescriptor* SmpAssignTargetTaskSelect(void)
|
||||
{
|
||||
|
||||
uint8 coreid = GetCpuId();
|
||||
|
||||
if (Assign.os_assign_read_vector.highest_prio > Assign.smp_os_assign_ready_rector[coreid].highest_prio)
|
||||
{
|
||||
return ChooseTaskWithHighestPrio(&Assign.os_assign_read_vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ChooseTaskWithHighestPrio(&Assign.smp_os_assign_ready_rector[coreid]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void SmpOsAssignSwtichToNewTask(struct TaskDescriptor* old_task, struct TaskDescriptor* new_task)
|
||||
{
|
||||
NULL_PARAM_CHECK(old_task);
|
||||
NULL_PARAM_CHECK(new_task);
|
||||
|
||||
Assign.ready_vector_done->remove(new_task);
|
||||
KTaskStatSetAsRunning(new_task);
|
||||
|
||||
#ifdef USING_OVERFLOW_CHECK
|
||||
_KTaskOsAssignStackCheck(new_task);
|
||||
#endif
|
||||
|
||||
SwitchKtaskContext((x_ubase)&old_task->stack_point, (x_ubase)&new_task->stack_point, new_task);
|
||||
}
|
||||
|
||||
static inline void SmpSwitchToFirstRunningTask(struct TaskDescriptor* task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
Assign.ready_vector_done->remove(task);
|
||||
KTaskStatSetAsRunning(task);
|
||||
|
||||
SwitchKtaskContextTo((x_ubase)&task->stack_point, task);
|
||||
|
||||
}
|
||||
|
||||
static inline void SetSystemRunningTask(struct TaskDescriptor* task)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
task->task_smp_info.runing_coreid = GetCpuId();
|
||||
}
|
||||
|
||||
static void SmpOsAssignInit(void)
|
||||
{
|
||||
int coreid = 0;
|
||||
while(coreid < CPU_NUMBERS) {
|
||||
Assign.ready_vector_done->init(&Assign.smp_os_assign_ready_rector[coreid]);
|
||||
Assign.smp_os_running_task[coreid] = NONE;
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
isrManager.isr_switch_trigger_flag[coreid] = 0;
|
||||
#else
|
||||
isrManager.isr_switch_trigger_flag = 0;
|
||||
#endif
|
||||
Assign.current_priority[coreid] = KTASK_PRIORITY_MAX - 1;
|
||||
Assign.assign_lock[coreid] = 0;
|
||||
coreid++;
|
||||
}
|
||||
}
|
||||
|
||||
struct smp_assign_done smp_assign_done =
|
||||
{
|
||||
SmpGetReadyVectorHighestPrio,
|
||||
SmpAssignTargetTaskSelect,
|
||||
SmpOsAssignSwtichToNewTask,
|
||||
SmpSwitchToFirstRunningTask,
|
||||
SetSystemRunningTask,
|
||||
SmpOsAssignInit,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* task schedule function.getting the highest priority task then switching to it
|
||||
*/
|
||||
void KTaskOsAssign(void)
|
||||
{
|
||||
x_base lock = 0;
|
||||
int coreid = 0;
|
||||
x_ubase highest_prio = 0;
|
||||
struct TaskDescriptor *new_task = NONE;
|
||||
struct TaskDescriptor *runningtask = NONE;
|
||||
|
||||
coreid = GetCpuId();
|
||||
if (isrManager.done->isInIsr()) {
|
||||
isrManager.done->setSwitchTrigerFlag();
|
||||
return;
|
||||
}
|
||||
|
||||
if(Assign.assign_lock[coreid] >= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
runningtask = Assign.smp_os_running_task[coreid];
|
||||
|
||||
/* if the bitmap is empty then do not switch */
|
||||
if((RET_TRUE == JudgeAssignReadyBitmapIsEmpty(&Assign.os_assign_read_vector)) &&
|
||||
(RET_TRUE == JudgeAssignReadyBitmapIsEmpty(&Assign.smp_os_assign_ready_rector[coreid]))) {
|
||||
return;
|
||||
}
|
||||
|
||||
highest_prio = Assign.smp_assign_done->GetHighest();
|
||||
new_task = Assign.smp_assign_done->select();
|
||||
|
||||
|
||||
if(RET_TRUE != JudgeKTaskStatIsRunning(runningtask)) {
|
||||
CHECK(NONE != new_task);
|
||||
goto SWITCH;
|
||||
}
|
||||
/* if the running task’ priority is the highest and this task is not be yield then do not switch */
|
||||
if(highest_prio < runningtask->task_dync_sched_member.cur_prio) {
|
||||
return;
|
||||
} else {
|
||||
Assign.ready_vector_done->insert(runningtask);
|
||||
}
|
||||
SWITCH:
|
||||
|
||||
new_task->task_smp_info.runing_coreid = coreid;
|
||||
Assign.current_priority[coreid] = (uint8)highest_prio;
|
||||
|
||||
HOOK(hook.assign.hook_Assign,(runningtask, new_task));
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED,
|
||||
("[%d]switch to priority#%d "
|
||||
"task:%.*s(sp:0x%08x), "
|
||||
"from task:%.*s(sp: 0x%08x)\n",
|
||||
isrManager.done->getCounter(), highest_prio,
|
||||
NAME_NUM_MAX, new_task->task_base_info.name, new_task->stack_point,
|
||||
NAME_NUM_MAX, runningtask->task_base_info.name, runningtask->stack_point));
|
||||
|
||||
Assign.smp_assign_done->SwitchToNew(runningtask,new_task);
|
||||
}
|
||||
|
||||
/**
|
||||
* task switch in IRQ context.
|
||||
*/
|
||||
void KTaskOsAssignDoIrqSwitch(void *context)
|
||||
{
|
||||
int coreid = 0;
|
||||
x_base lock = 0;
|
||||
x_ubase highest_priority = 0;
|
||||
struct TaskDescriptor *new_task = NONE;
|
||||
struct TaskDescriptor *runningtask = NONE;
|
||||
|
||||
coreid = GetCpuId();
|
||||
if ( isrManager.done->getSwitchTrigerFlag() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Assign.assign_lock[coreid] >= 1 || isrManager.done->getCounter() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
isrManager.done->clearSwitchTrigerFlag();
|
||||
|
||||
runningtask = Assign.smp_os_running_task[coreid];
|
||||
|
||||
if((RET_TRUE == JudgeAssignReadyBitmapIsEmpty(&Assign.os_assign_read_vector)) &&
|
||||
(RET_TRUE == JudgeAssignReadyBitmapIsEmpty(&Assign.smp_os_assign_ready_rector[coreid]))) {
|
||||
return;
|
||||
}
|
||||
|
||||
highest_priority = Assign.smp_assign_done->GetHighest();
|
||||
new_task = Assign.smp_assign_done->select();
|
||||
|
||||
if (RET_TRUE == JudgeKTaskStatIsRunning(runningtask)) {
|
||||
if (runningtask->task_dync_sched_member.cur_prio > highest_priority) {
|
||||
new_task = runningtask;
|
||||
} else {
|
||||
Assign.ready_vector_done->insert(runningtask);
|
||||
}
|
||||
}
|
||||
|
||||
new_task->task_smp_info.runing_coreid = coreid;
|
||||
if (new_task != runningtask) {
|
||||
Assign.current_priority[coreid] = (uint8)highest_priority;
|
||||
HOOK(hook.assign.hook_Assign, (runningtask, new_task));
|
||||
Assign.ready_vector_done->remove(new_task);
|
||||
KTaskStatSetAsRunning(new_task);
|
||||
|
||||
#ifdef KERNEL_STACK_OVERFLOW_CHECK
|
||||
_KTaskOsAssignStackCheck(new_task);
|
||||
#endif
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED, ("switch in interrupt\n"));
|
||||
|
||||
|
||||
HwInterruptcontextSwitch( (x_ubase)&runningtask->stack_point,
|
||||
(x_ubase)&new_task->stack_point, new_task, context);
|
||||
}
|
||||
}
|
||||
void KTaskOsAssignAfterIrq(void *context)
|
||||
{
|
||||
x_base lock = 0;
|
||||
lock = DISABLE_INTERRUPT();
|
||||
HwLockSpinlock(&AssignSpinLock);
|
||||
KTaskOsAssignDoIrqSwitch(context);
|
||||
HwUnlockSpinlock(&AssignSpinLock);
|
||||
ENABLE_INTERRUPT(lock);
|
||||
}
|
||||
|
||||
static void UncombineInsert(struct TaskDescriptor *task)
|
||||
{
|
||||
uint32 cpu_mask = 0;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
#if KTASK_PRIORITY_MAX > 32
|
||||
MERGE_FLAG(&Assign.os_assign_read_vector.ready_vector[task->task_dync_sched_member.bitmap_offset], task->task_dync_sched_member.bitmap_row);
|
||||
#endif
|
||||
MERGE_FLAG(&Assign.os_assign_read_vector.priority_ready_group, task->task_dync_sched_member.bitmap_column);
|
||||
AssignPolicyInsert(task, &Assign.os_assign_read_vector);
|
||||
cpu_mask = CPU_MASK ^ (1 << GetCpuId());
|
||||
HwSendIpi(ASSIGN_IPI, cpu_mask);
|
||||
}
|
||||
|
||||
static void ComnbineInsert(struct TaskDescriptor *task, int coreid)
|
||||
{
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
#if KTASK_PRIORITY_MAX > 32
|
||||
MERGE_FLAG(&Assign.smp_os_assign_ready_rector[coreid].ready_vector[task->task_dync_sched_member.bitmap_offset], task->task_dync_sched_member.bitmap_row);
|
||||
#endif
|
||||
MERGE_FLAG(&Assign.smp_os_assign_ready_rector[coreid].priority_ready_group, task->task_dync_sched_member.bitmap_column);
|
||||
AssignPolicyInsert(task, &Assign.smp_os_assign_ready_rector[coreid]);
|
||||
if (coreid != task->task_smp_info.combined_coreid)
|
||||
{
|
||||
uint32 cpu_mask;
|
||||
cpu_mask = 1 << task->task_smp_info.combined_coreid;
|
||||
HwSendIpi(ASSIGN_IPI, cpu_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* insert a ready task to system ready table with READY state and remove it from suspend list
|
||||
*
|
||||
* @param task the task descriptor
|
||||
*
|
||||
*/
|
||||
void KTaskInsertToReadyVector(struct TaskDescriptor *task)
|
||||
{
|
||||
int coreid = 0;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
KTaskStatSetAsReady(task);
|
||||
|
||||
coreid = task->task_smp_info.combined_coreid;
|
||||
|
||||
switch (coreid)
|
||||
{
|
||||
case UNCOMBINE_CPU_CORE:
|
||||
UncombineInsert(task);
|
||||
break;
|
||||
|
||||
default:
|
||||
ComnbineInsert(task, coreid);
|
||||
break;
|
||||
}
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED, ("insert task[%.*s], the priority: %d\n",
|
||||
NAME_NUM_MAX, task->task_base_info.name, task->task_dync_sched_member.cur_prio));
|
||||
|
||||
}
|
||||
|
||||
static void UncombineRemove(struct TaskDescriptor *task)
|
||||
{
|
||||
register x_ubase number = 0;
|
||||
register x_ubase highest_priority = 0;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
if (IsDoubleLinkListEmpty(&(Assign.os_assign_read_vector.priority_ready_vector[task->task_dync_sched_member.cur_prio]))) {
|
||||
#if KTASK_PRIORITY_MAX > 32
|
||||
|
||||
CLEAR_FLAG(&Assign.os_assign_read_vector.ready_vector[task->task_dync_sched_member.bitmap_offset], task->task_dync_sched_member.bitmap_row);
|
||||
if (Assign.os_assign_read_vector.ready_vector[task->task_dync_sched_member.bitmap_offset] == 0) {
|
||||
CLEAR_FLAG(&Assign.os_assign_read_vector.priority_ready_group, task->task_dync_sched_member.bitmap_column);
|
||||
}
|
||||
number = PrioCaculate(Assign.os_assign_read_vector.priority_ready_group);
|
||||
highest_priority = (number * 8) + PrioCaculate(Assign.os_assign_read_vector.ready_vector[number]);
|
||||
#else
|
||||
|
||||
|
||||
CLEAR_FLAG(&Assign.os_assign_read_vector.priority_ready_group, task->task_dync_sched_member.bitmap_column);
|
||||
highest_priority = PrioCaculate(Assign.os_assign_read_vector.priority_ready_group);
|
||||
#endif
|
||||
Assign.os_assign_read_vector.highest_prio = highest_priority;
|
||||
}
|
||||
}
|
||||
|
||||
static void CombineRemove(struct TaskDescriptor *task)
|
||||
{
|
||||
register x_ubase number = 0;
|
||||
register x_ubase highest_prio_on_core = 0;
|
||||
uint8 combined_coreid = task->task_smp_info.combined_coreid;
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
if (IsDoubleLinkListEmpty(&(Assign.smp_os_assign_ready_rector[combined_coreid].priority_ready_vector[task->task_dync_sched_member.cur_prio]))) {
|
||||
#if KTASK_PRIORITY_MAX > 32
|
||||
CLEAR_FLAG(&Assign.smp_os_assign_ready_rector[combined_coreid].ready_vector[task->task_dync_sched_member.bitmap_offset], task->task_dync_sched_member.bitmap_row);
|
||||
if (Assign.os_assign_read_vector.ready_vector[task->task_dync_sched_member.bitmap_offset] == 0) {
|
||||
CLEAR_FLAG(&Assign.smp_os_assign_ready_rector[combined_coreid].priority_ready_group, task->task_dync_sched_member.bitmap_column);
|
||||
}
|
||||
number = PrioCaculate(Assign.smp_os_assign_ready_rector[combined_coreid].priority_ready_group);
|
||||
highest_prio_on_core = (number * 8) + PrioCaculate(Assign.smp_os_assign_ready_rector[combined_coreid].ready_vector[number]);
|
||||
#else
|
||||
CLEAR_FLAG(&Assign.smp_os_assign_ready_rector[combined_coreid].priority_ready_group, task->task_dync_sched_member.bitmap_column);
|
||||
highest_prio_on_core = PrioCaculate(Assign.smp_os_assign_ready_rector[combined_coreid].priority_ready_group);
|
||||
#endif
|
||||
Assign.smp_os_assign_ready_rector[combined_coreid].highest_prio = highest_prio_on_core;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* a task will be removed from ready table.
|
||||
*
|
||||
* @param task task descriptor
|
||||
*
|
||||
*/
|
||||
void KTaskOsAssignRemoveKTask(struct TaskDescriptor *task)
|
||||
{
|
||||
|
||||
NULL_PARAM_CHECK(task);
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED, ("remove task[%.*s], the priority: %d\n",
|
||||
NAME_NUM_MAX, task->task_base_info.name,
|
||||
task->task_dync_sched_member.cur_prio));
|
||||
|
||||
DoubleLinkListRmNode(&(task->task_dync_sched_member.sched_link));
|
||||
switch (task->task_smp_info.combined_coreid)
|
||||
{
|
||||
case UNCOMBINE_CPU_CORE:
|
||||
UncombineRemove(task);
|
||||
break;
|
||||
|
||||
default:
|
||||
CombineRemove(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
x_err_t YieldOsAssign(void)
|
||||
{
|
||||
x_base lock = 0;
|
||||
int coreid = 0;
|
||||
x_ubase highest_prio = 0;
|
||||
struct TaskDescriptor *new_task = NONE;
|
||||
struct TaskDescriptor *runningtask = NONE;
|
||||
|
||||
lock = DISABLE_INTERRUPT();
|
||||
HwLockSpinlock(&AssignSpinLock);
|
||||
coreid = GetCpuId();
|
||||
runningtask = Assign.smp_os_running_task[coreid];
|
||||
|
||||
if (isrManager.done->getCounter()) {
|
||||
HwUnlockSpinlock(&AssignSpinLock);
|
||||
ENABLE_INTERRUPT(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
if(Assign.assign_lock[coreid] >= 1) {
|
||||
HwUnlockSpinlock(&AssignSpinLock);
|
||||
ENABLE_INTERRUPT(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
/* if the bitmap is empty then do not switch */
|
||||
if((RET_TRUE == JudgeAssignReadyBitmapIsEmpty(&Assign.os_assign_read_vector)) &&
|
||||
(RET_TRUE == JudgeAssignReadyBitmapIsEmpty(&Assign.smp_os_assign_ready_rector[coreid]))) {
|
||||
HwUnlockSpinlock(&AssignSpinLock);
|
||||
ENABLE_INTERRUPT(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
highest_prio = Assign.smp_assign_done->GetHighest();
|
||||
new_task = Assign.smp_assign_done->select();
|
||||
|
||||
if(RET_TRUE != JudgeKTaskStatIsRunning(runningtask)) {
|
||||
CHECK(NONE != new_task);
|
||||
} else {
|
||||
Assign.ready_vector_done->insert(runningtask);
|
||||
}
|
||||
|
||||
new_task->task_smp_info.runing_coreid = coreid;
|
||||
Assign.current_priority[coreid] = (uint8)highest_prio;
|
||||
|
||||
HOOK(hook.assign.hook_Assign,(runningtask, new_task));
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED,
|
||||
("[%d]switch to priority#%d "
|
||||
"task:%.*s(sp:0x%08x), "
|
||||
"from task:%.*s(sp: 0x%08x)\n",
|
||||
isrManager.done->getCounter(), highest_prio,
|
||||
NAME_NUM_MAX, new_task->task_base_info.name, new_task->stack_point,
|
||||
NAME_NUM_MAX, runningtask->task_base_info.name, runningtask->stack_point));
|
||||
|
||||
Assign.smp_assign_done->SwitchToNew(runningtask,new_task);
|
||||
|
||||
ENABLE_INTERRUPT(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* OsAssign startup function
|
||||
* .
|
||||
*/
|
||||
void StartupOsAssign(void)
|
||||
{
|
||||
struct TaskDescriptor *FirstRunningTask = NONE;
|
||||
|
||||
FirstRunningTask = Assign.smp_assign_done->select();
|
||||
Assign.smp_assign_done->SetSystemTask(FirstRunningTask);
|
||||
Assign.smp_assign_done->SwitchToFirst(FirstRunningTask);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* system OsAssign init function
|
||||
*/
|
||||
void SysInitOsAssign(void)
|
||||
{
|
||||
SYS_KDEBUG_LOG(KDBG_SCHED, ("start Os Assign: max priority 0x%02x\n",
|
||||
KTASK_PRIORITY_MAX));
|
||||
|
||||
Assign.ready_vector_done = &ready_vector_done;
|
||||
Assign.smp_assign_done = &smp_assign_done;
|
||||
Assign.ready_vector_done->init(&Assign.os_assign_read_vector);
|
||||
Assign.smp_assign_done->SmpInit();
|
||||
|
||||
}
|
||||
357
kernel/thread/softtimer.c
Normal file
357
kernel/thread/softtimer.c
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* 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: softtimer.c
|
||||
* @brief: softtimer file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
|
||||
DoubleLinklistType xiaoshan_timer_sort_head = {&xiaoshan_timer_sort_head, &xiaoshan_timer_sort_head};
|
||||
DoubleLinklistType k_timer_list = {&k_timer_list, &k_timer_list};
|
||||
|
||||
DECLARE_ID_MANAGER(k_softtimer_id_manager, ID_NUM_MAX);
|
||||
extern queue *sys_workq;
|
||||
|
||||
void _Init(struct Timer *timer,
|
||||
const char *name,
|
||||
void (*timeout)(void *parameter),
|
||||
void *parameter,
|
||||
x_ticks_t time,
|
||||
uint8 trigger_mode)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(timer);
|
||||
|
||||
strncpy(timer->name, name, NAME_NUM_MAX);
|
||||
|
||||
// insert to link
|
||||
lock = CriticalAreaLock();
|
||||
DoubleLinkListInsertNodeAfter(&(k_timer_list), &(timer->link));
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
timer->trigger_mode = trigger_mode;
|
||||
timer->active_status = TIMER_ACTIVE_FALSE;
|
||||
timer->func_callback = timeout;
|
||||
timer->param = parameter;
|
||||
timer->deadline_timeslice = 0;
|
||||
timer->origin_timeslice = time;
|
||||
timer->prio = GetKTaskDescriptor()->task_base_info.origin_prio;
|
||||
}
|
||||
|
||||
x_err_t _Delete(TimerType timer)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(timer);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
DoubleLinkListRmNode(&(timer->sortlist));
|
||||
DoubleLinkListRmNode(&(timer->link));
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
KERNEL_FREE(timer);
|
||||
timer = NONE;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
x_err_t _StartRun(TimerType timer)
|
||||
{
|
||||
NULL_PARAM_CHECK(timer);
|
||||
|
||||
x_base lock = CriticalAreaLock();
|
||||
timer->active_status = TIMER_ACTIVE_FALSE;
|
||||
|
||||
CHECK(timer->origin_timeslice < TICK_SIZE_MAX / 2);
|
||||
timer->deadline_timeslice = CurrentTicksGain() + timer->origin_timeslice;
|
||||
timer->active_status = TIMER_ACTIVE_TRUE;
|
||||
|
||||
DoubleLinklistType *pLink = NONE;
|
||||
TimerType pNode = NONE;
|
||||
|
||||
DOUBLE_LINKLIST_FOR_EACH(pLink, &xiaoshan_timer_sort_head) {
|
||||
pNode = CONTAINER_OF(pLink, struct Timer, sortlist);
|
||||
if (timer->deadline_timeslice < pNode->deadline_timeslice) {
|
||||
DoubleLinkListInsertNodeBefore(pLink, &timer->sortlist);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pLink == &xiaoshan_timer_sort_head) {
|
||||
DoubleLinkListInsertNodeBefore(&xiaoshan_timer_sort_head, &timer->sortlist);
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
// Just stop working, don't free memory
|
||||
x_err_t _QuitRun(TimerType timer)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(timer);
|
||||
|
||||
if (!(timer->active_status == TIMER_ACTIVE_TRUE))
|
||||
return -ERROR;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
timer->active_status = TIMER_ACTIVE_FALSE;
|
||||
timer->deadline_timeslice = 0;
|
||||
DoubleLinkListRmNode(&(timer->sortlist));
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
x_err_t _Modify(TimerType timer, x_ticks_t ticks)
|
||||
{
|
||||
NULL_PARAM_CHECK(timer);
|
||||
if (0 == ticks) {
|
||||
KPrintf("timeout ticks must be setted more then 0.\n");
|
||||
return -EINVALED;
|
||||
}
|
||||
timer->origin_timeslice = ticks;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static struct TimerDone Done =
|
||||
{
|
||||
.Init = _Init,
|
||||
.Delete = _Delete,
|
||||
.StartRun = _StartRun,
|
||||
.QuitRun = _QuitRun,
|
||||
.Modify = _Modify,
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will create a softtimer.
|
||||
*
|
||||
* @param name the length of the msg queue.
|
||||
* @param timeout the callback of the timer.
|
||||
* @param parameter the parameter of the callback function
|
||||
* @param time the timeout time
|
||||
* @param trigger_mode the trigger way of the timer
|
||||
*
|
||||
* @return id on success
|
||||
*/
|
||||
|
||||
int32 KCreateTimer(const char *name,
|
||||
void (*timeout)(void *parameter),
|
||||
void *parameter,
|
||||
x_ticks_t time,
|
||||
uint8 trigger_mode)
|
||||
{
|
||||
struct Timer *timer = NONE;
|
||||
|
||||
timer = (struct Timer *)x_malloc(sizeof(struct Timer));
|
||||
if (timer == NONE) {
|
||||
return NONE;
|
||||
}
|
||||
memset(timer, 0x0, sizeof(struct Timer));
|
||||
|
||||
// Generate ID
|
||||
int32 id = IdInsertObj(&k_softtimer_id_manager, &timer->id_node);
|
||||
if (id < 0) {
|
||||
x_free(timer);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
timer->done = &Done;
|
||||
timer->done->Init(timer, name, timeout, parameter, time, trigger_mode);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will delete a timer.
|
||||
*
|
||||
* @param timer_id the id number of timer.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
x_err_t KDeleteTimer(int32 timer_id)
|
||||
{
|
||||
TimerType timer = KGetTimer(timer_id);
|
||||
|
||||
timer->done->Delete(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will startup a timer.
|
||||
*
|
||||
* @param timer_id the id number of timer.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
x_err_t KTimerStartRun(int32 timer_id)
|
||||
{
|
||||
TimerType timer = KGetTimer(timer_id);
|
||||
|
||||
return timer->done->StartRun(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will stop a timer.
|
||||
*
|
||||
* @param timer_id the id number of timer.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
x_err_t KTimerQuitRun(int32 timer_id)
|
||||
{
|
||||
TimerType timer = KGetTimer(timer_id);
|
||||
|
||||
timer->done->QuitRun(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will modify the timeout of a timer.
|
||||
*
|
||||
* @param timer_id the id number of timer.
|
||||
* @param ticks timeout ticks
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
x_err_t KTimerModify(int32 timer_id, x_ticks_t ticks)
|
||||
{
|
||||
TimerType timer = KGetTimer(timer_id);
|
||||
|
||||
timer->done->Modify(timer, ticks);
|
||||
}
|
||||
|
||||
static void TimerCBEnter(void *param)
|
||||
{
|
||||
struct Timer *t = (struct Timer *)param;
|
||||
|
||||
t->func_callback(t->param);
|
||||
free(t->t_work);
|
||||
}
|
||||
|
||||
void timer_work_func(struct Work *work, void *work_data)
|
||||
{
|
||||
x_err_t flag;
|
||||
struct Timer *t = work_data;
|
||||
|
||||
int32 timer_work = KTaskCreate("timer_work_thr", TimerCBEnter, t, 2048, t->prio);
|
||||
flag = StartupKTask(timer_work);
|
||||
if (flag != EOK) {
|
||||
KPrintf("timer create callback thread failed .\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void CheckTimerList(void)
|
||||
{
|
||||
x_base lock = 0;
|
||||
struct Timer *t = NONE;
|
||||
x_ticks_t current_tick = 0;
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SOFTTIMER, ("timer check enter\n"));
|
||||
|
||||
current_tick = CurrentTicksGain();
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
while (!IsDoubleLinkListEmpty(&xiaoshan_timer_sort_head)) {
|
||||
t = SYS_DOUBLE_LINKLIST_ENTRY(xiaoshan_timer_sort_head.node_next,
|
||||
struct Timer, sortlist);
|
||||
|
||||
if ((current_tick - t->deadline_timeslice) < TICK_SIZE_MAX / 2) {
|
||||
if (t->active_status == TIMER_ACTIVE_TRUE) {
|
||||
DoubleLinkListRmNode(&t->sortlist); // Take it off the list first
|
||||
|
||||
current_tick = CurrentTicksGain();
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SOFTTIMER, ("current tick: %d\n", current_tick));
|
||||
|
||||
if (t->trigger_mode == TIMER_TRIGGER_PERIODIC) {
|
||||
t->done->StartRun(t); // Periodic timer, re insert the appropriate position of the list
|
||||
} else {
|
||||
t->done->QuitRun(t);
|
||||
}
|
||||
|
||||
// Throw it to the task queue and start a new thread
|
||||
t->t_work = x_malloc(sizeof(struct Work));
|
||||
|
||||
((WorkQueueDoneType *)sys_workq->done)->WorkInit(t->t_work, timer_work_func, t);
|
||||
CriticalAreaUnLock(lock);
|
||||
((WorkQueueDoneType *)sys_workq->done)->WorkSubmit((WorkqueueType *)sys_workq->property, t->t_work, 0);
|
||||
lock = CriticalAreaLock();
|
||||
} else {
|
||||
KPrintf("sortlist run unactive timer(%s), quit this timer\n", t->name);
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
SYS_KDEBUG_LOG(KDBG_SOFTTIMER, ("timer check leave\n"));
|
||||
}
|
||||
|
||||
x_err_t KTimerAssignMemberRun(int32 timer_id, x_ticks_t ticks)
|
||||
{
|
||||
TimerType timer = KGetTimer(timer_id);
|
||||
|
||||
NULL_PARAM_CHECK(timer);
|
||||
if (ticks == 0) {
|
||||
KPrintf("Timeout ticks must be setted more than 0.\n");
|
||||
return -EINVALED;
|
||||
}
|
||||
timer->origin_timeslice = ticks;
|
||||
|
||||
return timer->done->StartRun(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will get the timer with id.
|
||||
*
|
||||
* @param id the id number of timer.
|
||||
*
|
||||
* @return timer structrue
|
||||
*/
|
||||
TimerType KGetTimer(int32 id)
|
||||
{
|
||||
x_base lock = 0;
|
||||
TimerType timer = NONE;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
struct IdNode *idnode = IdGetObj(&k_softtimer_id_manager, id);
|
||||
if (idnode == NONE){
|
||||
CriticalAreaUnLock(lock);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
timer = CONTAINER_OF(idnode, struct Timer, id_node);
|
||||
CriticalAreaUnLock(lock);
|
||||
return timer;
|
||||
}
|
||||
|
||||
int32 KGetTimerID(TimerType timer)
|
||||
{
|
||||
return timer->id_node.id;
|
||||
}
|
||||
123
kernel/thread/tick.c
Normal file
123
kernel/thread/tick.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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: tick.c
|
||||
* @brief: system heartbeat_ticks update
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <xs_spinlock.h>
|
||||
#include <xs_delay.h>
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
static x_ticks_t heartbeat_ticks[CPU_NUMBERS] = {0};
|
||||
#else
|
||||
static x_ticks_t heartbeat_ticks = 0;
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_SMP
|
||||
#define UPDATE_GLOBAL_HEARTBEAT() \
|
||||
do { \
|
||||
heartbeat_ticks[GetCpuId()]++; \
|
||||
} while(0);
|
||||
#else
|
||||
#define UPDATE_GLOBAL_HEARTBEAT() \
|
||||
do { \
|
||||
heartbeat_ticks ++; \
|
||||
} while(0);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* get haertbeat count
|
||||
*
|
||||
* @return CurrentTicks
|
||||
*/
|
||||
x_ticks_t CurrentTicksGain(void)
|
||||
{
|
||||
#ifdef ARCH_SMP
|
||||
return heartbeat_ticks[GetCpuId()];
|
||||
#else
|
||||
return heartbeat_ticks;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* this function increases global systick in tick interrupt,and process task time slice
|
||||
*
|
||||
*/
|
||||
void TickAndTaskTimesliceUpdate(void)
|
||||
{
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
UPDATE_GLOBAL_HEARTBEAT();
|
||||
|
||||
#if defined(SCHED_POLICY_FIFO)
|
||||
FifoTaskTimesliceUpdate();
|
||||
#elif defined (SCHED_POLICY_RR)
|
||||
task = GetKTaskDescriptor();
|
||||
RoundRobinTaskTimesliceUpdate(task);
|
||||
#elif defined (SCHED_POLICY_RR_REMAINSLICE)
|
||||
task = GetKTaskDescriptor();
|
||||
RoundRobinRemainTaskTimesliceUpdate(task);
|
||||
#endif
|
||||
CheckTaskDelay();
|
||||
#ifdef KERNEL_SOFTTIMER
|
||||
CheckTimerList();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will convert ms to ticks.
|
||||
*
|
||||
* @param ms time need to be converted
|
||||
* @return ticks
|
||||
*/
|
||||
#define MIN_TICKS 1
|
||||
|
||||
x_ticks_t CalculteTickFromTimeMs(uint32 ms)
|
||||
{
|
||||
uint32 tmp = 0;
|
||||
x_ticks_t ticks = 0;
|
||||
|
||||
ticks = (uint32)(((uint64)(ms * TICK_PER_SECOND)) / 1000) ;
|
||||
if (0 == ticks) {
|
||||
ticks = MIN_TICKS;
|
||||
} else {
|
||||
tmp = (uint32)(((uint64)(ms * TICK_PER_SECOND)) % 1000);
|
||||
|
||||
if(tmp >= 5 && tmp <= 9) {
|
||||
ticks = ticks + MIN_TICKS;
|
||||
}
|
||||
}
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will convert ticks to ms.
|
||||
*
|
||||
* @param ticks ticks need to be converted
|
||||
* @return ms
|
||||
*/
|
||||
uint32 CalculteTimeMsFromTick(x_ticks_t ticks)
|
||||
{
|
||||
uint32 ms = 0;
|
||||
|
||||
ms = (uint32)(((uint64)(ticks * 1000)) / TICK_PER_SECOND);
|
||||
|
||||
return ms;
|
||||
}
|
||||
148
kernel/thread/waitqueue.c
Normal file
148
kernel/thread/waitqueue.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include <xs_isr.h>
|
||||
#include <device.h>
|
||||
#include <xs_klist.h>
|
||||
#include <xs_memory.h>
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
183
kernel/thread/workqueue.c
Normal file
183
kernel/thread/workqueue.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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: workqueue.c
|
||||
* @brief: workqueue file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <device.h>
|
||||
queue *sys_workq = NONE;
|
||||
|
||||
static void _WorkQueueKTaskEntry(void *parameter)
|
||||
{
|
||||
x_base lock = 0;
|
||||
WorkqueueType *p_queue = (WorkqueueType *)parameter;
|
||||
|
||||
while (1)
|
||||
{
|
||||
lock = CriticalAreaLock();
|
||||
if (p_queue->front != p_queue->rear) { // The team is not empty
|
||||
struct Work *work = &(p_queue->base[p_queue->front]);
|
||||
|
||||
p_queue->front = (p_queue->front + 1) % MAX_WORK_QUEUE;
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
if (work->cb_func) {
|
||||
work->cb_func(work, work->cb_param);
|
||||
}
|
||||
} else {
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
SuspendKTask(p_queue->task);
|
||||
DO_KTASK_ASSIGN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeInitWorkQueue(WorkqueueType *p_queue)
|
||||
{
|
||||
if (NONE != p_queue->task) {
|
||||
KTaskDelete(p_queue->task);
|
||||
}
|
||||
|
||||
if (NONE != p_queue) {
|
||||
if (NONE != p_queue->base) {
|
||||
x_free(p_queue->base);
|
||||
}
|
||||
x_free(p_queue);
|
||||
}
|
||||
}
|
||||
|
||||
WorkqueueType *CreateWorkQueue(const char *name, uint16 stack_size, uint8 priority)
|
||||
{
|
||||
WorkqueueType *p_queue = NONE;
|
||||
do {
|
||||
p_queue = x_malloc(sizeof(WorkqueueType));
|
||||
|
||||
if (NONE == p_queue) {
|
||||
KPrintf("CreateWorkQueue x_malloc(sizeof(WorkqueueType) failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
memset(p_queue, 0, sizeof(WorkqueueType));
|
||||
|
||||
p_queue->base = x_malloc(MAX_WORK_QUEUE * sizeof(struct Work));
|
||||
if (NONE == p_queue->base) {
|
||||
KPrintf("CreateWorkQueue x_malloc(MAX_WORK_QUEUE * sizeof(struct Work) failed\n");
|
||||
break;
|
||||
}
|
||||
memset(p_queue->base, 0, MAX_WORK_QUEUE * sizeof(struct Work));
|
||||
|
||||
p_queue->front = p_queue->rear = 0;
|
||||
|
||||
// start work thread
|
||||
p_queue->task = KTaskCreate(name, _WorkQueueKTaskEntry, p_queue, 2048, priority);
|
||||
if (NONE == p_queue->task) {
|
||||
KPrintf("CreateWorkQueue KTaskCreate failed\n");
|
||||
break;
|
||||
}
|
||||
StartupKTask(p_queue->task);
|
||||
|
||||
return p_queue;
|
||||
} while (0);
|
||||
|
||||
DeInitWorkQueue(p_queue);
|
||||
return NONE;
|
||||
}
|
||||
|
||||
void WorkInit(struct Work *work, void (*work_func)(struct Work *work, void *work_data), void *work_data)
|
||||
{
|
||||
work->cb_func = work_func;
|
||||
work->cb_param = work_data;
|
||||
}
|
||||
|
||||
void work_elem_timeout(void *in_param)
|
||||
{
|
||||
WorkTimerParamType *param = (WorkTimerParamType *)in_param;
|
||||
WorkSubmit_immediate(param->p_queue, param->p_work);
|
||||
}
|
||||
|
||||
x_err_t WorkSubmit_immediate(WorkqueueType *sys_workq, struct Work *work)
|
||||
{
|
||||
x_base lock = CriticalAreaLock();
|
||||
|
||||
NULL_PARAM_CHECK(sys_workq);
|
||||
NULL_PARAM_CHECK(work);
|
||||
|
||||
// check queue is full
|
||||
if ((sys_workq->rear + 1 + MAX_WORK_QUEUE) % MAX_WORK_QUEUE == sys_workq->front) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ERROR;
|
||||
}
|
||||
// add to queue
|
||||
sys_workq->base[sys_workq->rear].cb_func = work->cb_func;
|
||||
sys_workq->base[sys_workq->rear].cb_param = work->cb_param;
|
||||
sys_workq->rear = (sys_workq->rear + 1) % MAX_WORK_QUEUE;
|
||||
|
||||
// awake work thread
|
||||
KTaskWakeup(sys_workq->task);
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
}
|
||||
|
||||
x_err_t WorkSubmit(WorkqueueType *sys_workq, struct Work *work, x_ticks_t time)
|
||||
{
|
||||
NULL_PARAM_CHECK(sys_workq);
|
||||
NULL_PARAM_CHECK(work);
|
||||
|
||||
if (0 == time) {
|
||||
WorkSubmit_immediate(sys_workq, work);
|
||||
} else {
|
||||
// init a timer, add to queue later
|
||||
WorkTimerParamType *param = x_malloc(sizeof(WorkTimerParamType));
|
||||
param->p_queue = sys_workq;
|
||||
param->p_work = work;
|
||||
param->p_timer = KCreateTimer("wk_timer", work_elem_timeout, param, time, TIMER_TRIGGER_ONCE);
|
||||
if (NONE == param->p_timer) {
|
||||
KPrintf("WorkSubmit KCreateTimer failed \n");
|
||||
x_free(param);
|
||||
return -ERROR;
|
||||
}
|
||||
KTimerStartRun(param->p_timer);
|
||||
}
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will create a workqueue.
|
||||
*
|
||||
* @return EOK on success;ERROR on failure
|
||||
*/
|
||||
int WorkSysWorkQueueInit(void)
|
||||
{
|
||||
if (sys_workq != NONE)
|
||||
return 0;
|
||||
|
||||
sys_workq = x_malloc(sizeof(queue));
|
||||
sys_workq->done = g_queue_done[WORK_QUEUE];
|
||||
sys_workq->property = ((WorkQueueDoneType*)sys_workq->done)->CreateWorkQueue("sys_work", WORKQUEUE_KTASK_STACKSIZE,
|
||||
WORKQUEUE_KTASK_PRIORITY);
|
||||
|
||||
if (sys_workq->property == NONE) {
|
||||
KPrintf("log sys_workq create failed\n");
|
||||
} else {
|
||||
KPrintf("log sys_workq create success\n");
|
||||
}
|
||||
|
||||
return sys_workq->property == NONE ? ERROR : EOK;
|
||||
}
|
||||
96
kernel/thread/zombierecycle.c
Normal file
96
kernel/thread/zombierecycle.c
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
/*
|
||||
* 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: zombierecycle.c
|
||||
* @brief: a recycle task of system
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#ifdef TASK_ISOLATION
|
||||
#include <xs_isolation.h>
|
||||
#endif
|
||||
|
||||
DoubleLinklistType KTaskZombie;
|
||||
|
||||
#ifndef ZOMBIE_KTASK_STACKSIZE
|
||||
#define ZOMBIE_KTASK_STACKSIZE 2048
|
||||
#endif
|
||||
|
||||
int32 zombie_recycle;
|
||||
|
||||
int JudgeZombieKTaskIsNotEmpty(void)
|
||||
{
|
||||
return (IsDoubleLinkListEmpty(&KTaskZombie) ? 0 : RET_TRUE);
|
||||
}
|
||||
|
||||
static void ZombieKTaskEntry(void *parameter)
|
||||
{
|
||||
x_base lock = 0;
|
||||
KTaskDescriptorType task = NONE;
|
||||
|
||||
while(RET_TRUE)
|
||||
{
|
||||
KDEBUG_NOT_IN_INTERRUPT;
|
||||
lock = CriticalAreaLock();
|
||||
if (JudgeZombieKTaskIsNotEmpty()) {
|
||||
task = SYS_DOUBLE_LINKLIST_ENTRY(KTaskZombie.node_next, struct TaskDescriptor, task_dync_sched_member.sched_link);
|
||||
DoubleLinkListRmNode(&(task->task_dync_sched_member.sched_link));
|
||||
CriticalAreaUnLock(lock);
|
||||
#ifdef SEPARATE_COMPILE
|
||||
if(1 == task->task_dync_sched_member.isolation_flag ){
|
||||
#ifdef MOMERY_PROTECT_ENABLE
|
||||
if(mem_access.Free)
|
||||
mem_access.Free(task->task_dync_sched_member.isolation);
|
||||
#endif
|
||||
x_ufree(task->task_base_info.stack_start);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
KERNEL_FREE(task->task_base_info.stack_start);
|
||||
}
|
||||
|
||||
DoubleLinkListRmNode(&(task->link));
|
||||
|
||||
KTaskIdDelete(task->id.id);
|
||||
|
||||
if(task->task_dync_sched_member.delay != NONE){
|
||||
|
||||
}
|
||||
KERNEL_FREE(task->task_dync_sched_member.delay);
|
||||
|
||||
KERNEL_FREE(task);
|
||||
} else {
|
||||
SuspendKTask(zombie_recycle);
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZombieTaskRecycleInit(void)
|
||||
{
|
||||
InitDoubleLinkList(&KTaskZombie);
|
||||
|
||||
zombie_recycle = KTaskCreate("ZombieRecycleKTask",
|
||||
ZombieKTaskEntry,
|
||||
NONE,
|
||||
ZOMBIE_KTASK_STACKSIZE,
|
||||
KTASK_LOWEST_PRIORITY + 1);
|
||||
|
||||
StartupKTask(zombie_recycle);
|
||||
}
|
||||
Reference in New Issue
Block a user