shared memory driver(2)

__attribute__ ((packed))的意思是什么

如果变量使用packed修饰,告诉编译器不要为了对齐等,在里面填充字节;

更重要的一点是生成的代码,将以字节形式处理结构体中的变量。

typedef struct smd_tx_stream_tag

{
    unsigned int write;
    const unsigned int read;
    unsigned int size;
    const unsigned char res[20];
    unsigned char   buffer[SMD_BUFFER_SIZE];
    const unsigned char   protection[32];

} __attribute__ ((packed)) T_SMD_TX_STREAM;


已函数smd_stream_write_avail为例

unsigned int smd_stream_write_avail(T_SMD_STREAM_CHANNEL *ch)
{
    T_SMD_TX_STREAM *stream=&ch->tx_stream;
    return (stream->size - stream->write + stream->read);
}

如果使用packed,则生成的汇编代码,都是使用ldrb,对字节进行操作

crash> dis smd_stream_write_avail
0xc021e6fc <smd_stream_write_avail>:    mov     r12, sp
0xc021e700 <smd_stream_write_avail+4>:  push    {r4, r5, r6, r11, r12, lr, pc}
0xc021e704 <smd_stream_write_avail+8>:  sub     r11, r12, #4
0xc021e708 <smd_stream_write_avail+12>: ldrb    r12, [r0, #37]  ; 0x25
0xc021e70c <smd_stream_write_avail+16>: ldrb    r3, [r0, #36]   ; 0x24
0xc021e710 <smd_stream_write_avail+20>: ldrb    r1, [r0, #41]   ; 0x29
0xc021e714 <smd_stream_write_avail+24>: ldrb    r2, [r0, #40]   ; 0x28
0xc021e718 <smd_stream_write_avail+28>: orr     r12, r3, r12, lsl #8
0xc021e71c <smd_stream_write_avail+32>: ldrb    r4, [r0, #38]   ; 0x26
0xc021e720 <smd_stream_write_avail+36>: ldrb    r3, [r0, #42]   ; 0x2a
0xc021e724 <smd_stream_write_avail+40>: orr     r1, r2, r1, lsl #8
0xc021e728 <smd_stream_write_avail+44>: ldrb    r2, [r0, #39]   ; 0x27
0xc021e72c <smd_stream_write_avail+48>: ldrb    r6, [r0, #33]   ; 0x21
0xc021e730 <smd_stream_write_avail+52>: orr     r12, r12, r4, lsl #16
0xc021e734 <smd_stream_write_avail+56>: ldrb    r5, [r0, #43]   ; 0x2b
0xc021e738 <smd_stream_write_avail+60>: orr     r1, r1, r3, lsl #16
0xc021e73c <smd_stream_write_avail+64>: ldrb    r4, [r0, #34]   ; 0x22
0xc021e740 <smd_stream_write_avail+68>: orr     r12, r12, r2, lsl #24
0xc021e744 <smd_stream_write_avail+72>: ldrb    r3, [r0, #32]
0xc021e748 <smd_stream_write_avail+76>: ldrb    r2, [r0, #35]   ; 0x23
0xc021e74c <smd_stream_write_avail+80>: orr     r1, r1, r5, lsl #24
0xc021e750 <smd_stream_write_avail+84>: orr     r3, r3, r6, lsl #8
0xc021e754 <smd_stream_write_avail+88>: add     r0, r12, r1
0xc021e758 <smd_stream_write_avail+92>: orr     r3, r3, r4, lsl #16
0xc021e75c <smd_stream_write_avail+96>: orr     r3, r3, r2, lsl #24
0xc021e760 <smd_stream_write_avail+100>:        rsb     r0, r3, r0
0xc021e764 <smd_stream_write_avail+104>:        ldm     sp, {r4, r5, r6, r11, sp, pc}


如果去掉packeted属性,则生成的汇编代码为:

注意这个是使用objdump工具看得

arm-none-eabi-objdump -D vmlinux | less,而上面那个使用的是 crash工具

c0254518 <smd_stream_write_avail>:
c0254518:       e1a0c00d        mov     ip, sp
c025451c:       e92dd800        push    {fp, ip, lr, pc}
c0254520:       e24cb004        sub     fp, ip, #4      ; 0x4
c0254524:       e5901024        ldr     r1, [r0, #36]
c0254528:       e5902028        ldr     r2, [r0, #40]
c025452c:       e5903020        ldr     r3, [r0, #32]
c0254530:       e0810002        add     r0, r1, r2
c0254534:       e0630000        rsb     r0, r3, r0
c0254538:       e89da800        ldm     sp, {fp, sp, pc}


后果是什么

因为变量如读写指针,是按字节更新的,当另一个 CPU [BP]使用使,看到的可能是更新工程中的一部分【变量都是4个字节,但按字节1个个更新】

算法的设计是一次更新4个字节,就是一次更新完变量。

如函数:smd_stream_read_avail中,可以发现 可以读出的数据大于最大的实际的整个shared memory,这肯定是错误的

unsigned int smd_stream_read_avail(T_SMD_STREAM_CHANNEL *ch)
{
    int len = 0;
    T_SMD_RX_STREAM *stream=&ch->rx_stream;

    len = stream->write - stream->read;
    if(len < 0 || len > SMD_BUFFER_SIZE)
    {
        pr_err("ERRORED current write %x, read %x\n", stream->write, stream->read);
        pr_err("ERRORED Last write %x, read %x\n", stream->protection[1], stream->protection[0]);
        pr_err("ERRORED SMD READ/WRITE POINTER!!!!!!!!!\n");
        stream->read = stream->write;
    }

    stream->protection[0]= stream->read;
    stream->protection[1]= stream->write;

    return (stream->write - stream->read);
}

总结

即使使用原子操作,操作这些变量,也不能解决问题。原子操作的意思是SMP【AP】中多个CPU的访问,而不是说的另外一个CPU【BP】。

问题的解决,却是修改数据变量的类型,有点神奇啊,解决bug,思路要开阔啊,敢于审视那些应该不会出问题的地方。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值