First commit XiUOS

This commit is contained in:
xuetest
2021-04-28 17:49:18 +08:00
commit 6001051eb7
1331 changed files with 433955 additions and 0 deletions

View 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
View 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
View 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
View 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();
}

View 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;
}

View 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;
}
}

View 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
View 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
View 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
View 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
View 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;
}
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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++;
}

View 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

File diff suppressed because it is too large Load Diff

105
kernel/thread/ktask_stat.c Normal file
View 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
View 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
View 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
View 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
View 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);
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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);
}