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

📄 sem.c

📁 一种操作系统源码核
💻 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 + -