You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

102 lines
2.7 KiB
C

/* Copyright (C) 2021,2022 fef <owo@fef.moe>. All rights reserved. */
#pragma once
#include <arch/atom.h>
#include <gay/mm.h>
#include <gay/types.h>
#include <gay/util.h>
/**
* @defgroup kqueue Lock Free FIFO (kqueue)
*
* kqueue is a simple API that allows any structure to become part of a
* lock-free FIFO queue. It only uses atomic primitives and spin-wait loops,
* which makes it safe to use even from irq context. Furthermore, it supports
* multiple concurrent emitters *and* consumers, making it suitable for stuff
* like serving as the backend for a basic batch processing system distributed
* across several CPUs.
*
* @{
*/
/** @brief Embed this into structs that you want to put in a kqueue. */
struct kq_node {
patom_t next;
};
/** @brief Lock free FIFO with support for multiple emitters and consumers. */
struct kqueue {
patom_t head;
patom_t tail;
struct kq_node _dummy;
};
/**
* @brief Initialize a kqueue.
*
* @param kq kqueue to initialize
*/
static inline void kq_init(struct kqueue *kq)
{
patom_init(&kq->head, &kq->_dummy);
patom_init(&kq->tail, &kq->_dummy);
patom_init(&kq->_dummy.next, nil);
}
/**
* @brief Allocate a new kqueue and initialize it.
*
* @param flags Flags for `kmalloc()`
* @return The initialized kqueue, or `nil` if OOM
*/
struct kqueue *kq_create(enum mflags flags);
/**
* @brief Add a new entry to the end of a kqueue.
*
* @param kq kqueue to append the entry to
* @param node New node to append to the queue
*/
void kq_add(struct kqueue *kq, struct kq_node *node);
/**
* @brief Remove the first item in a kqueue.
*
* @param kq kqueue to remove an item from
* @return The removed item, or `nil` if the queue was empty
*/
struct kq_node *kq_del(struct kqueue *kq);
/**
* @brief Cast a kqueue entry out to the structure it is embedded in.
*
* @param head The `kq_node_t *` to cast out of
* @param type Type of the containing structure
* @param member Name of the `kq_node_t` within the structure
* @returns The `struct *` that `head` is embedded in
*/
#define kq_entry(head, type, member) container_of(head, type, member)
/**
* @brief Remove the first item in a kqueue and return the structure
* it is embedded in.
*
* @param kq kqueue to remove an item from
* @param type Type of the containing structure
* @param member Name of the `kq_node_t` within the structure
* @returns The `struct *` that was removed from the queue,
* or `nil` if the queue was empty
*/
#define kq_del_entry(kq, type, member) ({ \
struct kq_node *__node = kq_del(kq); \
/* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
type *__entry = nil; \
if (__node != nil) \
__entry = kq_entry(__node, type, member); \
__entry; \
})
/** @} */