| 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 | |
| 9 | struct 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 | |
| 16 | static 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 | |
| 24 | static 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 | |
| 44 | static 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 | |
| 49 | static 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 | |
| 54 | static 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 | |
| 59 | static 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 | |
| 66 | static 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 | |
| 71 | static 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 | |
| 76 | static 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 | |