看门狗不断复位


最近遇到一个问题,在zynq上跑起linux 4.4的kernel出现如下状况:
板子出现死机,在串口上无法敲命令,最后60s后被watchdog 复位。这个状况出现频率不固定。
/*****************************************************************************/
请教了一个kernel大神,初步怀疑是deadlock。
排除步骤如下
首先要先考虑deadlock是hard lock还是soft lock引起。首先找一个按键中断控制gpio灯,当出现死机时候,按下按键,如果点灯ok,说明没有关中断,只是soft lock,可以开softlock lockdep(还没学习),会进行死锁检测,找到两个死锁进程进行分析。Hardlock 关中断比较难弄。

后续我通过gitlog 发现有我在网卡中断中不停的ioremap和unmap,ioremap设置kmalloc 且标志位GFP_KERNEL,也就是可能会引起睡眠。我把ioremap在注册驱动中的函数实现,目前还没有出现死机问题。且加了中断控制led灯还没起到检测作用。
/*****************************************************************************/
模拟出现问题:
1.我在中断中加入睡眠函数,会主动调度。进程上下文和中断上下文,两个不同的东东,中断的优先级一定高于进程,且中断里面没有进程(task struct)概念,所以中断里面无法完成调度工作。Schedule函数如下:

asmlinkage void __sched schedule(void)
{
	struct task_struct *prev, *next;
	struct prio_array *array;
	struct list_head *queue;
	unsigned long long now;
	unsigned long run_time;
	int cpu, idx, new_prio;
	long *switch_count;
	struct rq *rq;

	/*
	 * Test if we are atomic.  Since do_exit() needs to call into
	 * schedule() atomically, we ignore that path for now.
	 * Otherwise, whine if we are scheduling when we should not be.
	 */
	if (unlikely(in_atomic() && !current->exit_state)) {
		printk(KERN_ERR "BUG: scheduling while atomic: "
			"%s/0x%08x/%d\n",
			current->comm, preempt_count(), current->pid);
		debug_show_held_locks(current);
		if (irqs_disabled())
			print_irqtrace_events(current);
		dump_stack();
	}
  ...............................................................
}
打印如下:

"BUG: scheduling while atomic: swapper1/0/0x00010002





2.故意使用spin_lock造成死锁。
此现象和 问题出现的一致,但是中断指示灯还是亮的。就是spin_lock关抢占引起。又试验了mutex_lock(学习下区别呗),会进入D状态(uninterruptible sleep),确实,系统不会挂掉只是进入不可中断睡眠。


后续我又写成了AB-BA死锁,由于我是双核的SMP,所以只有线程p获得A且线程B获取B锁,才会造成死锁(有点儿随机哦,不是必现)。

现在状况:
现象还是没有复现,但是怀疑不是中断函数里面睡眠引起的。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是符合您要求的代码实现: ``` #include "stm32f10x.h" #define IWDG_PR_VALUE 4 #define IWDG_RLR_VALUE 5000 void IWDG_Config(void) { /* 使能IWDG时钟 */ RCC_LSICmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET); /* 选择IWDG时钟 */ IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); IWDG_SetPrescaler(IWDG_Prescaler_4); IWDG_SetReload(5000); IWDG_ReloadCounter(); IWDG_Enable(); } void GPIO_Config(void) { /* 使能GPIOA时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* 配置PA0和PA8为输入模式 */ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); } int main(void) { /* 初始化IWDG和GPIO */ IWDG_Config(); GPIO_Config(); /* 初始状态,LED0点亮 */ GPIO_ResetBits(GPIOA, GPIO_Pin_8); while(1) { /* 判断WK_UP按键是否被按下 */ if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == RESET) { /* 喂狗一次 */ IWDG_ReloadCounter(); /* LED0长亮 */ GPIO_SetBits(GPIOA, GPIO_Pin_8); } else { /* 看门狗不断复位,LED0闪烁 */ GPIO_ToggleBits(GPIOA, GPIO_Pin_8); /* 延时一段时间 */ for(int i = 0; i < 1000000; i++); } } } ``` 以上代码中,`IWDG_Config()`和`GPIO_Config()`函数分别用于配置独立看门狗和GPIO。在`main()`函数中,首先调用了这两个函数进行初始化。在每次循环中,判断WK_UP按键是否被按下,如果按下则喂狗一次,同时LED0长亮;否则看门狗不断复位,LED0闪烁。在循环中加入了延时,以便更好地观察LED0的闪烁情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值