📄 sem.c
字号:
#if !defined(__EBOS_H)
#include "ebos.h"
#endif
/*
*********************************************************************************************************
* sem module implement FILE
*********************************************************************************************************
*/
static SEM_SCB *SemTable[MAX_SEM_NUM]; //信号灯向量表
static void CleanupSem(void *information);///信号灯清除函数
static SEM_SCB * SemFreeList; //可用信号灯列表
/*
*********************************************************************************************************
* 获得一个可用的ID号
*********************************************************************************************************
*/
static SIGNED _NewSemId()
{
static UNSIGNED Next_ID;
UNSIGNED id; /* process id to return */
EnLock();
if ( (id=Next_ID++) <MAX_SEM_NUM){
if (SemTable[id] == NULL){
UnLock();
return(id);
}
}
else if(SemFreeList){
id=SemFreeList->id;
#if ENABLE_MEM
FreeBuff(SemFreeList);
#endif
SemFreeList=SemFreeList->next;
UnLock();
return(id);
}
UnLock();
return(NO_SEM_SPACE);
}
/*
*********************************************************************************************************
* 创建一个信号灯
*********************************************************************************************************
*/
#if ENABLE_MEM
SIGNED CreateSem(UNSIGNED initial_count)
#else
SIGNED CreateSem(SEM_SCB *sem_ptr,UNSIGNED initial_count)
#endif
{
SIGNED sem_id;
STATUS err;
#if ENABLE_MEM
SEM_SCB *sem_ptr;
#endif
sem_id=_NewSemId();
if (sem_id<0)
return (sem_id);
#if ENABLE_MEM
err=AllocBuff(KERNAL.event_pool,&(void *)sem_ptr,-1);
if(err!=OK)
return (ERR_NO_MEMORY);
#else
if (sem_ptr==NULL) return(ERR_INVALID_SEM);
else if(SemTable[sem_ptr->id]==sem_ptr) return (sem_ptr->id);
#endif
#if DEBUG
DebugLog(CREATE_SEM,sem_ptr->sem_id);//在日志中记录操作,时间等信息
#endif
SemTable[sem_id]=sem_ptr;
sem_ptr->id=sem_id;
sem_ptr->current_protect=NULL;
sem_ptr->suspend_type=FIFO;
sem_ptr->sem_count=initial_count;
sem_ptr->task_wait_header=NULL;
return(sem_id);
}
/*
*********************************************************************************************************
* Del A sem
*********************************************************************************************************
*/
STATUS DelSem(SIGNED sem_id)
{
STATUS state,oldstate;
SEM_SCB *sem_ptr;
if (sem_id<0 ||sem_id<0 || sem_id >MAX_SEM_NUM) { /* Not allowed to Del idle task */
return (ERR_INVALID_SEM);
}
sem_ptr=SemTable[sem_id];
#if DEBUG
DebugLog(DELETE_SEM,sem_id);//在日志中记录操作,时间等信息
#endif
DoProtect(sem_ptr);
if (sem_ptr == NULL) /* Not allowed to Del idle sem */
return (ERR_INVALID_SEM);
while(sem_ptr->task_wait_header){
state=_ResumeTask(sem_ptr->task_wait_header->task_ptr,EVENT_SUSPEND);
if(state==TRUE)
oldstate =state;
DelHead(&(void *)(sem_ptr->task_wait_header));
}
#if ENABLE_MEM
FreeBuff(sem_ptr);
#endif
UnProtect(sem_ptr);
EnLock();
sem_ptr->next=SemFreeList;
SemFreeList=sem_ptr;
SemTable[sem_id]=NULL;
UnLock();
if(oldstate==TRUE)
_ControlToSystem();
return (OK);
}
/*
*********************************************************************************************************
* 信号灯参数设置函数
*********************************************************************************************************
*/
STATUS SysSemCtl(SIGNED sem_id,INT8U cmd,INT8U param)
{
STATUS ret;
SEM_SCB *sem_ptr;
if (sem_id<0 || sem_id >MAX_SEM_NUM) { /* Not allowed to Del idle task */
return (ERR_INVALID_SEM);
}
sem_ptr=SemTable[sem_id];
#if DEBUG
DebugLog(SYS_SEM_CTL,sem_id);//在日志中记录操作,时间等信息
#endif
DoProtect(sem_ptr);
if (sem_ptr == NULL) {
return (ERR_INVALID_TASK); /* Not allowed is idle task */
}
switch(cmd){
case SUSPEND_TYPE:
sem_ptr->suspend_type=param;
ret=OK;
break;
default:
ret=ERR_INVALID_CMD;
break;
}
UnProtect(sem_ptr);
return(ret);
}
/*
*********************************************************************************************************
* 信号灯的V操作,信号灯计数值加1,若有等待的任务,则恢复任务
*********************************************************************************************************
*/
STATUS ReleaseSem(SIGNED sem_id)
{
TASK_TCB *task_ptr;
STATUS status;
SEM_SCB *sem_ptr;
if (sem_id<0 || sem_id >MAX_SEM_NUM) { /* Not allowed to Del idle task */
return (ERR_INVALID_SEM);
}
sem_ptr=SemTable[sem_id];
#if DEBUG
DebugLog(RELEASE_SEM,sem_id);//在日志中记录操作,时间等信息
#endif
DoProtect(sem_ptr);
if (sem_ptr == NULL) { /* Not allowed to Del idle sem */
return (ERR_INVALID_SEM);
}
if((sem_ptr->sem_count++)<0){//有任务等待信号灯释放,恢复任务
task_ptr=(sem_ptr->task_wait_header)->task_ptr;
sem_ptr->task_wait_header->sem_return_status=FINISHED;
DelHead(&(void *)(sem_ptr->task_wait_header));
UnProtect(sem_ptr);
status=_ResumeTask(task_ptr,EVENT_SUSPEND);
if (status==TRUE)
_ControlToSystem();
return (OK);
}
UnProtect(sem_ptr);
return (OK);
}
/*
*********************************************************************************************************
* 信号灯的PV操作,信号灯计数值减1,若小于0,任务挂起
*********************************************************************************************************
*/
STATUS ObtainSem(SIGNED sem_id, SIGNED suspend)
{
WAIT_QUEUE *task_suspend;
TASK_TCB *task_ptr;
STATUS status;
SEM_SCB *sem_ptr;
#if WAIT_QUEUE_ALLOC_MODE
WAIT_QUEUE sem_wait_queue;
task_suspend=&sem_wait_queue;
#else
task_suspend=WaitQueueFreeList;
WaitQueueFreeList=WaitQueueFreeList->queue_ptr;
#endif
if (sem_id<0 || sem_id >MAX_SEM_NUM) { /* Not allowed to Del idle task */
return (ERR_INVALID_SEM);
}
sem_ptr=SemTable[sem_id];
#if DEBUG
DebugLog(OBTAIN_SEM,sem_id);//在日志中记录操作,时间等信息
#endif
DoProtect(sem_ptr);
if (sem_ptr == NULL) /* Not allowed to Del idle sem */
return (ERR_INVALID_SEM);
if(--(sem_ptr->sem_count)<0){ //不能得到信号灯
if(suspend ==SUSPEND){//任务挂起
if (((TASK_TCB *)KERNAL.current_thread)->type!=TASK){
UnProtect(sem_ptr);
return(ERR_INVALID_SUSPEND);
}
task_suspend->task_ptr=((TASK_TCB *)KERNAL.current_thread);
task_suspend->priority=GetPriority(((TASK_TCB *)KERNAL.current_thread)->id);
AddList(&(void *)(sem_ptr->task_wait_header),task_suspend,sem_ptr->suspend_type);
UnProtect(sem_ptr);
_SuspendTask(KERNAL.current_thread,EVENT_SUSPEND,CleanupSem,sem_ptr,suspend);
_ControlToSystem();
Enlock();
#if WAIT_QUEUE_ALLOC_MODE
task_suspend->queue_ptr=WaitQueueFreeList;
WaitQueueFreeList=task_suspend;
#endif
if(sem_ptr==NULL) {
Unlock();
return(ERR_SEM_DELETED);
}
if (task_suspend->sem_return_status!=FINISHED){
Unlock();
return(ERR_TIMEOUT);
}
Unlock();
return (OK);
}
else{
UnProtect(sem_ptr);
return (ERR_UNAVAILABLE);
}
}
UnProtect(sem_ptr);
return (OK);
}
/*
*********************************************************************************************************
* 在一个信号灯上的等待列表上的某个任务恢复或删除时,清除相应等待列表上的项
*********************************************************************************************************
*/
static void CleanupSem(void *information)
{
SEM_SCB *sem_ptr;
TASK_TCB *task_ptr;
WAIT_QUEUE *linknode;
sem_ptr=(SEM_SCB *)information;
UnProtect(sem_ptr);
EnLock();
linknode=sem_ptr->task_wait_header;
do{
task_ptr=linknode->task_ptr;
if (task_ptr==((TASK_TCB *)KERNAL.current_thread)){
sem_ptr->sem_count++;
DelList(&(void *)(sem_ptr->task_wait_header),linknode);
#if WAIT_QUEUE_ALLOC_MODE
linknode->queue_ptr=WaitQueueFreeList;
WaitQueueFreeList=linknode;
#endif
}
linknode=(WAIT_QUEUE *)(linknode->next);
if (linknode==NULL)
break;
}while(linknode!=sem_ptr->task_wait_header);
UnLock();
}
/*
*********************************************************************************************************
* 获得信号灯的计数值
*********************************************************************************************************
*/
INT8 SemCount(SIGNED sem_id,INT8 *err)
{
SEM_SCB *sem_ptr;
if (sem_id<0 || sem_id >MAX_SEM_NUM) { /* Not allowed to Del idle task */
*err=ERR_INVALID_SEM;
return (-1);
}
sem_ptr=SemTable[sem_id];
if (sem_ptr == NULL) { /* Not allowed to Del idle task */
*err=ERR_INVALID_SEM;
return (-1);
}
*err=OK;
return (sem_ptr->sem_count);
}
/*
*********************************************************************************************************
* 列出系统中存在的信号灯信息
*********************************************************************************************************
*/
STATUS ListSem(SIGNED sem_id,SEM_DATA ** sem_lst)
{
SEM_SCB *sem_ptr;
UNSIGNED i;
if (sem_id+1<0 || sem_id >MAX_SEM_NUM) { /* Not allowed to Del idle task */
return (ERR_INVALID_SEM);
}
if(sem_id>=0){
sem_ptr=SemTable[sem_id];
DoProtect(sem_ptr);
if (sem_ptr == NULL) /* Not allowed to Del idle task */
return (ERR_INVALID_SEM);
(*sem_lst)->current_count= sem_ptr->sem_count;
(*sem_lst)->suspend_type=sem_ptr->suspend_type;
(*sem_lst)->task_id=(sem_ptr->task_wait_header)->task_ptr->id;
UnProtect(sem_ptr);
return (OK);
}
else{
for(i=0;i<MAX_SEM_NUM;i++){
sem_ptr=SemTable[i];
DoProtect(sem_ptr);
if (sem_ptr){ /* Not allowed to Del idle task */
(*sem_lst)->current_count= sem_ptr->sem_count;
(*sem_lst)->suspend_type=sem_ptr->suspend_type;
(*sem_lst)->task_id=(sem_ptr->task_wait_header)->task_ptr->id;
sem_lst++;
}
UnProtect(sem_ptr);
}
return (OK);
}
}
/*
*********************************************************************************************************
* 信号灯模块的初始化
*********************************************************************************************************
*/
void SemInit(void)
{
UNSIGNED i;
for(i=0;i<MAX_SEM_NUM;i++)
SemTable[i]=NULL;
}
/*
*********************************************************************************************************
* This function resets a sem back to the initial state.
*********************************************************************************************************
*/
STATUS ResetSem(SIGNED sem_id,UNSIGNED initial_count)
{
WAIT_QUEUE *linknode;
STATUS oldstate,state;
SEM_SCB *sem_ptr;
if (sem_id<0 || sem_id >MAX_SEM_NUM) { /* Not allowed to Del idle task */
return (ERR_INVALID_SEM);
}
sem_ptr=SemTable[sem_id];
#if DEBUG
DebugLog(RESET_SEM,sem_id);//在日志中记录操作,时间等信息
#endif
oldstate=0;
DoProtect(sem_ptr);
if (sem_ptr == NULL) /* Not allowed to Del idle task */
return (ERR_INVALID_SEM);
sem_ptr->sem_count=initial_count;
while(sem_ptr->task_wait_header){
state=_ResumeTask(sem_ptr->task_wait_header->task_ptr,EVENT_SUSPEND);
if(state==TRUE)
oldstate =state;
DelHead(&(void *)(sem_ptr->task_wait_header));
}
UnProtect(sem_ptr);
if(oldstate==TRUE)
_ControlToSystem();
return (OK);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -