嵌入式复位流程与优化(2)

背景

在前一篇《嵌入式复位流程研究与优化》中,主要针对之前复位流程中无脑关闭FD进行了优化。这几日,出现了一次复位流程未能走完的问题,一直阻塞在umount中不能出来。经过优化后,即使卡在umount中,也不会像以前那样控制台断开了(因为没有关闭控制台对应的套接字),保留了现场。经过对内核态堆栈的分析,我们认为应当是阻塞在了工作队列(work queue)上,在umount中,需要刷新cache到一个工作队列上,并等待该工作队列中的工作全部处理完,但是很遗憾,我们没有等到。板卡复位后,通过对日志的分析,发现有一个任务一直在占用CPU。目前,该问题我们可以在实验室稳定复现,可以证明时该问题导致了复位流程阻塞,未能执行完,导致复位不成功。
由于umount阻塞的问题不止一次出现,且原因并不相同,考虑到该问题严重影响设备稳定性,我们不能仅解决引起umount阻塞的问题,我们必须寻求办法来进行规避,使阻塞在umount中的问题,在任何情况下都不能出现。

分析与解决

解决该问题最直接且暴力的方法,就是另起一个线程,等待一定时间后直接无脑复位。但我一直认为这种修改比较别扭,未采用。主要原因如下:
(1) 需要pthread_create创建一个线程,还需要设置一大堆参数,优先级设置的不合适不定出现什么问题,麻烦;
(2) pthread_create需要指定一个入口函数,目前我们没有这样线程的入口函数。而且在新平台架构下,复位函数被绑定到了板卡配置的一个reset_func函数指针上。目前复位函数本身,包含了文件系统同步,而这个线程入口函数,则不能含有文件系统的同步。新写一个函数是肯定的了,而这个函数由需要直接操作寄存器,怎么写都觉得别扭。
直到今日翻《APUE》时,偶然看到了其中对于慢速I/O读超时的处理方法。书中的例子主要针对的是read函数,使用alarm函数来实现。alarm函数向系统注册一个alarm定时器,该定时器超时后,会向进程发送SIGALRM信号。在SIGALRM信号中,我们只需要使其跳出阻塞的系统调用即可。信号处理函数,会打断系统调用的执行,在处理完信号后,系统调用是否会重试,依赖于具体的操作系统。在我们的这种场景下,我们需要系统调用被打断后,不能重试,否则又会陷入到阻塞态。这里,我们就要使用setjmp以及longjmp,书中之前就多次提到这两个函数配合信号使用,达到打断系统调用的目的。先写了一个demo做试验,代码如下:

#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>


static jmp_buf env_alrm;

void sig_alrm(int signo)
{
    printf("receive sig alarm.\n");
    longjmp(env_alrm, 1);
}

int main()
{
    if(signal(SIGALRM, sig_alrm) == SIG_ERR)
    {
        printf("fail to regist sig_alrm.\n");
    }
    if(setjmp(env_alrm) != 0)
    {
        printf("saved by alarm.\n");
        return 0;
    }
    alarm(10);
    while(1)
    {
        sleep(1);
    }

}

代码十分简单,在main函数中,通过setjmp设置jump点,在收到alarm信号后,即可还原到该点,然后从main函数中退出。代码在调用alarm注册后,直接陷入无限循环。我们期望,alarm信号可以把这段代码从无限循环中拯救出来。运行结果如下:

$ ./test4.o 
receive sig alarm.
saved by alarm.

代码最终正常退出。这段代码对应到我们的项目中,main函数就可以理解成reboot_hook函数,在该函数内仅执行文件系统同步的功能,并不执行复位操作,我们可以通过alarm注册,保证该函数在一定时间内一定会返回,不会导致再次卡死在复位函数中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值