mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-20 00:31:13 +00:00
atomicqueue: fix subtle race
Fix a race where the reader would see the updated the tail pointer before the write could write the data into the queue. Fix this by having a separate reader tail pointer that is only incremented after the writer wrote the data.
This commit is contained in:
parent
beea57dca7
commit
61e8fa0dc5
1 changed files with 8 additions and 3 deletions
|
@ -57,6 +57,7 @@ struct _GstAQueueMem
|
||||||
gpointer *array;
|
gpointer *array;
|
||||||
volatile gint head;
|
volatile gint head;
|
||||||
volatile gint tail;
|
volatile gint tail;
|
||||||
|
volatile gint tail_read;
|
||||||
GstAQueueMem *next;
|
GstAQueueMem *next;
|
||||||
GstAQueueMem *free;
|
GstAQueueMem *free;
|
||||||
};
|
};
|
||||||
|
@ -84,6 +85,7 @@ new_queue_mem (guint size, gint pos)
|
||||||
mem->array = g_new0 (gpointer, mem->size + 1);
|
mem->array = g_new0 (gpointer, mem->size + 1);
|
||||||
mem->head = pos;
|
mem->head = pos;
|
||||||
mem->tail = pos;
|
mem->tail = pos;
|
||||||
|
mem->tail_read = pos;
|
||||||
mem->next = NULL;
|
mem->next = NULL;
|
||||||
mem->free = NULL;
|
mem->free = NULL;
|
||||||
|
|
||||||
|
@ -234,7 +236,7 @@ gst_atomic_queue_peek (GstAtomicQueue * queue)
|
||||||
head_mem = g_atomic_pointer_get (&queue->head_mem);
|
head_mem = g_atomic_pointer_get (&queue->head_mem);
|
||||||
|
|
||||||
head = g_atomic_int_get (&head_mem->head);
|
head = g_atomic_int_get (&head_mem->head);
|
||||||
tail = g_atomic_int_get (&head_mem->tail);
|
tail = g_atomic_int_get (&head_mem->tail_read);
|
||||||
size = head_mem->size;
|
size = head_mem->size;
|
||||||
|
|
||||||
/* when we are not empty, we can continue */
|
/* when we are not empty, we can continue */
|
||||||
|
@ -291,7 +293,7 @@ gst_atomic_queue_pop (GstAtomicQueue * queue)
|
||||||
head_mem = g_atomic_pointer_get (&queue->head_mem);
|
head_mem = g_atomic_pointer_get (&queue->head_mem);
|
||||||
|
|
||||||
head = g_atomic_int_get (&head_mem->head);
|
head = g_atomic_int_get (&head_mem->head);
|
||||||
tail = g_atomic_int_get (&head_mem->tail);
|
tail = g_atomic_int_get (&head_mem->tail_read);
|
||||||
size = head_mem->size;
|
size = head_mem->size;
|
||||||
|
|
||||||
/* when we are not empty, we can continue */
|
/* when we are not empty, we can continue */
|
||||||
|
@ -380,6 +382,9 @@ gst_atomic_queue_push (GstAtomicQueue * queue, gpointer data)
|
||||||
tail + 1));
|
tail + 1));
|
||||||
|
|
||||||
tail_mem->array[tail & size] = data;
|
tail_mem->array[tail & size] = data;
|
||||||
|
|
||||||
|
/* and now the readers can read */
|
||||||
|
g_atomic_int_inc (&tail_mem->tail_read);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -408,7 +413,7 @@ gst_atomic_queue_length (GstAtomicQueue * queue)
|
||||||
head = g_atomic_int_get (&head_mem->head);
|
head = g_atomic_int_get (&head_mem->head);
|
||||||
|
|
||||||
tail_mem = g_atomic_pointer_get (&queue->tail_mem);
|
tail_mem = g_atomic_pointer_get (&queue->tail_mem);
|
||||||
tail = g_atomic_int_get (&tail_mem->tail);
|
tail = g_atomic_int_get (&tail_mem->tail_read);
|
||||||
|
|
||||||
#ifdef LOW_MEM
|
#ifdef LOW_MEM
|
||||||
if (g_atomic_int_dec_and_test (&queue->num_readers))
|
if (g_atomic_int_dec_and_test (&queue->num_readers))
|
||||||
|
|
Loading…
Reference in a new issue