OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4663|回复: 3

发现原子阻塞I/O 按键例程的小问题 Segmentation fault

[复制链接]

1

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-11-11
在线时间
7 小时
发表于 2020-4-3 16:07:07 | 显示全部楼层 |阅读模式
在做阻塞I/O实验时,对原子例程代码稍做了一点修改遇到了Segmentation fault 下面上代码:原子例程14 block.c中 208行起 代码片段如下:
    DECLARE_WAITQUEUE(wait, current);   /* 定义一个等待队列 等待队列项*/
    if(atomic_read(&dev->releasekey) == 0) {    /* 没有按键按下 */
        add_wait_queue(&dev->r_wait, &wait);    /* 将等待队列项 添加到等待队列头 */
        __set_current_state(TASK_INTERRUPTIBLE);/* 设置任务状态 */
        schedule();                         /* 进行一次任务切换 */
        if(signal_pending(current)) {           /* 判断是否为信号引起的唤醒 */
            ret = -ERESTARTSYS;
            goto wait_error;
        }
    }
    remove_wait_queue(&dev->r_wait, &wait);     /* 唤醒以后将等待队列移除 */

    keyvalue = atomic_read(&dev->keyvalue);
    releasekey = atomic_read(&dev->releasekey);


修改代码:将keyvalue和releasekey 赋值语句 往前提,并采用releasekey 进行休眠判断,代码如下:
    DECLARE_WAITQUEUE(wait, current);   /* 定义一个等待队列 等待队列项*/
    keyvalue = atomic_read(&dev->keyvalue);
    releasekey = atomic_read(&dev->releasekey);
    if(releasekey == 0) {   /* 没有按键按下 */
        add_wait_queue(&dev->r_wait, &wait);    /* 将等待队列项 添加到等待队列头 */
        __set_current_state(TASK_INTERRUPTIBLE);/* 设置任务状态 */
        schedule();                         /* 进行一次任务切换 */
        if(signal_pending(current)) {           /* 判断是否为信号引起的唤醒 */
            ret = -ERESTARTSYS;
            goto wait_error;
        }
    }
    remove_wait_queue(&dev->r_wait, &wait);     /* 唤醒以后将等待队列移除 */


这时候编译,并在目标板中加载模块,执行应用程序,按下按键后 控制台打印如下错误:
Unable to handle kernel NULL pointer dereference at virtual address 00000004
pgd = 88728000
[00000004] *pgd=884a3831, *pte=00000000, *ppte=00000000
Internal error: Oops: 817 [#1] PREEMPT SMP ARM
Modules linked in: blockio(O)
CPU: 0 PID: 75 Comm: imx6uirqApp Tainted: G           O    4.1.15 #1
Hardware name: Freescale i.MX6 Ultralite (Device Tree)
task: 884f8980 ti: 8873e000 task.ti: 8873e000
PC is at remove_wait_queue+0x20/0x48
LR is at get_parent_ip+0x10/0x2c
pc : [<80066878>]    lr : [<80057274>]    psr: 600d0093
sp : 8873fec8  ip : 00100100  fp : 00000000
r10: 00000000  r9 : 8873e000  r8 : 8000f684
r7 : 00000004  r6 : 7ecd7d08  r5 : 7f000570  r4 : 8873fedc
r3 : 00000000  r2 : 00000000  r1 : 00200200  r0 : 200d0013
Flags: nZCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c5387d  Table: 8872806a  DAC: 00000015
Process imx6uirqApp (pid: 75, stack limit = 0x8873e210)
Stack: (0x8873fec8 to 0x88740000)
fec0:                   7f0004dc 00000001 7ecd7d08 7f000130 8173e000 00000000
fee0: 884f8980 80059034 00000000 00000000 884a6180 7f000070 8873ff88 800ea904
ff00: 88750015 76f81000 00000000 860f9660 88742028 00000101 00000000 00000040
ff20: 00000001 00000020 88001b80 80973210 8bc65a00 88750000 8873ff40 800e4d4c
ff40: 80974754 7ecd7d08 884a6180 7ecd7d08 884a6180 8873ff88 00000004 800eb0a8
ff60: 00000000 800ea498 00000000 884a6180 884a6180 7ecd7d08 00000004 8000f684
ff80: 8873e000 800eb948 00000000 00000000 00000000 7ecd7d38 00000000 00000000
ffa0: 00000003 8000f500 7ecd7d38 00000000 00000003 7ecd7d08 00000004 7ecd7d08
ffc0: 7ecd7d38 00000000 00000000 00000003 00000000 00000000 76f81000 00000000
ffe0: 00000000 7ecd7cfc 000104c3 76ef3f66 600d0030 00000003 8bf5e821 8bf5ec21
[<80066878>] (remove_wait_queue) from [<7f000130>] (imx6uirq_read+0xc0/0x148 [blockio])
[<7f000130>] (imx6uirq_read [blockio]) from [<800ea904>] (__vfs_read+0x20/0xd4)
[<800ea904>] (__vfs_read) from [<800eb0a8>] (vfs_read+0x7c/0x104)
[<800eb0a8>] (vfs_read) from [<800eb948>] (SyS_read+0x44/0x9c)
[<800eb948>] (SyS_read) from [<8000f500>] (ret_fast_syscall+0x0/0x3c)
Code: e5943010 e594200c e59f1020 e59fc020 (e5823004)
---[ end trace d86b1eaea8c25eeb ]---
note: imx6uirqApp[75] exited with preempt_count 1
Segmentation fault



百思不得解,为什么把赋值语句 拿到前面会报段错误,并没有涉及指针的赋值啊,而且和之前的语句代码逻辑并没有任何区别啊。求解释



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2020-4-5 13:53:57 | 显示全部楼层
本帖最后由 zuozhongkai 于 2020-4-5 13:56 编辑

是remove_wait_queue(&dev->r_wait, &wait);这一行出问题的,例程写的有问题,应该改为下面这种形式
UXWZ]6LB)Z~I}GGH7XGBL0S.png

回复 支持 反对

使用道具 举报

1

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-11-11
在线时间
7 小时
 楼主| 发表于 2020-4-7 16:35:34 | 显示全部楼层
zuozhongkai 发表于 2020-4-5 13:53
是remove_wait_queue(&dev->r_wait, &wait);这一行出问题的,例程写的有问题,应该改为下面这种形式

嗯 这样确实解决了上述问题。个人认为对于按键来说,完全可以不判断 直接休眠,在中断里唤醒线程。唤醒后再读设备结构体里的键值。后来代码也是修改成为直接休眠了。
回复 支持 反对

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2020-4-9 09:10:38 | 显示全部楼层
李兴浩 发表于 2020-4-7 16:35
嗯 这样确实解决了上述问题。个人认为对于按键来说,完全可以不判断 直接休眠,在中断里唤醒线程。唤醒后 ...

是可以这么做,但是教程为了讲解用法,所以就这么做了
开往春天的手扶拖拉机
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 10:59

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表