void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr; #endif void *msg; OS_Q *pq; if (OSIntNesting > 0) { /* See if called from ISR ... */ *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return ((void *)0); } #if OS_ARG_CHK_EN > 0 if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *err = OS_ERR_PEVENT_NULL; return ((void *)0); } if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */ *err = OS_ERR_EVENT_TYPE; return ((void *)0); } #endif OS_ENTER_CRITICAL(); pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */ if (pq->OSQEntries > 0) { /* See if any messages in the queue */ msg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */ pq->OSQEntries--; /* Update the number of entries in the queue */ if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */ pq->OSQOut = pq->OSQStart; } OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (msg); /* Return message received */ } OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */ OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); OS_Sched(); /* Find next highest priority task ready to run */ OS_ENTER_CRITICAL(); if (OSTCBCur->OSTCBStat & OS_STAT_Q) { /* Was task readied because of a timeout? */ OS_EventTO(pevent); /* Yes */ OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; /* Indicate a timeout occured */ return ((void *)0); /* No message received */ } msg = OSTCBCur->OSTCBMsg;/* No, Extract message from TCB (Put there by QPost) */ OSTCBCur->OSTCBMsg = (void *)0; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (msg); /* Return message received */ }
void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { void *msg; #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 (err == (INT8U *)0) { /* Validate 'err' */ return ((void *)0); } if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *err = OS_ERR_PEVENT_NULL; return ((void *)0); } #endif if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ *err = OS_ERR_EVENT_TYPE; return ((void *)0); } if (OSIntNesting > 0) { /* See if called from ISR ... */ *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return ((void *)0); } OS_ENTER_CRITICAL(); msg = pevent->OSEventPtr; if (msg != (void *)0) { /* See if there is already a message */ pevent->OSEventPtr = (void *)0; /* Clear the mailbox */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (msg); /* Return the message received (or NULL) */ } OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */ OSTCBCur->OSTCBPendTO = FALSE; OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); OS_Sched(); /* Find next highest priority task ready to run */ OS_ENTER_CRITICAL(); if (OSTCBCur->OSTCBPendTO == TRUE) { /* See if we were given the message */ OS_EventTO(pevent); /* Timed out, Make task ready */ OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; /* Indicate that a timeout occured */ return ((void *)0); /* Return a NULL message */ } msg = OSTCBCur->OSTCBMsg; OSTCBCur->OSTCBMsg = (void *)0; /* Yes, clear message received */ OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (msg); /* Return the message received */ }
void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { #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 (err == (INT8U *)0) { /* Validate 'err' */ return; } if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *err = OS_ERR_PEVENT_NULL; return; } #endif if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ *err = OS_ERR_EVENT_TYPE; return; } if (OSIntNesting > 0) { /* See if called from ISR ... */ *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return; } if (OSLockNesting > 0) { /* See if called with scheduler locked ... */ *err = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return; } OS_ENTER_CRITICAL(); if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ... */ pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return; } /* Otherwise, must wait until event occurs */ OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */ OSTCBCur->OSTCBPendTO = OS_FALSE; OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); OS_Sched(); /* Find next highest priority task ready */ OS_ENTER_CRITICAL(); if (OSTCBCur->OSTCBPendTO == OS_TRUE) { /* See if we timedout */ OS_EventTO(pevent); OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; /* Indicate that didn't get event within TO */ return; } OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; }
void OSSemPend (OS_EVENT *pevent, INT32U timeout, INT8U *perr) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif #ifdef OS_SAFETY_CRITICAL if (perr == (INT8U *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif #if OS_ARG_CHK_EN > 0u if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *perr = OS_ERR_PEVENT_NULL; return; } #endif if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ *perr = OS_ERR_EVENT_TYPE; return; } if (OSIntNesting > 0u) { /* See if called from ISR ... */ *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return; } if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */ *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return; } OS_ENTER_CRITICAL(); if (pevent->OSEventCnt > 0u) { /* If sem. is positive, resource available ... */ pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */ OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; return; } /* Otherwise, must wait until event occurs */ OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); OS_Sched(); /* Find next highest priority task ready */ OS_ENTER_CRITICAL(); switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */ case OS_STAT_PEND_OK: *perr = OS_ERR_NONE; break; case OS_STAT_PEND_ABORT: *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ break; case OS_STAT_PEND_TO: default: OS_EventTaskRemove(OSTCBCur, pevent); *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */ break; } OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ #if (OS_EVENT_MULTI_EN > 0u) OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; #endif OS_EXIT_CRITICAL(); }
void *OSQPend (OS_EVENT *pevent, INT32U timeout, INT8U *perr) { void *pmsg; OS_Q *pq; #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif #ifdef OS_SAFETY_CRITICAL if (perr == (INT8U *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return ((void *)0); } #endif #if OS_ARG_CHK_EN > 0u if (pevent == (OS_EVENT *)0) /* Validate 'pevent' */ { *perr = OS_ERR_PEVENT_NULL; return ((void *)0); } #endif if (pevent->OSEventType != OS_EVENT_TYPE_Q) /* Validate event block type */ { *perr = OS_ERR_EVENT_TYPE; return ((void *)0); } if (OSIntNesting > 0u) /* See if called from ISR ... */ { *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return ((void *)0); } if (OSLockNesting > 0u) /* See if called with scheduler locked ... */ { *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return ((void *)0); } OS_ENTER_CRITICAL(); pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */ if (pq->OSQEntries > 0u) /* See if any messages in the queue */ { pmsg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */ pq->OSQEntries--; /* Update the number of entries in the queue */ if (pq->OSQOut == pq->OSQEnd) /* Wrap OUT pointer if we are at the end of the queue */ { pq->OSQOut = pq->OSQStart; } OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; return (pmsg); /* Return message received */ } OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); OS_Sched(); /* Find next highest priority task ready to run */ OS_ENTER_CRITICAL(); switch (OSTCBCur->OSTCBStatPend) /* See if we timed-out or aborted */ { case OS_STAT_PEND_OK: /* Extract message from TCB (Put there by QPost) */ pmsg = OSTCBCur->OSTCBMsg; *perr = OS_ERR_NONE; break; case OS_STAT_PEND_ABORT: pmsg = (void *)0; *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ break; case OS_STAT_PEND_TO: default: OS_EventTaskRemove(OSTCBCur, pevent); pmsg = (void *)0; *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */ break; } OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ #if (OS_EVENT_MULTI_EN > 0u) OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; #endif OSTCBCur->OSTCBMsg = (void *)0; /* Clear received message */ OS_EXIT_CRITICAL(); return (pmsg); /* Return received message */ }
void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr) { void *pmsg; INT8U pend_stat; #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 (perr == (INT8U *)0) { /* Validate 'perr' */ return ((void *)0); } if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *perr = OS_ERR_PEVENT_NULL; return ((void *)0); } #endif if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ *perr = OS_ERR_EVENT_TYPE; return ((void *)0); } if (OSIntNesting > 0) { /* See if called from ISR ... */ *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return ((void *)0); } if (OSLockNesting > 0) { /* See if called with scheduler locked ... */ *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return ((void *)0); } OS_ENTER_CRITICAL(); pmsg = pevent->OSEventPtr; if (pmsg != (void *)0) { /* See if there is already a message */ pevent->OSEventPtr = (void *)0; /* Clear the mailbox */ OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; return (pmsg); /* Return the message received (or NULL) */ } OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); OS_Sched(); /* Find next highest priority task ready to run */ OS_ENTER_CRITICAL(); if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) { /* See if we weren't given the message */ pend_stat = OSTCBCur->OSTCBStatPend; OS_EventTOAbort(pevent); /* Timed out, Make task ready */ OS_EXIT_CRITICAL(); switch (pend_stat) { case OS_STAT_PEND_TO: default: *perr = OS_ERR_TIMEOUT; /* Indicate that a timeout occured */ break; case OS_STAT_PEND_ABORT: *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ break; } return ((void *)0); /* Return a NULL message */ } pmsg = OSTCBCur->OSTCBMsg; OSTCBCur->OSTCBMsg = (void *)0; /* Yes, clear message received */ OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */ OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; return (pmsg); /* Return the message received */ }
/*$PAGE*/ void *OSMboxPend (OS_EVENT *pevent, INT32U timeout, INT8U *perr) { void *pmsg; #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif #ifdef OS_SAFETY_CRITICAL if (perr == (INT8U *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); } #endif #if OS_ARG_CHK_EN > 0u if (pevent == (OS_EVENT *)0) { /*事件控制块指针是否有效 */ *perr = OS_ERR_PEVENT_NULL; return ((void *)0); } #endif if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* 事件控制块类型是否有效 */ *perr = OS_ERR_EVENT_TYPE; return ((void *)0); } if (OSIntNesting > 0u) { /* 查看是否在中断服务程序ISR中调用本函数 */ *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return ((void *)0); } if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */ *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return ((void *)0); } OS_ENTER_CRITICAL(); pmsg = pevent->OSEventPtr; if (pmsg != (void *)0) { /* See if there is already a message */ pevent->OSEventPtr = (void *)0; /* 清邮箱 */ OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; return (pmsg); /* 返回获得的消息(或空指针) */ } OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); OS_Sched(); /* Find next highest priority task ready to run */ OS_ENTER_CRITICAL(); switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */ case OS_STAT_PEND_OK: pmsg = OSTCBCur->OSTCBMsg; *perr = OS_ERR_NONE; break; case OS_STAT_PEND_ABORT: pmsg = (void *)0; *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ break; case OS_STAT_PEND_TO: default: OS_EventTaskRemove(OSTCBCur, pevent); pmsg = (void *)0; *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */ break; } OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ #if (OS_EVENT_MULTI_EN > 0u) OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; #endif OSTCBCur->OSTCBMsg = (void *)0; /* 清除获得的消息 */ OS_EXIT_CRITICAL(); return (pmsg); /* 返回获得的消息 */ }
// 要求获得邮箱的消息 void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { void *msg; #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 (err == (INT8U *)0) /* Validate 'err' */ { return ((void *)0); } if (pevent == (OS_EVENT *)0) /* Validate 'pevent' */ { *err = OS_ERR_PEVENT_NULL; return ((void *)0); } #endif // 事件类型是邮箱? if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) /* Validate event block type */ { *err = OS_ERR_EVENT_TYPE; return ((void *)0); } // 中断处理里不允许挂起 if (OSIntNesting > 0) /* See if called from ISR ... */ { *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return ((void *)0); } // 调度禁止时不允许挂起 if (OSLockNesting > 0) /* See if called with scheduler locked ... */ { *err = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return ((void *)0); } OS_ENTER_CRITICAL(); msg = pevent->OSEventPtr; // 可获得邮箱消息? if (msg != (void *)0) /* See if there is already a message */ { // 清空邮箱 pevent->OSEventPtr = (void *)0; /* Clear the mailbox */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; // 返回 return (msg); /* Return the message received (or NULL) */ } // 如果获取不到邮箱信息,任务会挂起 // 更新任务状态标志 OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */ // 延时等待最大时间未到 OSTCBCur->OSTCBPendTO = OS_FALSE; // 设置延时等待最大时间 OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */ // 将任务添加到事件控制块的等待任务表 OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); // 找出优先级最高的任务并进行任务切换 OS_Sched(); /* Find next highest priority task ready to run */ // 当邮箱有效或者等待时间到后, // 并且调用OSMboxPend()函数的任务再一次成为最高优先级任务, // 就会回到这里继续执行 OS_ENTER_CRITICAL(); // 延时等待最大时间到了? if (OSTCBCur->OSTCBPendTO == OS_TRUE) /* See if we were given the message */ { // 由于等待超时而将任务置为就绪态。 OS_EventTO(pevent); /* Timed out, Make task ready */ OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; /* Indicate that a timeout occured */ return ((void *)0); /* Return a NULL message */ } // 邮箱可被获得: // 获得邮箱消息 msg = OSTCBCur->OSTCBMsg; // 清空邮箱 OSTCBCur->OSTCBMsg = (void *)0; /* Yes, clear message received */ // 更新任务状态标志 OSTCBCur->OSTCBStat = OS_STAT_RDY; // 释放TCB里的ECB OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return (msg); /* Return the message received */ }
// 要求获得一个信号量 void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) { #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 (err == (INT8U *)0) /* Validate 'err' */ { return; } if (pevent == (OS_EVENT *)0) /* Validate 'pevent' */ { *err = OS_ERR_PEVENT_NULL; return; } #endif // 确定事件类型是信号量 if (pevent->OSEventType != OS_EVENT_TYPE_SEM) /* Validate event block type */ { *err = OS_ERR_EVENT_TYPE; return; } // 中断处理里不允许挂起 if (OSIntNesting > 0) /* See if called from ISR ... */ { *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return; } // 调度禁止时不允许挂起 if (OSLockNesting > 0) /* See if called with scheduler locked ... */ { *err = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return; } OS_ENTER_CRITICAL(); // 如果信号量可用 if (pevent->OSEventCnt > 0) /* If sem. is positive, resource available ... */ { // 获得信号量,计数器减一,即可用的资源减少一份 pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */ OS_EXIT_CRITICAL(); *err = OS_NO_ERR; // 返回 return; } // 否则,等待信号量 /* Otherwise, must wait until event occurs */ // 更新任务状态标志 OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */ // 延时等待最大时间未到 OSTCBCur->OSTCBPendTO = OS_FALSE; // 设置延时等待最大时间 OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */ // 将任务添加到事件控制块的等待任务表 OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); // 找出优先级最高的任务并进行任务切换 OS_Sched(); /* Find next highest priority task ready */ // 当信号量有效或者等待时间到后, // 并且调用 OSSemPend()函数的任务再一次成为最高优先级任务, // 就会回到这里继续执行 OS_ENTER_CRITICAL(); // 是否延时等待最大时间到了? if (OSTCBCur->OSTCBPendTO == OS_TRUE) /* See if we timedout */ { // 由于等待超时而将任务置为就绪态。 OS_EventTO(pevent); OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; /* Indicate that didn't get event within TO */ return; } // 释放TCB里的ECB OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; }
/*$PAGE*/ void OSSemPend (OS_EVENT *pevent, INT32U timeout, INT8U *perr) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif #ifdef OS_SAFETY_CRITICAL if (perr == (INT8U *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif #if OS_ARG_CHK_EN > 0u if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *perr = OS_ERR_PEVENT_NULL; return; } #endif if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */ *perr = OS_ERR_EVENT_TYPE; return; } if (OSIntNesting > 0u) { /* See if called from ISR ... */ *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return; } if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */ *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return; } OS_ENTER_CRITICAL(); /* 信号量大于0,则信号量减1,返回 */ if (pevent->OSEventCnt > 0u) { /* If sem. is positive, resource available ... */ pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */ OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; return; } /* 信号量为0,则把TCB中的状态设置为等待信号量,并设置请求状态为请求OK */ /* Otherwise, must wait until event occurs */ OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* 把等待时限写入TCB */ OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */ /* 设置TCB中等待的事件 * 设置事件控制块中等待任务列表 * 取消当前任务的就绪状态 */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); /* 查找最高优先级的就绪任务,并调度运行 */ OS_Sched(); /* Find next highest priority task ready */ /* 执行OS_Sched()后,已经切换到其他任务。执行这里时,已经是信号量有效或者是等待超时了 */ OS_ENTER_CRITICAL(); /* 根据状态设置函数返回值 */ switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */ case OS_STAT_PEND_OK: *perr = OS_ERR_NONE; break; case OS_STAT_PEND_ABORT: *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ break; case OS_STAT_PEND_TO: default: /* 清除事件等待列表中的当前任务 * 因为OSSemPost()而退出等待状态的任务,会在OSSemPost()中清除事件等待列表中的该任务对应位 * 因为超时而退出等待状态的任务,对应的事件控制块的事件等待列表中该任务不会被清除,需要在这里清除 */ OS_EventTaskRemove(OSTCBCur, pevent); *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */ break; } /* 设置当前任务控制块状态 */ OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ #if (OS_EVENT_MULTI_EN > 0u) OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; #endif OS_EXIT_CRITICAL(); }