1/* @title: Locked list */
2#pragma once
3#include <enforce.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 spinlock lock;
11 struct list_head list TSA_GUARDED_BY(lock);
12 size_t num_elems : 63;
13 bool lock_high : 1;
14};
15
16static inline enum irql locked_list_lock(struct locked_list *ll)
17 TSA_ACQUIRES_SPIN(&ll->lock) {
18 if (ll->lock_high) {
19 return spin_lock_high(&ll->lock);
20 } else {
21 return spin_lock(&ll->lock);
22 }
23}
24
25static inline void locked_list_unlock(struct locked_list *ll, enum irql irql)
26 TSA_RELEASES_SPIN(&ll->lock) {
27 spin_unlock(&ll->lock, irql);
28}
29
30#define LOCKED_LIST_INIT(ll, irq_disable) \
31 (struct locked_list) { \
32 .list = LIST_HEAD_INIT(ll.list), .lock = SPINLOCK_INIT, \
33 .num_elems = ATOMIC_VAR_INIT(0), .lock_high = irq_disable \
34 }
35
36#define LOCKED_LIST_DEFINE(name, irq_disable) \
37 struct locked_list name = LOCKED_LIST_INIT(name, irq_disable)
38
39#define LOCKED_LIST_INIT_IRQ_DISABLE true
40#define LOCKED_LIST_INIT_NORMAL false
41#define LOCKED_LIST_DO(ll, action) \
42 enum irql __macro_irql = locked_list_lock(ll); \
43 action; \
44 locked_list_unlock(ll, __macro_irql);
45
46static inline bool locked_list_empty(struct locked_list *ll) {
47 LOCKED_LIST_DO(ll, bool empty = list_head_empty(&ll->list));
48 return empty;
49}
50
51static inline void locked_list_add(struct locked_list *ll,
52 struct list_node *lh) {
53 LOCKED_LIST_DO(ll, list_head_push_front(&ll->list, lh); ll->num_elems++;);
54}
55
56static inline void locked_list_del(struct locked_list *ll,
57 struct list_node *lh) {
58 LOCKED_LIST_DO(ll, list_node_delete_init(lh); ll->num_elems--;);
59}
60
61static inline void locked_list_del_locked(struct locked_list *ll,
62 struct list_node *lh) {
63 enforce(spinlock_locked(&ll->lock));
64 list_node_delete_init(n: lh);
65 ll->num_elems--;
66}
67
68static inline struct list_node *locked_list_pop_front(struct locked_list *ll) {
69 LOCKED_LIST_DO(ll, struct list_node *ret = list_head_pop_front(&ll->list));
70 return ret;
71}
72
73static inline size_t locked_list_num_elems(struct locked_list *ll) {
74 LOCKED_LIST_DO(ll, size_t ret = ll->num_elems);
75 return ret;
76}
77
78static inline void locked_list_init(struct locked_list *ll, bool irq_disable) {
79 tsa_unpublished(&ll->lock);
80 list_head_init(h: &ll->list);
81 spinlock_init(&ll->lock);
82 ll->num_elems = 0;
83 ll->lock_high = irq_disable;
84}
85