📄 djyos.c
字号:
// 3、与其他内部函数一样,由调用方保证参数合理性,即u32l_mS>0.
//-----------------------------------------------------------------------------
void __y_addto_delay(uint32_t u32l_mS)
{
struct event_script * event;
uint32_t start;
pg_event_running->delay_start = y_get_time(); //事件延时开始时间
pg_event_running->delay_end = pg_event_running->delay_start
+ (u32l_mS + cn_tick_ms -1)/cn_tick_ms; //延时结束时间
if(pg_event_delay==NULL) //延时队列空
{
pg_event_running->next = pg_event_running;
pg_event_running->previous = pg_event_running;
pg_event_delay=pg_event_running;
}else
{
event = pg_event_delay;
start=pg_event_running->delay_start;
do
{//本循环找到第一个剩余延时时间大于新延时事件的事件.
//如果1tick=1mS,那么49.7天后将回绕,yos不能提供超过49.7天的延时
//如果直接比较delay_end,则一个发生回绕而另一个不回绕时,将会出错,
//-start可以避免回绕时发生错误
if((event->delay_end - start)
<= (pg_event_running->delay_end - start))
event = event->next;
else
break;
}while(event != pg_event_delay);
//如果没有找到剩余延时时间比新延时事件长的事件,新事件插入队列尾,
//而队列尾部就是pg_event_delay的前面,event恰好等于pg_event_delay
//如果找到剩余延时时间长于新事件的事件,新事件插入该事件前面.
//所以无论前面循环找到与否,均可使用下列代码
pg_event_running->next = event;
pg_event_running->previous = event->previous;
event->previous->next = pg_event_running;
event->previous = pg_event_running;
if(pg_event_delay->delay_end -start > pg_event_running->delay_end-start)
//新事件延时小于原队列中的最小延时.
pg_event_delay = pg_event_running;
}
}
//----清除mark型事件标记-------------------------------------------------------
//功能: 用于mark型事件,一条mark型事件发生后,清除标记前,如果再次发生同类型的
// 事件,只是简单地repeats增量,在清除标记后,再次发生则登记新事件。登记事
// 件时,若前一条事件已经完成,则加入ready队列,并由和mark_unclear指针索引,
// 若前一条事件未完成,则只由mark_unclear指针索引,待前一条事件完成在加入
// ready队列,以确保mark型事件只有一条在处理。
//参数: 无
//返回: 无
//-----------------------------------------------------------------------------
void y_clear_mark(void)
{
struct event_type *pl_evtt; //被操作的事件的类型指针
pl_evtt = &tg_evtt_table[pg_event_running->evtt_id];
pl_evtt->repeats = 0; //mark标识状态量,一次全处理
pl_evtt->mark_unclear = NULL;
}
//----闹钟同步-----------------------------------------------------------------
//功能:由正在执行的事件调用,使自己暂停u32l_mS毫秒后继续运行.
//参数:u32l_mS,延迟时间,单位是毫秒,0且允许轮转调度则把事件放到同优先级的
// 最后。非0值将被向上调整为cn_tick_ms的整数倍
//返回:实际延时时间(ticks)数
//备注:延时队列为双向循环链表
//-----------------------------------------------------------------------------
uint32_t y_timer_sync(uint32_t u32l_mS)
{
struct event_script * event;
uint32_t start;
if( !y_query_sch())
{ //禁止调度,不能进入闹钟同步状态。
y_error_login(enum_knl_cant_sched,NULL);
return 0;
}
int_save_asyn_signal();
//延时量为0的算法:就绪队列中有同优先级的,把本事件放到轮转最后一个,
//注意:这里不管轮转调度是否允许
if(u32l_mS == 0)
{
if((pg_event_running->prio == pg_event_running->next->prio)
&& (pg_event_running != pg_event_running->next) )
{
pg_event_running->delay_start = y_get_time(); //设定闹铃的时间
__y_cut_ready_event(pg_event_running); //从同步队列取出
__y_event_ready(pg_event_running); //放回同步队列尾部
}else
{
int_restore_asyn_signal();
return 0; //延时量为0,且不符合轮转条件
}
}else
{
pg_event_running->delay_start = y_get_time(); //设定闹铃的时间
pg_event_running->delay_end = pg_event_running->delay_start
+ (u32l_mS + cn_tick_ms -1)/cn_tick_ms; //闹铃时间
__y_cut_ready_event(pg_event_running);
pg_event_running->last_status.all = pg_event_running->event_status.all;
pg_event_running->event_status.bit.event_delay=1;
if(pg_event_delay==NULL) //闹钟同步队列空
{
pg_event_running->next = pg_event_running;
pg_event_running->previous = pg_event_running;
pg_event_delay=pg_event_running;
}else
{
event = pg_event_delay;
start=pg_event_running->delay_start;
do
{//本循环找到第一个闹铃时间晚于新事件的事件.
//如果1tick=1mS,那么49.7天后将回绕,djyos不能提供超过49.7天的延时
//如果直接比较delay_end,则一个发生回绕而另一个不回绕时,将会出错,
//-start可以避免回绕时发生错误
if((event->delay_end - start)
<= (pg_event_running->delay_end - start))
event = event->next;
else
break;
}while(event != pg_event_delay);
//下面把新事件插入前述找到的事件前面,如没有找到,则event将等于
//pg_event_delay,因是双向循环队列,g_event_delay前面也就刚好是队列尾。
pg_event_running->next = event;
pg_event_running->previous = event->previous;
event->previous->next = pg_event_running;
event->previous = pg_event_running;
if(pg_event_delay->delay_end -start
>pg_event_running->delay_end-start)
//新事件延时小于原队列中的最小延时.
pg_event_delay = pg_event_running;
}
}
int_restore_asyn_signal();
return (y_get_time() - pg_event_running->delay_start)*cn_tick_ms;
}
//----同步事件----------------------------------------------------------------
//功能: 把正在运行的事件加入到指定事件的同步队列中去,然后重新调度
//参数: event_id,目标事件id号
// timeout,超时设置,单位是毫秒,cn_timeout_forever=无限等待,0则立即按
// 超时返回。非0值将被向上调整为cn_tick_ms的整数倍
//返回: cn_sync_success=同步条件成立返回,
// cn_sync_timeout=超时返回,
// cn_sync_error=出错,
//----------------------------------------------------------------------------
uint32_t y_event_sync(uint16_t event_id,uint32_t timeout)
{
struct event_script * pl_ecb;
pl_ecb = &tg_event_table[event_id];
if(y_query_sch() == false) //不能在禁止调度的情况下执行同步操作
return cn_sync_error;
if(timeout == 0)
return cn_sync_timeout;
int_save_asyn_signal();
if(pl_ecb->previous == (struct event_script *)&pg_event_free)
{//目标事件是空闲事件
int_restore_asyn_signal();
return cn_sync_error;
}
__y_cut_ready_event(pg_event_running);
pg_event_running->next = NULL;
pg_event_running->previous = NULL;
//以下把pg_event_running加入到目标事件的同步队列中
pg_event_running->sync_head = &pl_ecb->sync;
if(pl_ecb->sync != NULL)
{//被同步事件的同步队列不是空的
pg_event_running->multi_next = pl_ecb->sync;
pg_event_running->multi_previous = pl_ecb->sync->multi_previous;
pl_ecb->sync->multi_previous->multi_next = pg_event_running;
pl_ecb->sync->multi_previous = pg_event_running;
}else
{//被同步事件的同步队列是空的
pl_ecb->sync = pg_event_running;
pg_event_running->multi_next = pg_event_running;
pg_event_running->multi_previous = pg_event_running;
}
pg_event_running->last_status.all = pg_event_running->event_status.all;
pg_event_running->event_status.bit.event_sync = 1;
if(timeout != cn_timeout_forever)
{
pg_event_running->event_status.bit.wait_overtime = 1;
__y_addto_delay((timeout + cn_tick_ms -1)/cn_tick_ms);
}
int_restore_asyn_signal(); //恢复中断会引发重新调度
int_save_asyn_signal();
//检查从哪里返回,是超时还是同步事件完成。
if(pg_event_running->event_status.bit.event_sync)
{//说明同步条件未到,从超时返回,应从目标事件的同步队列中取出事件。
//此时,被同步的事件肯定还没有完成。
pg_event_running->event_status.bit.event_sync = 0;
int_restore_asyn_signal();
return cn_sync_timeout;
}else
{
int_restore_asyn_signal();
return cn_sync_success;
}
}
//----事件类型完成同步----------------------------------------------------------
//功能: 把正在运行的事件加入到指定事件类型的前同步队列中去,然后重新调度。完成
// 同步以目标事件类型的完成次数为同步条件。
//参数: evtt_id,目标事件类型号
// done_times,完成次数,0表示待最后一条该类型事件完成.
// timeout,超时设置,单位是毫秒,cn_timeout_forever=无限等待,0则立即按
// 超时返回。非0值将被向上调整为cn_tick_ms的整数倍
//返回: cn_sync_success=同步条件成立返回,
// cn_sync_timeout=超时返回,
// cn_sync_error=出错,
// 本函数必须联系共享文档的相关章节才容易读懂,注释难于解释那么清楚的。
//----------------------------------------------------------------------------
uint32_t y_evtt_done_sync(uint16_t evtt_id,uint16_t done_times,uint32_t timeout)
{
struct event_type *evtt;
struct event_script *pl_ecb;
evtt = &tg_evtt_table[evtt_id];
if(y_query_sch() == false) //不能在禁止调度的情况下执行同步操作
return cn_sync_error;
if(timeout == 0)
return cn_sync_timeout;
int_save_asyn_signal();
if(evtt->property.registered == false)
{//该事件类型是无效事件类型
int_restore_asyn_signal();
return cn_sync_error;
}
__y_cut_ready_event(pg_event_running);
pg_event_running->next = NULL;
pg_event_running->previous = NULL;
pg_event_running->sync_counter = done_times;
//以下把pg_event_running加入到目标事件的同步队列中
pg_event_running->sync_head = &evtt->done_sync;
if(evtt->done_sync != NULL)
{//被同步事件类型的同步队列不是空的
pl_ecb = evtt->done_sync;
do
{//本循环找到第一个剩余完成次数不小于新事件的事件.
if(pl_ecb->sync_counter < done_times)
pl_ecb = pl_ecb->multi_next;
else
break;
}while(pl_ecb != evtt->done_sync);
//下面把新事件(pg_event_running)插入到队列中
pg_event_running->multi_next = pl_ecb;
pg_event_running->multi_previous = pl_ecb->multi_previous;
pl_ecb->multi_previous->multi_next = pg_event_running;
pl_ecb->multi_previous = pg_event_running;
if(evtt->done_sync->sync_counter > done_times)
evtt->done_sync = pg_event_running;
}else
{//被同步事件类型的同步队列是空的
evtt->done_sync = pg_event_running;
pg_event_running->multi_next = pg_event_running;
pg_event_running->multi_previous = pg_event_running;
}
pg_event_running->last_status.all = pg_event_running->event_status.all;
pg_event_running->event_status.bit.evtt_done_sync = 1;
if(timeout != cn_timeout_forever)
{
pg_event_running->event_status.bit.wait_overtime = 1;
__y_addto_delay((timeout + cn_tick_ms -1)/cn_tick_ms);
}
int_restore_asyn_signal(); //恢复调度会引发事件切换
int_save_asyn_signal();
//检查从哪里返回,是超时还是同步事件完成。
if(pg_event_running->event_status.bit.evtt_done_sync)
{//说明同步条件未到,从超时返回,应从目标事件的同步队列中取出事件。
//此时,被同步的事件肯定还没有完成。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -