在shared memory的驱动中看到一个诡异的现象,从AP侧看BP的写指针有时会变小,例如:
read/write = 0x44f0, 但write忽然会变为0x4400,正常情况下是write增加,read在后面跟随。这样就会出现异常。
后来发现,读写操作不是按照预想的一次完成,而是按字节多次进行的。
假设AP 读却写指针(BP维护),当AP读第一个字节后,BP发生了变化,又更改了第一个字节,但是AP不知道,这样组合出来的4字节就有问题。
【简单的说就是两者没有同步】
虽然看上去是细节,但影响还是很严重的。
为什么执行的代码是按字节访问的哪?
其实原因很简单,数据结构的定义使用packeted进行了修饰。
__attrubte__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
如果packeted只是简单的理解为编译器不要填充字节,那么生成的代码也不会按字节操作啊?应该是编译器还会按照字节的方式进行处理。
typedef struct smd_tx_stream_tag
{
unsigned int write;
const unsigned int read;
unsigned int size; /*The buffer size, must be the power of 2*/
const unsigned char res[20];
unsigned char buffer[SMD_BUFFER_SIZE];
const unsigned char protection[32];
} __attribute__ ((packeted)) T_SMD_TX_STREAM;
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);
}
crash> dis smd_stream_write_avail
0xc024219c <smd_stream_write_avail>: mov r12, sp
0xc02421a0 <smd_stream_write_avail+4>: push {r4, r5, r6, r11, r12, lr, pc}
0xc02421a4 <smd_stream_write_avail+8>: sub r11, r12, #4
0xc02421a8 <smd_stream_write_avail+12>: ldrb r12, [r0, #37] ; 0x25
0xc02421ac <smd_stream_write_avail+16>: ldrb r3, [r0, #36] ; 0x24
0xc02421b0 <smd_stream_write_avail+20>: ldrb r1, [r0, #41] ; 0x29
0xc02421b4 <smd_stream_write_avail+24>: ldrb r2, [r0, #40] ; 0x28
0xc02421b8 <smd_stream_write_avail+28>: orr r12, r3, r12, lsl #8
0xc02421bc <smd_stream_write_avail+32>: ldrb r4, [r0, #38] ; 0x26
0xc02421c0 <smd_stream_write_avail+36>: ldrb r3, [r0, #42] ; 0x2a
0xc02421c4 <smd_stream_write_avail+40>: orr r1, r2, r1, lsl #8
0xc02421c8 <smd_stream_write_avail+44>: ldrb r2, [r0, #39] ; 0x27
0xc02421cc <smd_stream_write_avail+48>: ldrb r6, [r0, #33] ; 0x21
0xc02421d0 <smd_stream_write_avail+52>: orr r12, r12, r4, lsl #16
0xc02421d4 <smd_stream_write_avail+56>: ldrb r5, [r0, #43] ; 0x2b
0xc02421d8 <smd_stream_write_avail+60>: orr r1, r1, r3, lsl #16
0xc02421dc <smd_stream_write_avail+64>: ldrb r4, [r0, #34] ; 0x22
0xc02421e0 <smd_stream_write_avail+68>: orr r12, r12, r2, lsl #24
0xc02421e4 <smd_stream_write_avail+72>: ldrb r3, [r0, #32]
0xc02421e8 <smd_stream_write_avail+76>: ldrb r2, [r0, #35] ; 0x23
0xc02421ec <smd_stream_write_avail+80>: orr r1, r1, r5, lsl #24
0xc02421f0 <smd_stream_write_avail+84>: orr r3, r3, r6, lsl #8
0xc02421f4 <smd_stream_write_avail+88>: add r0, r12, r1
0xc02421f8 <smd_stream_write_avail+92>: orr r3, r3, r4, lsl #16
0xc02421fc <smd_stream_write_avail+96>: orr r3, r3, r2, lsl #24
0xc0242200 <smd_stream_write_avail+100>: rsb r0, r3, r0
0xc0242204 <smd_stream_write_avail+104>: ldm sp, {r4, r5, r6, r11, sp, pc}
怎样使用字的方式访问?
aligned什么用途?这里不用aligned也可以,它本身就是在4的边界上。可以从生成的vmlinux验证
在编译目录下:
arm-none-linux-gnueabi-objdump -D vmlinux | less
然后查找即可。
-
This attribute specifies a minimum alignment (in bytes) for variablesof the specified type. For example, the declarations:
struct S { short f[3]; } __attribute__ ((aligned (8))); typedef int more_aligned_int __attribute__ ((aligned (8)));
force the compiler to insure (as far as it can) that each variable whosetype is
struct S
ormore_aligned_int
will be allocated andaligned at least on a 8-byte boundary.
aligned (
alignment
)
typedef struct smd_tx_stream_tag
{unsigned int write;
const unsigned int read;
unsigned int size; /*The buffer size, must be the power of 2*/
const unsigned char res[20];
unsigned char buffer[SMD_BUFFER_SIZE];
const unsigned char protection[32];
} __attribute__ ((aligned(4))) T_SMD_TX_STREAM;
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);
}
c029b054 <smd_stream_write_avail>:
c029b054: e1a0c00d mov ip, sp
c029b058: e92dd800 push {fp, ip, lr, pc}
c029b05c: e24cb004 sub fp, ip, #4
c029b060: e92d4000 push {lr}
c029b064: ebf5ccf7 bl c000e448 <__gnu_mcount_nc>
c029b068: e5901024 ldr r1, [r0, #36] ; 0x24
c029b06c: e5902028 ldr r2, [r0, #40] ; 0x28
c029b070: e5903020 ldr r3, [r0, #32]
c029b074: e0810002 add r0, r1, r2
c029b078: e0630000 rsb r0, r3, r0
c029b07c: e89da800 ldm sp, {fp, sp, pc}