📄 lock.c
字号:
//----------------------------------------------------
//Copyright (C), 2004-2009, lst.
//版权所有 (C), 2004-2009, lst.
//所属模块: 锁模块
//作者:lst
//版本:V1.0.0
//文件描述: 包含信号量和互斥量
//其他说明:
//修订历史:
// 2. ...
// 1. 日期:
// 作者:
// 新版本号:
// 修改说明:
//------------------------------------------------------
#include "inc_os.h"
static struct semaphore_LCB *pg_semaphore_rsc=NULL;
static struct mutex_LCB *pg_mutex_rsc=NULL;
//说明: cn_locks_limit 是用户配置的,由于用户并不知道操作系统需要用多少信号量,
// 所以操作系统并不占用 cn_locks_limit 指标,用户使用的信号量从
// tg_semp_pool定义的内存池中分配,操作系统使用的信号量自己定义,两不
// 相关,如果用户企图调用 semp_delete 删除操作系统定义的信号量,将引起造成
// 内存泄漏,而且相关操作系统资源也将失去信号量保护,后果不可预料
//定义信号量结构初始内存池
static union lock_MCB tg_lock_mem_block[cn_locks_limit];
static struct mem_cell_pool *pg_lock_pool; //信号量结构内存池头指针
//----初始化锁模块模块step1----------------------------------------------------
//功能:初始化信号量模块的第一步,此后可以调用除semp_create和mutex_createe以外的
// 其他函数,包括__semp_create_knl和__mutex_createe_knl,该两函数被禁止是因
// 为module_init_memb还没有调用,又因mudule_init_memb需要使用信号量,故只能
// 在module_init_lock1后面调用。
//参数:无
//返回:无
//-----------------------------------------------------------------------------
bool_t module_init_lock1(void)
{
static struct semaphore_LCB semp_root;
static struct mutex_LCB mutex_root;
pg_semaphore_rsc = (struct semaphore_LCB*)
rsc_add_lock_root_node(&semp_root.node,sizeof(union lock_MCB),"semaphore");
pg_mutex_rsc = (struct mutex_LCB*)
rsc_add_lock_root_node(&mutex_root.node,sizeof(union lock_MCB),"mutex");
return true;
}
//----初始化锁模块模块step2----------------------------------------------------
//功能:初始化信号量模块的第二步,此后可以调用含semp_create和mutex_createe在内的
// 所有锁函数了
//参数:无
//返回:无
//-----------------------------------------------------------------------------
bool_t module_init_lock2(void)
{
static struct mem_cell_pool lock_pool;
//初始化锁控制块内存池
pg_lock_pool = __mb_create_knl( &lock_pool,
(void*)tg_lock_mem_block,
cn_locks_limit,
sizeof(union lock_MCB),
"锁控制块池");
return true;
}
//----创建一个信号量-----------------------------------------------------------
//功能:建立一个信号量,以后就可以使用这个信号量了。
//参数:semp_limit,信号灯的总数,0=有无限多的信号灯。
// init_lamp,初始信号灯数量
// name,信号量的名字
//返回:新建立的信号量指针
//-----------------------------------------------------------------------------
struct semaphore_LCB *semp_create(uint32_t lamps_limit,
uint32_t init_lamp,char *name)
{
struct semaphore_LCB *semp;
if(init_lamp > lamps_limit)
return NULL;
semp = mb_malloc(pg_lock_pool,0);
if(semp == NULL)
return NULL;
semp->lamps_limit = lamps_limit;
semp->lamp_counter = init_lamp;
semp->lamp_used = 0;
semp->semp_sync = NULL;
//把新节点挂到信号量根节点下
rsc_add_son(&pg_semaphore_rsc->node,&semp->node,
sizeof(struct semaphore_LCB),name);
return semp;
}
//----创建一个内核信号量-------------------------------------------------------
//功能:与semp_create的区别是,本函数需要调用者提供semp实体,而不是从池中分配。
// 因为cn_locks_limit是用户定义的,如果内核也与应用程序共享的话,将使内核
// 与应用程序发生耦合。
//参数:semp,目标信号量指针
// semp_limit,信号灯的总数,0=有无限多的信号灯。
// init_lamp,初始信号灯数量
// name,信号量的名字
//返回:新建立的信号量指针
//-----------------------------------------------------------------------------
void __semp_create_knl( struct semaphore_LCB *semp,
uint32_t lamps_limit,uint32_t init_lamp,char *name)
{
semp->lamps_limit = lamps_limit;
semp->lamp_counter = init_lamp;
semp->lamp_used = 0;
semp->semp_sync = NULL;
//把新节点挂到信号量根节点下
rsc_add_son(&pg_semaphore_rsc->node,&semp->node,
sizeof(struct semaphore_LCB),name);
}
//----点亮一个信号灯------------------------------------------------------------
//功能:点亮一盏信号灯,表示可用资源数加1。
//参数:semp,信号量指针
//返回:无
//-----------------------------------------------------------------------------
void semp_post(struct semaphore_LCB *semp)
{
struct event_script *event;
if(semp == NULL)
return;
int_save_asyn_signal();
semp->lamp_used--;
if(semp->semp_sync == NULL) //等待队列空,点亮一盏信号灯
{
if(semp->lamps_limit == 0) //信号灯数量不限
{
if(semp->lamp_counter != cn_limit_uint32) //信号灯数量未到上限
semp->lamp_counter ++; //点亮一盏信号灯
}else if(semp->lamp_counter < semp->lamps_limit )//信号灯数量未到上限
semp->lamp_counter++; //点亮一盏信号灯
} else //有事件在等待,把信号灯直接转交给队列中优先级最高的事件
{
event = semp->semp_sync;
event->sync_head = NULL;
if(event->multi_next == event)
{//队列中只有一个事件
semp->semp_sync = NULL;
}else
{//队列中有多个事件,取出队列头部的事件
semp->semp_sync = event->multi_next;
event->multi_next->multi_previous = event->multi_previous;
event->multi_previous->multi_next = event->multi_next;
event->multi_next = NULL;
event->multi_previous = NULL;
}
if(event->event_status.bit.wait_overtime)
__y_resume_delay(event); //如果事件在超时等待队列中,取出
event->event_status.bit.wait_overtime = 0;
event->last_status.all = event->event_status.all;//备份事件状态
event->event_status.bit.wait_semp = 0; //清除等待状态
__y_event_ready(event);
}
int_restore_asyn_signal();
}
//----请求一盏信号灯-----------------------------------------------------------
//功能:请求然后熄灭一盏信号灯,表示可用资源数减1。
//参数:semp,信号量指针
// timeout,超时设置,单位是毫秒,cn_timeout_forever=无限等待,0则立即按
// 超时返回。非0值将被向上调整为cn_tick_ms的整数倍
//返回:true=取得信号返回或资源不受信号灯保护(semp == NULL),semp==NULL时返回
// true是有意义的,如果你希望代码在不管是否受信号灯保护都保持一致,把semp
// 设为NULL是明智的选择,比如你要构建一个不受信号灯保护的设备,可把该设备
// struct pan_device的semp成员设为NULL。
// false=没有取得信号(超时返回或其他原因)
//-----------------------------------------------------------------------------
bool_t semp_pend(struct semaphore_LCB *semp,uint32_t timeout)
{
struct event_script *event;
bool_t lamp;
if(semp == NULL)
return true;
int_save_asyn_signal(); //以下读取信号灯数量,必须保证原子操作,故关中断
semp->lamp_used ++;
if(semp->lamps_limit == 0) //本信号量有无限多信号灯
{
if(semp->lamp_counter != 0) //信号灯数量不为0
semp->lamp_counter--; //熄灭一盏信号灯
lamp = true;
}else //本信号量的信号灯数量有限
{
if(semp->lamp_counter > 0) //有点亮的信号灯
{
lamp = true; //标记资源可用
semp->lamp_counter--; //熄灭一盏信号灯
}else //没有点亮的信号灯
lamp = false; //标记资源不可用
}
int_restore_asyn_signal();
if(lamp == true)
return true; //取得信号灯返回
else if(!y_query_sch() || (timeout == 0))//禁止调度时,不能阻塞.或timeout为0
return false; //没有取得信号灯返回
int_save_asyn_signal();
__y_cut_ready_event(pg_event_running);
pg_event_running->previous = NULL;
pg_event_running->next = NULL;
pg_event_running->sync_head = &semp->semp_sync;
if(semp->semp_sync == NULL)
{//同步队列空,running事件自成双向循环链表
pg_event_running->multi_next = pg_event_running;
pg_event_running->multi_previous = pg_event_running;
semp->semp_sync = pg_event_running;
}else
{//同步队列非空,按优先级排序
event = semp->semp_sync;
do
{ //找到一个优先级低于新事件的事件.
if(event->prio <= pg_event_running->prio)
event = event->multi_next;
else
break;
}while(event != semp->semp_sync);
pg_event_running->multi_next = event;
pg_event_running->multi_previous = event->multi_previous;
event->multi_previous->multi_next = pg_event_running;
event->multi_previous = pg_event_running;
if(semp->semp_sync->prio > pg_event_running->prio)
semp->semp_sync = semp->semp_sync->multi_previous;
}
pg_event_running->last_status.all =pg_event_running->event_status.all;
pg_event_running->event_status.bit.wait_semp = 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.wait_semp)
{//说明同步条件未到,从超时返回,应从目标事件的同步队列中取出事件。
//此时,被同步的事件肯定还没有完成。
pg_event_running->event_status.bit.wait_semp = 0;
int_restore_asyn_signal();
return false;
}else
{//说明是得到信号量返回
int_restore_asyn_signal();
return true;
}
}
//----删除一个信号量-----------------------------------------------------------
//功能:删除一个信号量
//参数:semp,被删除的信号量
//返回:无
//-----------------------------------------------------------------------------
bool_t semp_delete(struct semaphore_LCB *semp)
{
if(semp == NULL) //参数错误
return false;
if(semp->semp_sync != NULL) //没有事件在等待信号灯
{
rsc_del_node(&semp->node); //删除信号量结点
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -