TobudOS
TobudOS copied to clipboard
tos_at.c的at_parser问题
在at_parser的如下代码中,先释放了信号,后拷贝at_echo的buf,在这之间可能发生任务调度导致at_echo被提前释放而hardfault
if (at_parse_status == AT_PARSE_STATUS_EXPECT) {
at_echo->status = AT_ECHO_STATUS_EXPECT;
if (at_echo->__is_expecting) {
tos_sem_post(&at_echo->__expect_notify);
}
} else if (at_parse_status == AT_PARSE_STATUS_NEWLINE &&
at_echo->status == AT_ECHO_STATUS_NONE) {
at_echo_status_set(at_echo);
}
if (at_echo->buffer) {
at_echo_buffer_copy(recv_cache, at_echo);
}
您是实际遇到过因为这样hardfault的情况吗?能否提供问题复现的场景?
您好,我是在实际项目中遇到的这个问题。场景如下:
在at_parser
任务中释放了at_echo->__expect_notify
信号量,并且在at_echo_buffer_copy
之前发生了任务调度,任务切换到了tos_at_cmd_exec_until
中,成功获取了echo->__expect_notify
信号量,随后执行了AT_AGENT->echo = K_NULL;
,等任务再切换回at_parser
时,at_echo
已经为空,此时再拷贝就会出现hardfault。
将拷贝放到释放信号之前则不会出现该问题。
__STATIC__ void at_parser(void *arg)
{
...
if (at_parse_status == AT_PARSE_STATUS_EXPECT) {
at_echo->status = AT_ECHO_STATUS_EXPECT;
if (at_echo->__is_expecting) {
tos_sem_post(&at_echo->__expect_notify);
}
} else if (at_parse_status == AT_PARSE_STATUS_NEWLINE &&
at_echo->status == AT_ECHO_STATUS_NONE) {
at_echo_status_set(at_echo);
}
if (at_echo->buffer) {
at_echo_buffer_copy(recv_cache, at_echo);
}
...
}
__API__ int tos_at_cmd_exec_until(at_echo_t *echo, uint32_t timeout, const char *cmd, ...)
{
...
if (ret != 0) {
AT_AGENT->echo = K_NULL;
return -1;
}
if (tos_sem_pend(&echo->__expect_notify, tos_millisec2tick(timeout)) != K_ERR_NONE) {
ret = -1;
}
tos_sem_destroy(&echo->__expect_notify);
AT_AGENT->echo = K_NULL;
return ret;
}
这确实是一个问题,我提交一个bugfix。您那边可以暂时先把语句顺序调换一下,copy动作放到sem_post之前,应该可以规避这个问题。
我提问下, tos_at_cmd_exec_until 和 at_parser 是两个不同的任务在同时操作 echo,如果 tos_at_cmd_exec_until 执行 tos_sem_pend超时,AT_AGENT->echo 直接被清空,如果这时候执行到 at_parser 对AT_AGENT->echode 操作,应该也会生成一个hardfault, 发生的条件需要执行到 if (!at_echo) 判断后,进行了tos_sem_pend超时引起的任务切换 AT_AGENT->echo被清空; 对于 if (!at_echo) 后的对于echo的操作需要原子保护