⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lock.c

📁 新一代基于事件的嵌入式操作系统dyos在三星的s3c44b0的arm芯片上的完整移植代码
💻 C
📖 第 1 页 / 共 2 页
字号:
//----------------------------------------------------
//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 + -