include/drm/spsc_queue.h

Source file repositories/reference/linux-study-clean/include/drm/spsc_queue.h

File Facts

System
Linux kernel
Corpus path
include/drm/spsc_queue.h
Extension
.h
Size
3157 bytes
Lines
125
Domain
Repository Root And Misc
Bucket
include
Inferred role
Repository Root And Misc: implementation source
Status
source implementation candidate

Why This File Exists

Top-level or miscellaneous repository surface. Use this as map coverage unless a later manual pass promotes the file into a deeper subsystem dossier.

Dependency Surface

Detected Declarations

Annotated Snippet

struct spsc_node {

	/* Stores spsc_node* */
	struct spsc_node *next;
};

struct spsc_queue {

	 struct spsc_node *head;

	/* atomic pointer to struct spsc_node* */
	atomic_long_t tail;

	atomic_t job_count;
};

static inline void spsc_queue_init(struct spsc_queue *queue)
{
	queue->head = NULL;
	atomic_long_set(&queue->tail, (long)&queue->head);
	atomic_set(&queue->job_count, 0);
}

static inline struct spsc_node *spsc_queue_peek(struct spsc_queue *queue)
{
	return queue->head;
}

static inline int spsc_queue_count(struct spsc_queue *queue)
{
	return atomic_read(&queue->job_count);
}

static inline bool spsc_queue_push(struct spsc_queue *queue, struct spsc_node *node)
{
	struct spsc_node **tail;

	node->next = NULL;

	preempt_disable();

	atomic_inc(&queue->job_count);
	smp_mb__after_atomic();

	tail = (struct spsc_node **)atomic_long_xchg(&queue->tail, (long)&node->next);
	WRITE_ONCE(*tail, node);

	/*
	 * In case of first element verify new node will be visible to the consumer
	 * thread when we ping the kernel thread that there is new work to do.
	 */
	smp_wmb();

	preempt_enable();

	return tail == &queue->head;
}


static inline struct spsc_node *spsc_queue_pop(struct spsc_queue *queue)
{
	struct spsc_node *next, *node;

	/* Verify reading from memory and not the cache */
	smp_rmb();

	node = READ_ONCE(queue->head);

	if (!node)
		return NULL;

	next = READ_ONCE(node->next);
	WRITE_ONCE(queue->head, next);

	if (unlikely(!next)) {
		/* slowpath for the last element in the queue */

		if (atomic_long_cmpxchg(&queue->tail,
				(long)&node->next, (long) &queue->head) != (long)&node->next) {
			/* Updating tail failed wait for new next to appear */
			do {
				smp_rmb();
			} while (unlikely(!(queue->head = READ_ONCE(node->next))));
		}
	}

	atomic_dec(&queue->job_count);
	return node;
}

Annotation

Implementation Notes