/* Copyright (C) 2021,2022 fef . All rights reserved. */ #pragma once #include #include #include #include /** * @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; \ }) /** @} */