对于函数OSSemPend来说,会使当前TCB挂起,ECB中的EventWaitList置位,TCB中的事件等待指针指向相应的ECB
那么对于OSSemPost函数来说,就应该解除ECB中的EventWaitList置位,然后修改TCB,使相应的task进入rdy状态
- /*
- *********************************************************************************************************
- * POST TO A SEMAPHORE
- *
- * Description: This function signals a semaphore
- *
- * Arguments : pevent is a pointer to the event control block associated with the desired
- * semaphore.
- *
- * Returns : OS_NO_ERR The call was successful and the semaphore was signaled.
- * OS_SEM_OVF If the semaphore count exceeded its limit. In other words, you have
- * signalled the semaphore more often than you waited on it with either
- * OSSemAccept() or OSSemPend().
- * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
- * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
- *********************************************************************************************************
- */
- INT8U OSSemPost (OS_EVENT *pevent)
- {
- #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0;
- #endif
- #if OS_ARG_CHK_EN > 0
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- return (OS_ERR_PEVENT_NULL);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
- return (OS_ERR_EVENT_TYPE);
- }
- OS_ENTER_CRITICAL();
- if (pevent->OSEventGrp != 0) { /* See if any task waiting for semaphore*/
- (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); /* Ready HPT waiting on event */
- OS_EXIT_CRITICAL();
- OS_Sched(); /* Find HPT ready to run */
- return (OS_NO_ERR);
- }
- if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow */
- pevent->OSEventCnt++; /* Increment semaphore count to register event */
- OS_EXIT_CRITICAL();
- return (OS_NO_ERR);
- }
- OS_EXIT_CRITICAL(); /* Semaphore value has reached its maximum */
- return (OS_SEM_OVF);
- }
参数是ECB指针,对这个ECB输入一个信号量
首先检测ECB指针是否为空
检测type是否是信号量
关中断,
检测EWL是否为0,如果为0,说明没有任务在等待信号量,cnt++并且返回NO_ERR
如果不为零检测最高优先级的任务并使任务得到信号量,函数OS_EventTaskRdy
- /*
- *********************************************************************************************************
- * MAKE TASK READY TO RUN BASED ON EVENT OCCURING
- *
- * Description: This function is called by other uC/OS-II services and is used to ready a task that was
- * waiting for an event to occur.
- *
- * Arguments : pevent is a pointer to the event control block corresponding to the event.
- *
- * msg is a pointer to a message. This pointer is used by message oriented services
- * such as MAILBOXEs and QUEUEs. The pointer is not used when called by other
- * service functions.
- *
- * msk is a mask that is used to clear the status byte of the TCB. For example,
- * OSSemPost() will pass OS_STAT_SEM, OSMboxPost() will pass OS_STAT_MBOX etc.
- *
- * Returns : none
- *
- * Note : This function is INTERNAL to uC/OS-II and your application should not call it.
- *********************************************************************************************************
- */
- #if OS_EVENT_EN
- INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk)
- {
- OS_TCB *ptcb;
- INT8U x;
- INT8U y;
- INT8U prio;
- #if OS_LOWEST_PRIO <= 63
- INT8U bitx;
- INT8U bity;
- #else
- INT16U bitx;
- INT16U bity;
- INT16U *ptbl;
- #endif
- #if OS_LOWEST_PRIO <= 63
- y = OSUnMapTbl[pevent->OSEventGrp]; /* Find HPT waiting for message */
- bity = (INT8U)(1 << y);
- x = OSUnMapTbl[pevent->OSEventTbl[y]];
- bitx = (INT8U)(1 << x);
- prio = (INT8U)((y << 3) + x); /* Find priority of task getting the msg */
- #else
- if ((pevent->OSEventGrp & 0xFF) != 0) { /* Find HPT waiting for message */
- y = OSUnMapTbl[pevent->OSEventGrp & 0xFF];
- } else {
- y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF] + 8;
- }
- bity = (INT16U)(1 << y);
- ptbl = &pevent->OSEventTbl[y];
- if ((*ptbl & 0xFF) != 0) {
- x = OSUnMapTbl[*ptbl & 0xFF];
- } else {
- x = OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8;
- }
- bitx = (INT16U)(1 << x);
- prio = (INT8U)((y << 4) + x); /* Find priority of task getting the msg */
- #endif
- pevent->OSEventTbl[y] &= ~bitx; /* Remove this task from the waiting list */
- if (pevent->OSEventTbl[y] == 0) {
- pevent->OSEventGrp &= ~bity; /* Clr group bit if this was only task pending */
- }
- ptcb = OSTCBPrioTbl[prio]; /* Point to this task's OS_TCB */
- ptcb->OSTCBDly = 0; /* Prevent OSTimeTick() from readying task */
- ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* Unlink ECB from this task */
- #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
- ptcb->OSTCBMsg = msg; /* Send message directly to waiting task */
- #else
- msg = msg; /* Prevent compiler warning if not used */
- #endif
- ptcb->OSTCBPendTO = OS_FALSE; /* Cancel 'any' timeout because of post */
- ptcb->OSTCBStat &= ~msk; /* Clear bit associated with event type */
- if (ptcb->OSTCBStat == OS_STAT_RDY) { /* See if task is ready (could be susp'd) */
- OSRdyGrp |= bity; /* Put task in the ready to run list */
- OSRdyTbl[y] |= bitx;
- }
- return (prio);
- }
- #endif
这个函数有三个参数,第一个是ECB,第二个是指向信号内容的指针,只在信号是消息邮箱或者消息队列的时候才有用,第三个是TCB中的stat信号
木有返回值
第一步,通过EWL查找到最高优先级等待任务,求出其优先级prio
第二步,将这个task从EWL中移除
第三步。找到这个prio的TCB,并将其中的delaytime置0,将event连接指针指向NULL
第四步,如果是消息邮箱,消息队列,那么将msg赋值给TCB中的msg指针,否则不使用这个msg参数
第五步,将TCB中的pendto置为false,表示不是timeout结束的等待,将stat等待的sem位清除,其余保持不变
第六步,将就绪表中的prio位置1,并返回prio
完成这个函数之后回到Post主函数中,主函数开中断,并进入调度函数
我们来看另外一种不同于pend的非等待信号接收函数accept,他们的不同在于,一个进入调度,而另一个不进入
- /*
- *********************************************************************************************************
- * ACCEPT SEMAPHORE
- *
- * Description: This function checks the semaphore to see if a resource is available or, if an event
- * occurred. Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the
- * resource is not available or the event did not occur.
- *
- * Arguments : pevent is a pointer to the event control block
- *
- * Returns : > 0 if the resource is available or the event did not occur the semaphore is
- * decremented to obtain the resource.
- * == 0 if the resource is not available or the event did not occur or,
- * if 'pevent' is a NULL pointer or,
- * if you didn't pass a pointer to a semaphore
- *********************************************************************************************************
- */
- #if OS_SEM_ACCEPT_EN > 0
- INT16U OSSemAccept (OS_EVENT *pevent)
- {
- INT16U cnt;
- #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0;
- #endif
- #if OS_ARG_CHK_EN > 0
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- return (0);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
- return (0);
- }
- OS_ENTER_CRITICAL();
- cnt = pevent->OSEventCnt;
- if (cnt > 0) { /* See if resource is available */
- pevent->OSEventCnt--; /* Yes, decrement semaphore and notify caller */
- }
- OS_EXIT_CRITICAL();
- return (cnt); /* Return semaphore count */
- }
- #endif
这个函数只有一个参数ECB,pend有三个参数,一个ECB表示信号,一个timeout限制等待时间,一个err返回错误
检测是否为空指针参数,检测eventtype是不是sem
取得ECB中的cnt计数值,检测是否大于0,如果大于0 则--,函数返回cnt自减之前的值。
删除一个信号量ECB的函数
该函数有三个参数,第一是ECB,第二是opt选项,有两个选项,一个是只有不等待时才删除该信号量,另一个是always删除,第三个参数是err
第一步,检测err指针和ECB指针
第二部,检测type是不是sem
第三步,检测是否在中断嵌套中
第四步,关中断,检查EWL是否还有task在等待,一个switch语句,如果opt是非等待删除,并且没有等待task,将ECB清除并加入eventfreelist中,如果有task在等待,返回错误跳出。
如果opt是直接删除,如果有task在等待,先要将所等待的task置为rdy,再清除ECB,类似初始化ECB,然后进入调度函数,返回NULL说明删除成功,否则返回TCB
如果没有task等待
阅读(3214) | 评论(0) | 转发(0) |