完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
控制块
其除了名字等基本信息外还有PendList 链表与 Ctr 创建函数 OSSemCreate除去安全检测剩余部分如下 void OSSemCreate (OS_SEM *p_sem, //多值信号量控制块指针 CPU_CHAR *p_name, //多值信号量名称 OS_SEM_CTR cnt, //资源数目或事件是否发生标志 OS_ERR *p_err) //返回错误类型 { CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和定义一个局部变 //量,用于保存关中断前的 CPU 状态寄存器 SR(临界段关中断只需保存SR) //,开中断时将该值还原。 OS_CRITICAL_ENTER(); //进入临界段 p_sem->Type = OS_OBJ_TYPE_SEM; //初始化多值信号量指标 p_sem->Ctr = cnt; p_sem->TS = (CPU_TS)0; p_sem->NamePtr = p_name; OS_PendListInit(&p_sem->PendList); //初始化该多值信号量的等待列表 #if OS_CFG_DBG_EN > 0u //如果使能(默认使能)了调试代码和变量 OS_SemDbgListAdd(p_sem); //将该定时添加到多值信号量双向调试链表 #endif OSSemQty++; //多值信号量个数加1 OS_CRITICAL_EXIT_NO_SCHED(); //退出临界段(无调度) 信号量删除函数 OSSemDel除去安全检测剩余部分如下 #if OS_CFG_SEM_DEL_EN > 0u //如果使能了 OSSemDel() 函数 OS_OBJ_QTY OSSemDel (OS_SEM *p_sem, //多值信号量指针 OS_OPT opt, //选项 OS_ERR *p_err) //返回错误类型 { OS_OBJ_QTY cnt; OS_OBJ_QTY nbr_tasks; OS_PEND_DATA *p_pend_data; OS_PEND_LIST *p_pend_list; OS_TCB *p_tcb; CPU_TS ts; CPU_SR_ALLOC(); CPU_CRITICAL_ENTER(); //关中断 p_pend_list = &p_sem->PendList; //获取信号量的等待列表到 p_pend_list cnt = p_pend_list->NbrEntries; //获取等待该信号量的任务数 nbr_tasks = cnt; switch (opt) { //根据选项分类处理 case OS_OPT_DEL_NO_PEND: //如果只在没有任务等待的情况下删除信号量 if (nbr_tasks == (OS_OBJ_QTY)0) { //如果没有任务在等待该信号量 #if OS_CFG_DBG_EN > 0u //如果使能了调试代码和变量 OS_SemDbgListRemove(p_sem); //将该信号量从信号量调试列表移除 #endif OSSemQty--; //信号量数目减1 OS_SemClr(p_sem); //清除信号量内容 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_NONE; //返回错误类型为“无错误” } else { //如果有任务在等待该信号量 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_TASK_WAITING; //返回错误类型为“有任务在等待该信号量” } break; case OS_OPT_DEL_ALWAYS: //如果必须删除信号量 OS_CRITICAL_ENTER_CPU_EXIT(); //锁调度器,并开中断 ts = OS_TS_GET(); //获取时间戳 while (cnt > 0u) { //逐个移除该信号量等待列表中的任务 p_pend_data = p_pend_list->HeadPtr; p_tcb = p_pend_data->TCBPtr; OS_PendObjDel((OS_PEND_OBJ *)((void *)p_sem), p_tcb, ts); cnt--; } #if OS_CFG_DBG_EN > 0u //如果使能了调试代码和变量 OS_SemDbgListRemove(p_sem); //将该信号量从信号量调试列表移除 #endif OSSemQty--; //信号量数目减1 OS_SemClr(p_sem); //清除信号量内容 OS_CRITICAL_EXIT_NO_SCHED(); //减锁调度器,但不进行调度 OSSched(); //任务调度,执行最高优先级的就绪任务 *p_err = OS_ERR_NONE; //返回错误类型为“无错误” break; default: //如果选项超出预期 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_OPT_INVALID; //返回错误类型为“选项非法” break; } return ((OS_OBJ_QTY)nbr_tasks); //返回删除信号量前等待其的任务数 } #endif 信号量释放函数 信号量的释放可以在任务、中断中使用。OSSemPost去安全检测如下 OS_SEM_CTR OSSemPost (OS_SEM *p_sem, //多值信号量控制块指针 OS_OPT opt, //选项 OS_ERR *p_err) //返回错误类型 { OS_SEM_CTR ctr; CPU_TS ts; ts = OS_TS_GET(); //获取时间戳 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u //如果使能了中断延迟发布 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { //如果该函数是在中断中被调用 OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_SEM, //将该信号量发布到中断消息队列 (void *)p_sem, (void *)0, (OS_MSG_SIZE)0, (OS_FLAGS )0, (OS_OPT )opt, (CPU_TS )ts, (OS_ERR *)p_err); return ((OS_SEM_CTR)0); //返回0(尚未发布),不继续执行 } #endif ctr = OS_SemPost(p_sem, //将信号量按照普通方式处理 opt, ts, p_err); return (ctr); //返回信号的当前计数值 } 当信号量不特殊时,将信号量按照普通方式处用OS_SemPost OS_SEM_CTR OS_SemPost (OS_SEM *p_sem, //多值信号量指针 OS_OPT opt, //选项 CPU_TS ts, //时间戳 OS_ERR *p_err) //返回错误类型 { OS_OBJ_QTY cnt; OS_SEM_CTR ctr; OS_PEND_LIST *p_pend_list; OS_PEND_DATA *p_pend_data; OS_PEND_DATA *p_pend_data_next; OS_TCB *p_tcb; CPU_SR_ALLOC(); CPU_CRITICAL_ENTER(); //关中断 p_pend_list = &p_sem->PendList; //取出该信号量的等待列表 if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) { //如果没有任务在等待该信号量 switch (sizeof(OS_SEM_CTR)) { //判断是否将导致该信号量计数值溢出, case 1u: //如果溢出,则开中断,返回错误类型为 if (p_sem->Ctr == DEF_INT_08U_MAX_VAL) { //“计数值溢出”,返回0(有错误), CPU_CRITICAL_EXIT(); //不继续执行。 *p_err = OS_ERR_SEM_OVF; return ((OS_SEM_CTR)0); } break; case 2u: if (p_sem->Ctr == DEF_INT_16U_MAX_VAL) { CPU_CRITICAL_EXIT(); *p_err = OS_ERR_SEM_OVF; return ((OS_SEM_CTR)0); } break; case 4u: if (p_sem->Ctr == DEF_INT_32U_MAX_VAL) { CPU_CRITICAL_EXIT(); *p_err = OS_ERR_SEM_OVF; return ((OS_SEM_CTR)0); } break; default: break; } p_sem->Ctr++; //信号量计数值不溢出则加1 ctr = p_sem->Ctr; //获取信号量计数值到 ctr p_sem->TS = ts; //保存时间戳 CPU_CRITICAL_EXIT(); //则开中断 *p_err = OS_ERR_NONE; //返回错误类型为“无错误” return (ctr); //返回信号量的计数值,不继续执行 } OS_CRITICAL_ENTER_CPU_EXIT(); //加锁调度器,但开中断 if ((opt & OS_OPT_POST_ALL) != (OS_OPT)0) { //如果要将信号量发布给所有等待任务 cnt = p_pend_list->NbrEntries; //获取等待任务数目到 cnt } else { //如果要将信号量发布给优先级最高的等待任务 cnt = (OS_OBJ_QTY)1; //将要操作的任务数为1,cnt 置1 } p_pend_data = p_pend_list->HeadPtr; //获取等待列表的首个任务到 p_pend_data while (cnt > 0u) { //逐个处理要发布的任务 p_tcb = p_pend_data->TCBPtr; //取出当前任务 p_pend_data_next = p_pend_data->NextPtr; //取出下一个任务 OS_Post((OS_PEND_OBJ *)((void *)p_sem), //发布信号量给当前任务 p_tcb, (void *)0, (OS_MSG_SIZE)0, ts); p_pend_data = p_pend_data_next; //处理下一个任务 cnt--; } ctr = p_sem->Ctr; //获取信号量计数值到 ctr OS_CRITICAL_EXIT_NO_SCHED(); //减锁调度器,但不执行任务调度 if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) { //如果 opt 没选择“发布时不调度任务” OSSched(); //任务调度 } *p_err = OS_ERR_NONE; //返回错误类型为“无错误” return (ctr); //返回信号量的当前计数值 } 有信号量发布就有信号量获取OSSemPend,去除安全检测 OS_SEM_CTR OSSemPend (OS_SEM *p_sem, //多值信号量指针 OS_TICK timeout, //等待超时时间 OS_OPT opt, //选项 CPU_TS *p_ts, //等到信号量时的时间戳 OS_ERR *p_err) //返回错误类型 { OS_SEM_CTR ctr; OS_PEND_DATA pend_data; CPU_SR_ALLOC(); if (p_ts != (CPU_TS *)0) { //如果 p_ts 非空 *p_ts = (CPU_TS)0; //初始化(清零)p_ts,待用于返回时间戳 } CPU_CRITICAL_ENTER(); //关中断 if (p_sem->Ctr > (OS_SEM_CTR)0) { //如果资源可用 p_sem->Ctr--; //资源数目减1 if (p_ts != (CPU_TS *)0) { //如果 p_ts 非空 *p_ts = p_sem->TS; //获取该信号量最后一次发布的时间戳 } ctr = p_sem->Ctr; //获取信号量的当前资源数目 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_NONE; //返回错误类型为“无错误” return (ctr); //返回信号量的当前资源数目,不继续执行 } if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { //如果没有资源可用,而且选择了不堵塞任务 ctr = p_sem->Ctr; //获取信号量的资源数目到 ctr CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_PEND_WOULD_BLOCK; //返回错误类型为“等待渴求堵塞” return (ctr); //返回信号量的当前资源数目,不继续执行 } else { //如果没有资源可用,但选择了堵塞任务 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { //如果调度器被锁 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_SCHED_LOCKED; //返回错误类型为“调度器被锁” return ((OS_SEM_CTR)0); //返回0(有错误),不继续执行 } } OS_CRITICAL_ENTER_CPU_EXIT(); //锁调度器,并重开中断 OS_Pend(&pend_data, //堵塞等待任务,将当前任务脱离就绪列表, (OS_PEND_OBJ *)((void *)p_sem), //并插入到节拍列表和等待列表。 OS_TASK_PEND_ON_SEM, timeout); OS_CRITICAL_EXIT_NO_SCHED(); //开调度器,但不进行调度 OSSched(); //找到并调度最高优先级就绪任务 /* 当前任务(获得信号量)得以继续运行 */ CPU_CRITICAL_ENTER(); //关中断 switch (OSTCBCurPtr->PendStatus) { //根据当前运行任务的等待状态分类处理 case OS_STATUS_PEND_OK: //如果等待状态正常 if (p_ts != (CPU_TS *)0) { //如果 p_ts 非空 *p_ts = OSTCBCurPtr->TS; //获取信号被发布的时间戳 } *p_err = OS_ERR_NONE; //返回错误类型为“无错误” break; case OS_STATUS_PEND_ABORT: //如果等待被终止中止 if (p_ts != (CPU_TS *)0) { //如果 p_ts 非空 *p_ts = OSTCBCurPtr->TS; //获取等待被中止的时间戳 } *p_err = OS_ERR_PEND_ABORT; //返回错误类型为“等待被中止” break; case OS_STATUS_PEND_TIMEOUT: //如果等待超时 if (p_ts != (CPU_TS *)0) { //如果 p_ts 非空 *p_ts = (CPU_TS )0; //清零 p_ts } *p_err = OS_ERR_TIMEOUT; //返回错误类型为“等待超时” break; case OS_STATUS_PEND_DEL: //如果等待的内核对象被删除 if (p_ts != (CPU_TS *)0) { //如果 p_ts 非空 *p_ts = OSTCBCurPtr->TS; //获取内核对象被删除的时间戳 } *p_err = OS_ERR_OBJ_DEL; //返回错误类型为“等待对象被删除” break; default: //如果等待状态超出预期 *p_err = OS_ERR_STATUS_INVALID; //返回错误类型为“等待状态非法” CPU_CRITICAL_EXIT(); //开中断 return ((OS_SEM_CTR)0); //返回0(有错误),不继续执行 } ctr = p_sem->Ctr; //获取信号量的当前资源数目 CPU_CRITICAL_EXIT(); //开中断 return (ctr); //返回信号量的当前资源数目 } |
|
|
|
只有小组成员才能发言,加入小组>>
3319 浏览 9 评论
2997 浏览 16 评论
3495 浏览 1 评论
9065 浏览 16 评论
4088 浏览 18 评论
1185浏览 3评论
611浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
601浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2337浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1898浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-25 23:32 , Processed in 1.091666 second(s), Total 50, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号