#define _LINUX_LIST_H
#include <linux/types.h>
+#include <linux/compiler.h>
#include <linux/stddef.h>
#include <linux/poison.h>
#include <linux/const.h>
pos && ({ n = pos->member.next; 1; }); \
pos = hlist_entry_safe(n, typeof(*pos), member))
+/*
+ * Lists optimised for wait queues, where we should normally add to the tail
+ * and remove from the head. The head pointer points to the first element in
+ * the list. The first element in the list has a 'prev' pointer which points
+ * to the last element in the list. The last element in the list has a 'next'
+ * pointer which is NULL. This reduces memory consumption in the head while
+ * giving us O(1) access to the head and tail of the list, and allowing
+ * deletions from the middle in O(1).
+ */
+
+#define WLIST_HEAD_INIT { .first = NULL }
+#define WLIST_HEAD(name) struct wlist_head name = { .first = NULL }
+#define INIT_WLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_WLIST_NODE(struct wlist_node *w)
+{
+ w->next = NULL;
+ w->prev = NULL;
+}
+
+static inline bool wlist_empty(const struct wlist_head *h)
+{
+ return !READ_ONCE(h->first);
+}
+
+static inline bool wlist_is_singular(const struct wlist_head *head)
+{
+ const struct wlist_node *first = READ_ONCE(head->first);
+
+ return first && first->prev == first;
+}
+
+static inline bool wlist_deleted(const struct wlist_node *node)
+{
+ return !READ_ONCE(node->prev);
+}
+
+/**
+ * wlist_add - Adds a waiter to the tail of the wait list.
+ * @head: Wait list head.
+ * @node: New entry to add.
+ *
+ * Return: true if the queue was empty.
+ */
+static inline bool wlist_add(struct wlist_head *head, struct wlist_node *node)
+{
+ struct wlist_node *first = head->first;
+
+ node->next = NULL;
+ if (first) {
+ struct wlist_node *last = first->prev;
+ node->prev = last;
+ first->prev = node;
+ last->next = node;
+ return false;
+ } else {
+ node->prev = node;
+ head->first = node;
+ return true;
+ }
+}
+
+/* Returns true if the queue was empty */
+static inline bool wlist_add_head(struct wlist_head *head,
+ struct wlist_node *node)
+{
+ struct wlist_node *first = head->first;
+
+ WRITE_ONCE(node->next, first);
+ WRITE_ONCE(head->first, node);
+ if (first) {
+ node->prev = first->prev;
+ first->prev = node;
+ return false;
+ } else {
+ node->prev = node;
+ return true;
+ }
+}
+
+static inline struct wlist_node *__wlist_del_first(struct wlist_head *head,
+ struct wlist_node *node)
+{
+ struct wlist_node *next = node->next;
+
+ if (next)
+ next->prev = node->prev;
+ node->prev = NULL;
+ WRITE_ONCE(head->first, next);
+ return node;
+}
+
+static inline struct wlist_node *wlist_del_first(struct wlist_head *head)
+{
+ return __wlist_del_first(head, head->first);
+}
+
+#define wlist_del_first_entry(head, type, member) \
+ hlist_entry(wlist_del_first(head), type, member)
+
+/* Returns true if the queue is now empty */
+static inline bool wlist_del(struct wlist_head *head, struct wlist_node *node)
+{
+ struct wlist_node *next = node->next;
+ struct wlist_node *prev;
+ struct wlist_node *first = head->first;
+
+ if (first == node) {
+ __wlist_del_first(head, first);
+ return (next == NULL);
+ }
+
+ prev = node->prev;
+ if (next)
+ next->prev = prev;
+ node->prev = NULL;
+ WRITE_ONCE(prev->next, next);
+ if (!next)
+ first->prev = prev;
+ else
+ next->prev = prev;
+ return false;
+}
+
+static inline void wlist_move(struct wlist_head *oldh,
+ struct wlist_node *node, struct wlist_head *newh)
+{
+ wlist_del(oldh, node);
+ wlist_add(newh, node);
+}
+
+#define wlist_first_entry(head, type, member) \
+ hlist_entry_safe((head)->first, type, member)
+
+/**
+ * wlist_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the wlist_node within the struct.
+ */
+#define wlist_for_each_entry hlist_for_each_entry
+
+/**
+ * wlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: a &struct wlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the wlist_node within the struct.
+ */
+#define wlist_for_each_entry_safe hlist_for_each_entry_safe
+
+/**
+ * wlist_for_each_entry_from_safe - iterate over a wlist safe from removal of list entries continuing from current point
+ * @pos: the type * to use as a loop cursor.
+ * @member: the name of the wlist_node within the struct.
+ */
+#define wlist_for_each_entry_from_safe(pos, n, member) \
+ for (; \
+ pos && ({ n = pos->member.next; 1; }); \
+ pos = hlist_entry_safe(n, typeof(*pos), member))
+
#endif
--- /dev/null
+#include <linux/compiler.h>
+#include <asm/barrier.h>
+#include "../../../include/linux/list.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int verbose = 0;
+
+#define printv(level, fmt, ...) \
+ if (verbose >= level) \
+ printf(fmt, ##__VA_ARGS__)
+
+struct item {
+ int i;
+ struct wlist_node list;
+};
+
+struct item *item_create(int i)
+{
+ struct item *item = malloc(sizeof(*item));
+ item->i = i;
+ INIT_WLIST_NODE(&item->list);
+ printv(2, "item %d allocated at %p\n", i, item);
+ return item;
+}
+
+/* Check that an empty list behaves the way we want it to */
+void wlist_test0(struct wlist_head *wlist)
+{
+ struct item *item;
+ struct wlist_node *next;
+
+ assert(wlist_empty(wlist));
+ assert(wlist_first_entry(wlist, struct item, list) == NULL);
+ wlist_for_each_entry(item, wlist, list)
+ assert(0);
+ wlist_for_each_entry_safe(item, next, wlist, list)
+ assert(0);
+ printv(1, "test0 passed\n");
+}
+
+void verify_singleton(struct wlist_head *wlist)
+{
+ assert(wlist->first != NULL);
+ assert(wlist->first->next == NULL);
+ assert(wlist->first->prev == wlist->first);
+}
+
+void verify_doubleton(struct wlist_head *wlist)
+{
+ assert(wlist->first != NULL);
+ assert(wlist->first->next == wlist->first->prev);
+ assert(wlist->first->prev->next == NULL);
+ assert(wlist->first->prev->prev == wlist->first);
+}
+
+void wlist_test1(struct wlist_head *wlist)
+{
+ int i;
+ struct item *item;
+ struct wlist_node *next;
+ struct item *item0 = item_create(0);
+
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add(wlist, &item0->list));
+ assert(!wlist_empty(wlist));
+ verify_singleton(wlist);
+ assert(wlist_first_entry(wlist, struct item, list) == item0);
+ i = 0;
+ wlist_for_each_entry(item, wlist, list)
+ assert(item->i == i++);
+ assert(i == 1);
+
+ wlist_for_each_entry_safe(item, next, wlist, list)
+ wlist_del(wlist, &item->list);
+
+ assert(wlist_deleted(&item0->list));
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add_head(wlist, &item0->list));
+ verify_singleton(wlist);
+ item = item0;
+ i = 0;
+ wlist_for_each_entry_from_safe(item, next, list)
+ assert(item->i == i++);
+ assert(i == 1);
+ wlist_for_each_entry_from_safe(item, next, list)
+ assert(0);
+
+ item = item0;
+ wlist_for_each_entry_from_safe(item, next, list)
+ wlist_del(wlist, &item->list);
+ assert(wlist_empty(wlist));
+
+ free(item0);
+ printv(1, "test1 passed\n");
+}
+
+void wlist_test2(struct wlist_head *wlist)
+{
+ int i;
+ struct item *item;
+ struct wlist_node *next;
+ struct item *item0 = item_create(0);
+ struct item *item1 = item_create(1);
+
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add(wlist, &item0->list));
+ assert(wlist_first_entry(wlist, struct item, list) == item0);
+ assert(!wlist_add(wlist, &item1->list));
+ assert(!wlist_empty(wlist));
+ verify_doubleton(wlist);
+ assert(wlist_first_entry(wlist, struct item, list) == item0);
+ i = 0;
+ wlist_for_each_entry(item, wlist, list)
+ assert(item->i == i++);
+ assert(i == 2);
+
+ assert(!wlist_del(wlist, &item0->list));
+ verify_singleton(wlist);
+ assert(wlist_first_entry(wlist, struct item, list) == item1);
+ i = 1;
+ wlist_for_each_entry(item, wlist, list)
+ assert(item->i == i++);
+ assert(i == 2);
+
+ assert(wlist_del(wlist, &item1->list));
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add_head(wlist, &item1->list));
+ assert(!wlist_add_head(wlist, &item0->list));
+ verify_doubleton(wlist);
+ i = 0;
+ wlist_for_each_entry(item, wlist, list)
+ assert(item->i == i++);
+ assert(i == 2);
+
+ assert(!wlist_del(wlist, &item1->list));
+ verify_singleton(wlist);
+ i = 0;
+ wlist_for_each_entry(item, wlist, list)
+ assert(item->i == i++);
+ assert(i == 1);
+ assert(wlist_del(wlist, &item0->list));
+
+ assert(wlist_add(wlist, &item0->list));
+ assert(!wlist_add(wlist, &item1->list));
+ wlist_for_each_entry_safe(item, next, wlist, list)
+ wlist_del(wlist, &item->list);
+ assert(wlist_empty(wlist));
+
+ free(item0);
+ free(item1);
+ printv(1, "test2 passed\n");
+}
+
+void wlist_test3(struct wlist_head *wlist)
+{
+ int i;
+ struct item *item;
+ struct wlist_node *next;
+ struct item *item0 = item_create(0);
+ struct item *item1 = item_create(1);
+ struct item *item2 = item_create(2);
+
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add(wlist, &item0->list));
+ assert(!wlist_add(wlist, &item1->list));
+ assert(!wlist_add(wlist, &item2->list));
+ assert(!wlist_empty(wlist));
+ assert(wlist_first_entry(wlist, struct item, list) == item0);
+ i = 0;
+ wlist_for_each_entry(item, wlist, list)
+ assert(item->i == i++);
+ assert(i == 3);
+
+ assert(!wlist_del(wlist, &item0->list));
+ verify_doubleton(wlist);
+ assert(wlist_first_entry(wlist, struct item, list) == item1);
+ i = 1;
+ wlist_for_each_entry(item, wlist, list)
+ assert(item->i == i++);
+ assert(i == 3);
+
+ assert(!wlist_del(wlist, &item1->list));
+ verify_singleton(wlist);
+ assert(wlist_first_entry(wlist, struct item, list) == item2);
+ assert(wlist_del(wlist, &item2->list));
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add(wlist, &item0->list));
+ assert(!wlist_add(wlist, &item1->list));
+ assert(!wlist_add(wlist, &item2->list));
+ assert(!wlist_del(wlist, &item1->list));
+ verify_doubleton(wlist);
+ assert(wlist_first_entry(wlist, struct item, list) == item0);
+ i = 0;
+ wlist_for_each_entry(item, wlist, list) {
+ assert(item->i == i);
+ i += 2;
+ }
+ assert(i == 4);
+ assert(!wlist_del(wlist, &item0->list));
+ assert(wlist_del(wlist, &item2->list));
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add(wlist, &item0->list));
+ assert(!wlist_add(wlist, &item1->list));
+ assert(!wlist_add(wlist, &item2->list));
+ assert(!wlist_del(wlist, &item2->list));
+ verify_doubleton(wlist);
+ assert(wlist_first_entry(wlist, struct item, list) == item0);
+ i = 0;
+ wlist_for_each_entry(item, wlist, list)
+ assert(item->i == i++);
+ assert(i == 2);
+ assert(!wlist_del(wlist, &item0->list));
+ assert(wlist_del(wlist, &item1->list));
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add(wlist, &item0->list));
+ assert(!wlist_add(wlist, &item1->list));
+ assert(!wlist_add(wlist, &item2->list));
+ item = item0;
+ wlist_for_each_entry_from_safe(item, next, list)
+ wlist_del(wlist, &item->list);
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add(wlist, &item0->list));
+ assert(!wlist_add(wlist, &item1->list));
+ assert(!wlist_add(wlist, &item2->list));
+ wlist_for_each_entry_safe(item, next, wlist, list)
+ wlist_del(wlist, &item->list);
+ assert(wlist_empty(wlist));
+
+ assert(wlist_add(wlist, &item0->list));
+ assert(!wlist_add(wlist, &item1->list));
+ assert(!wlist_add(wlist, &item2->list));
+ assert(wlist_del_first(wlist) == &item0->list);
+ assert(wlist_del_first(wlist) == &item1->list);
+ assert(wlist_del_first(wlist) == &item2->list);
+ assert(wlist_empty(wlist));
+
+ free(item0);
+ free(item1);
+ free(item2);
+ printv(1, "test3 passed\n");
+}
+
+int main(int argc, char **argv)
+{
+ int opt;
+ WLIST_HEAD(wlist);
+
+ while ((opt = getopt(argc, argv, "v")) != -1) {
+ if (opt == 'v')
+ verbose++;
+ }
+
+ wlist_test0(&wlist);
+ wlist_test1(&wlist);
+ wlist_test2(&wlist);
+ wlist_test3(&wlist);
+ return 0;
+}