一、事件标志组创建
OSFlagCreate((OS_FLAG_GRP *)&MyEventFlag,
(CPU_CHAR *)"MyEventFlag",
(OS_FLAGS )0,
(OS_ERR *)&err);
创建我们采用这样一个函数,首先明白事件标志组本质就是一个内核对象里面有一个32位得变量Flags,这个变量每一位或者每几位可以表示一个事件得发生,当等待的任务需要的那几个事件(那几个标志位都被置为0或者1)那么就表示等待成功。
那么在创建时干啥了?
void OSFlagCreate (OS_FLAG_GRP *p_grp,
CPU_CHAR *p_name,
OS_FLAGS flags,
OS_ERR *p_err)
{
CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
if (OSSafetyCriticalStartFlag == DEF_TRUE) {
*p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
return;
}
#endif
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if called from ISR ... */
*p_err = OS_ERR_CREATE_ISR; /* ... can't CREATE from an ISR */
return;
}
#endif
#if OS_CFG_ARG_CHK_EN > 0u
if (p_grp == (OS_FLAG_GRP *)0) { /* Validate 'p_grp' */
*p_err = OS_ERR_OBJ_PTR_NULL;
return;
}
#endif
OS_CRITICAL_ENTER();
p_grp->Type = OS_OBJ_TYPE_FLAG; /* Set to event flag group type */
p_grp->NamePtr = p_name;
p_grp->Flags = flags; /* Set to desired initial value */
p_grp->TS = (CPU_TS)0;
OS_PendListInit(&p_grp->PendList);
#if OS_CFG_DBG_EN > 0u
OS_FlagDbgListAdd(p_grp);
#endif
OSFlagQty++;
OS_CRITICAL_EXIT();
*p_err = OS_ERR_NONE;
}
可以看见在事件标志组得创建得时候非常简单,就是参数检查、赋值变量类型(事件标志组类型)、赋值名字,初始值,时间戳,全局得事件标志组变量++。中间还调用了一个OS_PendListInit这个函数猜都知道,是初始化你事件标志组得等待列表用的。无非就是把等待列表置为空,表示这会儿刚创建 肯定没任务在等待
二、事件标志组的等待
1、除了常规的参数检查之外,进来就是看你要不要清除,就相当于用一次满足了就清除,这个变量要看你传参数opt加了没,加了就清除,没加就算了,然后把ts时间戳置零
if ((opt & OS_OPT_PEND_FLAG_CONSUME) != (OS_OPT)0) { /* See if we need to consume the flags */
consume = DEF_TRUE;
} else {
consume = DEF_FALSE;
}
if (p_ts != (CPU_TS *)0) {
*p_ts = (CPU_TS)0; /* Initialize the returned timestamp */
}
2、这里就是进行了一个眼膜操作(只需要低四位),相当于就是你判断是想所有都置为1、任意一位置为1,所有都置为0、任意一位置为0,这四种分出来四个case,原理都差不多,拿一个分析,上面if满足:就相当于是你现在满足了,你想要的位都置为1了,在看你需不需要清0得标志位,需要就清(取反)
if不满足:这里就是你现在想要的位还没值位,此时又要看你是阻塞还是非阻塞
非阻塞:直接返回0
阻塞:添加到等待列表里面去,添加到等待列表还要看你有没有超时等待,如果有还需添加到时钟基准列表里面去,同时还会保存一个状态值到挂起等待的pend data里面去
mode = opt & OS_OPT_PEND_FLAG_MASK;
CPU_CRITICAL_ENTER();
switch (mode) {
case OS_OPT_PEND_FLAG_SET_ALL: /* See if all required flags are set */
flags_rdy = (OS_FLAGS)(p_grp->Flags & flags); /* Extract only the bits we want */
if (flags_rdy == flags) { /* Must match ALL the bits that we want */
if (consume == DEF_TRUE) { /* See if we need to consume the flags */
p_grp->Flags &= ~flags_rdy; /* Clear ONLY the flags that we wanted */
}
OSTCBCurPtr->FlagsRdy = flags_rdy; /* Save flags that were ready */
if (p_ts != (CPU_TS *)0) {
*p_ts = p_grp->TS;
}
CPU_CRITICAL_EXIT(); /* Yes, condition met, return to caller */
*p_err = OS_ERR_NONE;
return (flags_rdy);
} else { /* Block task until events occur or timeout */
if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_PEND_WOULD_BLOCK; /* Specified non-blocking so task would block */
return ((OS_FLAGS)0);
} else { /* Specified blocking so check is scheduler is locked */
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* See if called with scheduler locked ... */
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_SCHED_LOCKED; /* ... can't PEND when locked */
return ((OS_FLAGS)0);
}
}
OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); /* Lock the scheduler/re-enable interrupts */
OS_FlagBlock(&pend_data,
p_grp,
flags,
opt,
timeout);
OS_CRITICAL_EXIT_NO_SCHED();
}
break;
3.任务重新调度回来,这里就有几种情况,看你任务是取消等待、删除、超时这些都直接返回0,后续如果成功的拿到了事件标志组,拿到一下使得任务成功拿到的一个状态,在判断要不要consume,最后在返回就行了。
OSSched(); /* Find next HPT ready to run */
CPU_CRITICAL_ENTER();
switch (OSTCBCurPtr->PendStatus) {
case OS_STATUS_PEND_OK: /* We got the vent flags */
if (p_ts != (CPU_TS *)0) {
*p_ts = OSTCBCurPtr->TS;
}
*p_err = OS_ERR_NONE;
break;
case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */
if (p_ts != (CPU_TS *)0) {
*p_ts = OSTCBCurPtr->TS;
}
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_PEND_ABORT;
return ((OS_FLAGS)0);
case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get semaphore within timeout */
if (p_ts != (CPU_TS *)0) {
*p_ts = (CPU_TS )0;
}
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_TIMEOUT;
return ((OS_FLAGS)0);
case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */
if (p_ts != (CPU_TS *)0) {
*p_ts = OSTCBCurPtr->TS;
}
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_OBJ_DEL;
return ((OS_FLAGS)0);
default:
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_STATUS_INVALID;
return ((OS_FLAGS)0);
}
flags_rdy = OSTCBCurPtr->FlagsRdy;
if (consume == DEF_TRUE) { /* See if we need to consume the flags */
switch (mode) {
case OS_OPT_PEND_FLAG_SET_ALL:
case OS_OPT_PEND_FLAG_SET_ANY: /* Clear ONLY the flags we got */
p_grp->Flags &= ~flags_rdy;
break;
#if OS_CFG_FLAG_MODE_CLR_EN > 0u
case OS_OPT_PEND_FLAG_CLR_ALL:
case OS_OPT_PEND_FLAG_CLR_ANY: /* Set ONLY the flags we got */
p_grp->Flags |= flags_rdy;
break;
#endif
default:
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_OPT_INVALID;
return ((OS_FLAGS)0);
}
}
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_NONE; /* Event(s) must have occurred */
return (flags_rdy);
三、时间标志组得发布
1、参数检查 不合适就返回,再拿一个时间戳ts = OS_TS_GET();
if (p_grp == (OS_FLAG_GRP *)0) { /* Validate 'p_grp' */
*p_err = OS_ERR_OBJ_PTR_NULL;
return ((OS_FLAGS)0);
}
switch (opt) {
case OS_OPT_POST_FLAG_SET:
case OS_OPT_POST_FLAG_CLR:
case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED:
case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED:
break;
default:
*p_err = OS_ERR_OPT_INVALID;
return ((OS_FLAGS)0);
}
2、这里就分为两部分有一部分就是中断中去处理,再就是非中断处理(先看这个)
flags_cur = OS_FlagPost(p_grp,
flags,
opt,
ts,
p_err);
这里进来就是,看你是要置零还是置1,看你传的opt是什么,并且保存一下刚才的ts
CPU_CRITICAL_ENTER();
switch (opt) {
case OS_OPT_POST_FLAG_SET:
case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED:
p_grp->Flags |= flags; /* Set the flags specified in the group */
break;
case OS_OPT_POST_FLAG_CLR:
case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED:
p_grp->Flags &= ~flags; /* Clear the flags specified in the group */
break;
default:
CPU_CRITICAL_EXIT(); /* INVALID option */
*p_err = OS_ERR_OPT_INVALID;
return ((OS_FLAGS)0);
}
p_grp->TS = ts;
再就是要去等待列表里看一下,这里面如果有等待列表的任务刚好在等待我们置为得这个数字的话,那么就把任务从等待列表中移除出去 然后让任务就绪。
p_pend_list = &p_grp->PendList;
if (p_pend_list->NbrEntries == 0u) { /* Any task waiting on event flag group? */
CPU_CRITICAL_EXIT(); /* No */
*p_err = OS_ERR_NONE;
return (p_grp->Flags);
}
如果有任务在等待事件标志组,遍历所有的任务,利用头节点和任务tcb,里面又要分你是置零还是任意为0,置1还是任意为1,都分别处理,但是他们在处理完之后都会把任务调用OS_FlagTaskRdy这个函数来表示任务已经成功获取到了事件标志组然后处理任务。这里为什么任务有这个opt这个选项就是任务在pend的时候就拿到了这个并且保存在任务得tcb里面。
p_pend_data = p_pend_list->HeadPtr;
p_tcb = p_pend_data->TCBPtr;
while (p_tcb != (OS_TCB *)0) { /* Go through all tasks waiting on event flag(s) */
p_pend_data_next = p_pend_data->NextPtr;
mode = p_tcb->FlagsOpt & OS_OPT_PEND_FLAG_MASK;
switch (mode) {
case OS_OPT_PEND_FLAG_SET_ALL: /* See if all req. flags are set for current node */
flags_rdy = (OS_FLAGS)(p_grp->Flags & p_tcb->FlagsPend);
if (flags_rdy == p_tcb->FlagsPend) {
OS_FlagTaskRdy(p_tcb, /* Make task RTR, event(s) Rx'd */
flags_rdy,
ts);
}
break;
case OS_OPT_PEND_FLAG_SET_ANY: /* See if any flag set */
flags_rdy = (OS_FLAGS)(p_grp->Flags & p_tcb->FlagsPend);
if (flags_rdy != (OS_FLAGS)0) {
OS_FlagTaskRdy(p_tcb, /* Make task RTR, event(s) Rx'd */
flags_rdy,
ts);
}
break;
#if OS_CFG_FLAG_MODE_CLR_EN > 0u
case OS_OPT_PEND_FLAG_CLR_ALL: /* See if all req. flags are set for current node */
flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
if (flags_rdy == p_tcb->FlagsPend) {
OS_FlagTaskRdy(p_tcb, /* Make task RTR, event(s) Rx'd */
flags_rdy,
ts);
}
break;
case OS_OPT_PEND_FLAG_CLR_ANY: /* See if any flag set */
flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
if (flags_rdy != (OS_FLAGS)0) {
OS_FlagTaskRdy(p_tcb, /* Make task RTR, event(s) Rx'd */
flags_rdy,
ts);
}
break;
#endif
default:
OS_CRITICAL_EXIT();
*p_err = OS_ERR_FLAG_PEND_OPT;
return ((OS_FLAGS)0);
}
p_pend_data = p_pend_data_next; /* Point to next task waiting for event flag(s) */
if (p_pend_data != (OS_PEND_DATA *)0) {
p_tcb = p_pend_data->TCBPtr;
} else {
p_tcb = (OS_TCB *)0;
}
}
这里得OS_FlagTaskRdy,就是修改任务得一些状态,然后根据任务得一些不同的状态,然后把任务从等待列表移除出去就行了。
void OS_FlagTaskRdy (OS_TCB *p_tcb,
OS_FLAGS flags_rdy,
CPU_TS ts)
{
p_tcb->FlagsRdy = flags_rdy;
p_tcb->PendStatus = OS_STATUS_PEND_OK; /* Clear pend status */
p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */
p_tcb->TS = ts;
switch (p_tcb->TaskState) {
case OS_TASK_STATE_RDY:
case OS_TASK_STATE_DLY:
case OS_TASK_STATE_DLY_SUSPENDED:
case OS_TASK_STATE_SUSPENDED:
break;
case OS_TASK_STATE_PEND:
case OS_TASK_STATE_PEND_TIMEOUT:
OS_TaskRdy(p_tcb);
p_tcb->TaskState = OS_TASK_STATE_RDY;
break;
case OS_TASK_STATE_PEND_SUSPENDED:
case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
break;
default:
break;
}
OS_PendListRemove(p_tcb);
}
在外层就是看你是否要调度,并且把事件标志组得变量作为函数得返回值返回。
if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
OSSched();
}
CPU_CRITICAL_ENTER();
flags_cur = p_grp->Flags;
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_NONE;
return (flags_cur);