You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
IPC中的 mb 和 mq,在缓冲区已满或者为空时,会把线程 A 挂在等待队列上。
当其他线程 B 读取数据或者发送数据后,会把之前的等待线程 A 唤醒,待线程 A 被调度后再处理数据。
若线程 A 被调度前,有高优先级的线程 C 先被调度,可能导致线程 A 处理数据失败,从而再次进入等待队列。
若 mb 和 mq 是 FIFO 类型,会导致先进入 FIFO 队列的线程 A 晚获取数据;晚进入 FIFO 队列的线程 C 反而先获取到数据。
[LOW ] recv, blocking on empty queue
[HIGH] waiting for its turn to receive
[SEND] one message -> wakes LOW
[SEND] rt_mq_send -> 0, entry now = 1
[SEND] releasing semaphore -> makes HIGH ready
[HIGH] scheduled before LOW, recv now (mq entry=1)
[HIGH] got message 42
[REPRO] acquire order = "H"
[REPRO] VERDICT: first waiter got nothing, later arrival took the data (FIFO inverted)
Activity
BernardXiong commentedon Aug 13, 2021
是的,此处没有做锁定,而semaphore相当于做了锁定。后面可以看看怎么来fix下
dongwencai commentedon Nov 21, 2021
uclinux里面也存在这样的问题,但是它的做法并没有把thread从mutex的suspend队列移除,只是wakeup线程,线程可以被调度,当线程获取锁的时候,才会从mutex的suspend队列将自己移除!
Yunlk commentedon Oct 22, 2026
按 #BernardXiong 的建议写了一个最小复现,在当前 master(
1c801efa)上可以稳定重现。没有提交到任何分支,代码在下面。场景
消息队列
rt_mq_create(..., msg_size=4, max_msgs=1, RT_IPC_FLAG_FIFO):waiter_low(priority 20)先rt_mq_recv(RT_WAITING_FOREVER),队列空 → 挂起,成为等待队列第一个waiter_high(priority 10)不在队列上等待,而是先阻塞在一个信号量上rt_mq_send()一条消息 → 唤醒waiter_low(此时它被从等待队列摘下、进入就绪队列)rt_sem_release()→waiter_high就绪waiter_high(10)先于waiter_low(20)运行,调用非阻塞rt_mq_recv()把那条消息取走实测输出(QEMU vexpress-a9 / ARM,未开 SMP)
注意最后
waiter_low始终没有打印 "done"——它被唤醒后重新进入rt_mq_recv又阻塞了,也就是按 issue 描述回到了等待队列,而此时它在队列里的位置已经排到后来者之后。机理
rt_mq_send()只是把消息挂到队列并把队首等待线程rt_ipc_list_resume(),消息仍留在队列里(日志里entry now = 1可以确认)这正是 @BernardXiong 说的"此处没有做锁定",以及 @dongwencai 提到 uClinux 的做法——只唤醒、不把它从 suspend 队列摘除,等真正拿到锁/数据时才出队。
想请内核维护者决定的方向
RT_IPC_FLAG_FIFO的字面意思,但需要处理"被唤醒后又超时/被信号打断"的边界,改动面在ipc.c的 suspend/resume 路径。rt_mq_send直接把消息交给队首等待者(类似 mailbox 的 handoff),队列里不再有可被抢的副本。改动更大,且要处理接收方超时的情况。RT_IPC_FLAG_FIFO的边界。我个人无法判断哪种符合内核长期意图,但从复现看,行为与
RT_IPC_FLAG_FIFO的名字存在落差,至少第 3 项(文档)是需要的。复现代码(临时 app,未提交)
环境:
bsp/qemu-vexpress-a9,QEMU 11.0.0,xpack arm-none-eabi-gcc 15.2.1,BSP 默认配置(未开 SMP)。RT_IPC_FLAG_FIFO与RT_IPC_FLAG_PRIO两种队列 flag 我都试过,现象相同。如果维护者认为应该修,我可以按上面任一方向出补丁并补 utest;如果确认是取舍,我可以顺手把文档那条补上。