1/* @title: Locked list */
2#pragma once
3#include <kassert.h>
4#include <structures/list.h>
5#include <sync/spinlock.h>
6
7/* Doubly linked list with a lock and counter for elements */
8
9struct locked_list {
10 struct list_head list;
11 struct spinlock lock;
12 size_t num_elems : 63;
13 bool lock_irq_disable : 1;
14};
15
16static inline enum irql locked_list_lock(struct locked_list *ll) {
17 if (ll->lock_irq_disable) {
18 return spin_lock_irq_disable(lock: &ll->lock);
19 } else {
20 return spin_lock(lock: &ll->lock);
21 }
22}
23
24static inline void locked_list_unlock(struct locked_list *ll, enum irql irql) {
25 spin_unlock(lock: &ll->lock, old: irql);
26}
27
28#define LOCKED_LIST_INIT(ll, irq_disable) \
29 (struct locked_list) { \
30 .list = LIST_HEAD_INIT(ll.list), .lock = SPINLOCK_INIT, \
31 .num_elems = ATOMIC_VAR_INIT(0), .lock_irq_disable = irq_disable \
32 }
33
34#define LOCKED_LIST_DEFINE(name, irq_disable) \
35 struct locked_list name = LOCKED_LIST_INIT(name, irq_disable)
36
37#define LOCKED_LIST_INIT_IRQ_DISABLE true
38#define LOCKED_LIST_INIT_NORMAL false
39#define LOCKED_LIST_DO(ll, action) \
40 enum irql __macro_irql = locked_list_lock(ll); \
41 action; \
42 locked_list_unlock(ll, __macro_irql);
43
44static inline bool locked_list_empty(struct locked_list *ll) {
45 LOCKED_LIST_DO(ll, bool empty = list_empty(&ll->list));
46 return empty;
47}
48
49static inline void locked_list_add(struct locked_list *ll,
50 struct list_head *lh) {
51 LOCKED_LIST_DO(ll, list_add(lh, &ll->list); ll->num_elems++;);
52}
53
54static inline void locked_list_del(struct locked_list *ll,
55 struct list_head *lh) {
56 LOCKED_LIST_DO(ll, list_del_init(lh); ll->num_elems--;);
57}
58
59static inline void locked_list_del_locked(struct locked_list *ll,
60 struct list_head *lh) {
61 kassert(spinlock_held(&ll->lock));
62 list_del_init(entry: lh);
63 ll->num_elems--;
64}
65
66static inline struct list_head *locked_list_pop_front(struct locked_list *ll) {
67 LOCKED_LIST_DO(ll, struct list_head *ret = list_pop_front(&ll->list));
68 return ret;
69}
70
71static inline size_t locked_list_num_elems(struct locked_list *ll) {
72 LOCKED_LIST_DO(ll, size_t ret = ll->num_elems);
73 return ret;
74}
75
76static inline void locked_list_init(struct locked_list *ll, bool irq_disable) {
77 INIT_LIST_HEAD(list: &ll->list);
78 spinlock_init(lock: &ll->lock);
79 ll->num_elems = 0;
80 ll->lock_irq_disable = irq_disable;
81}
82