📄 djyos.c
字号:
pl_ecbn->previous = pg_event_running;
}
}
}
return 0;
}
//----登记错误信息--------------------------------------------------------------
//功能:把系统错误信息登记到一个环形缓冲区里
//参数:error_type,错误类型
// text,文字说明
//返回:无
//还需添加文本串的功能,---db
//-----------------------------------------------------------------------------
void y_error_login(uint32_t error_type,const char *text)
{
pg_event_running->error_no = error_type;
}
//----提取最后一条错误信息-----------------------------------------------------
//功能:把系统错误信息登记到一个环形缓冲区里
//参数:text,返回该错误的文字说明
//返回:错误号
//还需添加文本串和时间的功能,时间使用ticks数---db
//-----------------------------------------------------------------------------
uint32_t y_get_last_error(char *text)
{
return pg_event_running->error_no;
}
//----从ready队列中取出一个事件------------------------------------------------
//功能: 把一个事件从ready队列中取出,并使ready队列重新连接
//参数: event,待取出的事件指针
//返回: 无
//注: 调用者请保证在异步信号(调度)被禁止的情况下调用本函数
//-----------------------------------------------------------------------------
void __y_cut_ready_event(struct event_script *event)
{
struct event_script *pl_ecb;
if(event != pg_event_ready) //event不是ready队列头
{
if(event->multi_next == NULL) //不是相应优先级的首事件
{
event->next->previous = event->previous;
event->previous->next = event->next;
}else //是相应优先级的首事件
{
pl_ecb = event->next;
event->next->previous = event->previous;
event->previous->next = event->next;
if(pl_ecb->prio == event->prio) //相应优先级不止一个事件
{
event->multi_previous->multi_next = pl_ecb;
pl_ecb->multi_previous = event->multi_previous;
event->multi_next->multi_previous = pl_ecb;
pl_ecb->multi_next = event->multi_next;
}else //相应优先级只有一个事件
{
//pl_ecb即event->multi_next.
pl_ecb->multi_previous = event->multi_previous;
event->multi_previous->multi_next = pl_ecb;
}
}
}else //event是ready队列头
{
pg_event_ready = event->next;
pl_ecb = event->next;
event->next->previous = event->previous;
event->previous->next = event->next;
if(pl_ecb->prio == event->prio) //相应优先级不止一个事件
{
event->multi_previous->multi_next = pl_ecb;
pl_ecb->multi_previous = event->multi_previous;
event->multi_next->multi_previous = pl_ecb;
pl_ecb->multi_next = event->multi_next;
}else //相应优先级只有一个事件
{
//pl_ecb即event->multi_next.
pl_ecb->multi_previous = event->multi_previous;
event->multi_previous->multi_next = pl_ecb;
}
}
event->event_status.bit.event_ready = 0;
}
//----设置轮转调度时间片-------------------------------------------------------
//功能: djyos总所有参与轮转调度的事件时间片都是相同的,在这里设置。如果设为0,
// 表示不允许时间片轮转。
//参数: slices,新的轮转调度时间片,毫秒数,将被向上取整为整数个ticks时间
//返回: 无
//-----------------------------------------------------------------------------
void y_set_RRS_slice(uint32_t slices)
{
#if (32 > cn_cpu_bits)
//若处理器字长<32位,需要多个周期才能更新u32g_RRS_slice,该过程不能被时钟中断打断.
int_save_asyn_signal( );
#endif
u32g_RRS_slice =(slices + cn_tick_ms -1)/cn_tick_ms;
#if (32 > cn_cpu_bits)
//若处理器字长<32位,需要多个周期才能更新u32g_RRS_slice,该过程不能被时钟中断打断.
int_restore_asyn_signal( );
#endif
}
//----查询轮转调度时间片-------------------------------------------------------
//功能: djyos总所有参与轮转调度的事件时间片都是相同的,可用本函数查询。
//参数: 无
//返回: 当前时间片长度,毫秒数。
//-----------------------------------------------------------------------------
uint32_t y_get_RRS_slice(void)
{
uint32_t temp;
#if (32 > cn_cpu_bits)
//处理器字长<32位,需要多个周期才能读取u32g_RRS_slice,该过程不能被时钟中断打断.
int_save_asyn_signal( );
#endif
temp = u32g_RRS_slice * cn_tick_ms;
#if (32 > cn_cpu_bits)
//处理器字长<32位,需要多个周期才能读取u32g_RRS_slice,该过程不能被时钟中断打断.
int_restore_asyn_signal( );
#endif
return temp * cn_tick_ms;
}
//----查找可运行线程----------------------------------------------------------
//功能: 在 pg_event_ready队列中获得一个可以运行的线程.
// 1.从pg_event_ready队列头开始查找,如果该事件还没有连接线程,则试图创建之.
// 2.如果不能建立,肯定是因内存不足,则把该事件放到内存等待表中,继续往下查找.
// 3.如此反复,直到找到一个可以运行的线程.然后把pg_event_ready指针指向该事件
//参数: 无
//返回: 无
//备注: 本函数由操作系统调用,调用前保证关异步信号。
// 由于系统服务事件总是ready,所以总是能找到可以运行的线程.
//----------------------------------------------------------------------------
void __y_select_event_to_run(void)
{
struct event_script *pl_ecb;
struct event_type *pl_evtt; //被操作的事件的类型指针
while(pg_event_ready->vm == NULL)
{
pl_evtt =& tg_evtt_table[pg_event_ready->evtt_id];
if(pl_evtt->my_free_vm != NULL) //该事件类型有空闲的线程,直接使用
{
pg_event_ready->vm = pl_evtt->my_free_vm;
pl_evtt->my_free_vm = pl_evtt->my_free_vm->next;
}else //该事件类型没有空闲的线程,试图创建之
{
pg_event_ready->vm = __create_thread(pl_evtt); //创建线程
if(pg_event_ready->vm == NULL) //创建线程失败
{
pl_ecb = pg_event_ready;
__y_cut_ready_event(pl_ecb);
__m_wait_memory(pl_ecb);
}else //成功创建线程
{
pl_evtt->vpus++;
//取此前被重复pop的次数
pg_event_ready->repeats = pl_evtt->repeats;
}
}
}
}
//----创建进程虚拟机-----------------------------------------------------------
//功能: 创建进程虚拟机。
//参数: 无
//返回: 无
//备注: 这只是占一个位而已,在mp模式才有实用价值
//-----------------------------------------------------------------------------
void y_create_process_vm(void)
{
static struct process_vm my_process;
pg_my_process = &my_process;
}
//----事件调度-----------------------------------------------------------------
//功能:剥夺running事件的cpu,把cpu交给ready队列的第一个事件.如果ready队列的第一
// 个事件尚未拥有线程,则建立之.建立线程时如果内存不足,则把这个事件放到
// 内存等待链表中,ready指针指向ready队列的下一个事件,依次推之,直到找到一个
// 线程虚拟机指针非空或者成功创建线程虚拟机的事件.
//参数:无
//返回:true = 成功切换,false = 未切换直接返回
//备注:1.本函数由操作系统调用
// 2.djyos系统认为,用户禁止中断就是为了能够连续执行,或者保护临界资源.
// djyos中异步信号相当于高优先级线程,所以全局和异步信号禁止状态
// 下,是不允许事件调度的.
// 3.实时中断是否禁止,与调度无关.
// 4.本函数由操作系统调用,调用方保证调用时中断是允许的,不检查.
// 5.由于最低优先级的系统服务事件总是ready,因此本函数总是能够找到目标事件
//-----------------------------------------------------------------------------
bool_t __schedule(void)
{
struct event_script *event;
if(tg_int_global.nest_asyn_signal != 0)
return false;
int_save_asyn_signal(); //在上下文切换期间不能发生异步信号中断
__y_select_event_to_run();
if(pg_event_ready != pg_event_running)
{//当running事件仍在ready队列中,且内存不足以建立新虚拟机时,可能会出现优先
//级高于running的事件全部进入内存等待队列的可能.此时执行else子句.
u32g_running_start=y_get_time();
event = pg_event_running;
pg_event_running=pg_event_ready;
__asm_switch_context(pg_event_ready->vm ,event->vm);
}else
{//优先级高于running的事件全部进入内存等待队列,下一个要处理的事件就是
//running事件,无须执行任何操作
int_restore_asyn_signal();
return false;
}
return true;
}
//----中断内执行的事件调度------------------------------------------------------
//功能:剥夺running事件的cpu,把cpu交给ready队列的第一个事件.如果ready队列的第一
// 个事件尚不拥有线程,则创建之.建立线程时如果内存不足,则把这个事件放到
// 内存等待链表中,ready指针指向ready队列的下一个事件,依次推之,直到找到一个
// 线程虚拟机指针非空或者成功创建线程虚拟机的事件.
//参数:无
//返回:无
//备注:本函数由操作系统在异步信号引擎返回前调用
// 由于最低优先级的y_idle_service事件总是ready,因此总是能够找到调度对象的.
//-----------------------------------------------------------------------------
void __schedule_asyn_signal(void)
{
struct event_script *event;
__y_select_event_to_run();
if(pg_event_ready != pg_event_running)
{//当running事件仍在ready队列中,且内存不足以建立新虚拟机时,可能会出现优先
//级高于running的事件全部进入内存等待队列的可能.此时执行else子句.
u32g_running_start=y_get_time();
event=pg_event_running;
pg_event_running=pg_event_ready;
__asm_switch_context_int(pg_event_ready->vm,event->vm);
}else
{//优先级高于running的事件全部进入内存等待队列,下一个要处理的事件就是
//running事件,无须执行任何操作
}
return;
}
//----登记事件类型------------------------------------------------------------
//功能:登记一个事件类型到系统中,事件类型经过登记后,就可以pop了,否则,系统会
// 拒绝pop该类型事件
//参数:mark,本事件类型是否mark型事件,true = 是,false = 否
// overlay,若是mark型事件,新事件参数是否覆盖队列中已有事件,非mark事件无效
// default_prio,本事件类型的默认优先级。
// vpus_limit,同一事件本类型事件所能拥有的线程数量的最大值
// thread_routine,线程入口函数(事件处理函数)
// stack_size,执行thread_routine需要的栈尺寸,不包括thread_routine函数可能
// 调用的系统服务。
// evtt_name,事件类型名,不同模块之间要交叉弹出事件的话,用事件类型名。
// 本参数允许是NULL,但只要非NULL,就不允许与事件类型表中已有的名字重名
//返回:新事件类型的类型号
//------------------------------------------------------------------------------
uint16_t y_evtt_regist(bool_t mark,bool_t overlay,
ufast_t default_prio,
uint16_t vpus_limit,
void (*thread_routine)(struct event_script *),
uint32_t stack_size,
char *evtt_name)
{
uint16_t i,evtt_id;
char *temp_name;
if((default_prio >= cn_prio_sys_service) || (default_prio == 0))
{
y_error_login(enum_knl_invalid_prio,"事件类型优先级非法");
return cn_invalid_evtt_id;
}
int_save_asyn_signal(); //禁止调度也就是禁止异步事件
for(evtt_id=0; evtt_id<cn_evtts_limit; evtt_id++) //查找空闲的事件控制块
if( tg_evtt_table[evtt_id].property.registered == 0)
break;
if(evtt_id == cn_evtts_limit) //没有空闲事件控制块
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -