summaryrefslogtreecommitdiff
path: root/components/drivers/ipc/dataqueue.c
diff options
context:
space:
mode:
authorGuEe-GUI <[email protected]>2026-07-22 22:25:04 +0800
committerRbb666 <[email protected]>2026-08-03 09:43:57 +0800
commit9915dc66c197b9df63701bc3cb7837cd78b6f5d9 (patch)
tree8ba09a3c6deee634bfc4f4f83dc883de783f75d8 /components/drivers/ipc/dataqueue.c
parentfe751c152101fc88ad887b06d91e2d96aafc2883 (diff)
ipc: fix recursive data queue locking on SMP
rt_data_queue_pop() holds the data queue spinlock while updating the ring state, then calls rt_data_queue_len(). The length function tries to acquire the same non-recursive spinlock again, causing an SMP deadlock when a pop leaves the queue non-empty. Add a private _data_queue_len_nolock() helper for callers which already hold the queue lock. Keep the public rt_data_queue_len() protected by one spinlock acquisition. This does not change the public API, ABI, queue state transitions, low-water mark wakeups, or event callback behavior. Tested on a four-core Spacemit K1 with cyclic HDMI playback and by building the SMP QEMU Virt64 RISC-V BSP with generic audio, Intel HDA and VirtIO Sound. Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components/drivers/ipc/dataqueue.c')
-rw-r--r--components/drivers/ipc/dataqueue.c35
1 files changed, 17 insertions, 18 deletions
diff --git a/components/drivers/ipc/dataqueue.c b/components/drivers/ipc/dataqueue.c
index f1ee2bd576..a73cca458a 100644
--- a/components/drivers/ipc/dataqueue.c
+++ b/components/drivers/ipc/dataqueue.c
@@ -22,6 +22,20 @@ struct rt_data_item
rt_size_t data_size;
};
+static rt_uint16_t _data_queue_len_nolock(struct rt_data_queue *queue)
+{
+ if (queue->is_empty)
+ {
+ return 0;
+ }
+ if (queue->put_index > queue->get_index)
+ {
+ return queue->put_index - queue->get_index;
+ }
+
+ return queue->size + queue->put_index - queue->get_index;
+}
+
/**
* @brief This function will initialize the data queue. Calling this function will
* initialize the data queue control block and set the notification callback function.
@@ -283,7 +297,7 @@ rt_err_t rt_data_queue_pop(struct rt_data_queue *queue,
queue->is_empty = 1;
}
- if (rt_data_queue_len(queue) <= queue->lwm)
+ if (_data_queue_len_nolock(queue) <= queue->lwm)
{
/* there is at least one thread in suspended list */
if (rt_susp_list_dequeue(&queue->suspended_push_list,
@@ -432,30 +446,15 @@ RTM_EXPORT(rt_data_queue_deinit);
rt_uint16_t rt_data_queue_len(struct rt_data_queue *queue)
{
rt_base_t level;
- rt_int16_t len;
+ rt_uint16_t len;
RT_ASSERT(queue != RT_NULL);
RT_ASSERT(queue->magic == DATAQUEUE_MAGIC);
- if (queue->is_empty)
- {
- return 0;
- }
-
level = rt_spin_lock_irqsave(&(queue->spinlock));
-
- if (queue->put_index > queue->get_index)
- {
- len = queue->put_index - queue->get_index;
- }
- else
- {
- len = queue->size + queue->put_index - queue->get_index;
- }
-
+ len = _data_queue_len_nolock(queue);
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
return len;
}
RTM_EXPORT(rt_data_queue_len);
-