1#include <stdarg.h>
2#include <thread/workqueue.h>
3
4#define DEQUEUE_FROM_ONESHOT_CODE 2
5#define DEQUEUE_FROM_REGULAR_CODE 1
6
7#define work_from_worklist_node(node) container_of(node, struct work, list_node)
8
9static inline enum irql workqueue_lock(struct workqueue *workqueue) {
10 if (workqueue->attrs.flags & WORKQUEUE_FLAG_ISR_SAFE) {
11 return spin_lock_irq_disable(lock: &workqueue->lock);
12 } else {
13 return spin_lock(lock: &workqueue->lock);
14 }
15}
16
17#define WORKQUEUE_NUM_WORKS(wq) (atomic_load(&wq->num_tasks))
18
19static inline uint64_t workqueue_current_worker_count(struct workqueue *q) {
20 return atomic_load(&q->num_workers);
21}
22
23static inline bool workqueue_works_empty(struct workqueue *queue) {
24 enum irql irql = spin_lock_irq_disable(lock: &queue->work_lock);
25 bool empty = list_empty(head: &queue->works);
26 spin_unlock(lock: &queue->work_lock, old: irql);
27 return empty;
28}
29
30static inline bool workqueue_empty(struct workqueue *queue) {
31 return atomic_load(&queue->num_tasks) == 0;
32}
33
34static inline void workqueue_set_needs_spawn(struct workqueue *queue,
35 bool needs) {
36 atomic_store(&queue->spawn_pending, needs);
37}
38
39static inline bool workqueue_needs_spawn(struct workqueue *queue) {
40 return atomic_load(&queue->spawn_pending);
41}
42
43static inline bool workqueue_get(struct workqueue *queue) {
44 return refcount_inc(rc: &queue->refcount);
45}
46
47static inline void workqueue_put(struct workqueue *queue) {
48 if (refcount_dec_and_test(rc: &queue->refcount))
49 return workqueue_free(queue);
50}
51
52/* Regardless of if we use static workers or not this will
53 * always be the list of workers we have */
54static inline void workqueue_add_worker(struct workqueue *wq,
55 struct worker *wker) {
56 enum irql irql = spin_lock_irq_disable(lock: &wq->worker_lock);
57 list_add(new: &wker->list_node, head: &wq->workers);
58 spin_unlock(lock: &wq->worker_lock, old: irql);
59}
60
61static inline void workqueue_remove_worker(struct workqueue *wq,
62 struct worker *worker) {
63 enum irql irql = spin_lock_irq_disable(lock: &wq->worker_lock);
64 list_del_init(entry: &worker->list_node);
65 spin_unlock(lock: &wq->worker_lock, old: irql);
66}
67
68static inline bool ignore_timeouts(struct workqueue *q) {
69 return atomic_load(&q->ignore_timeouts);
70}
71
72static inline bool workqueue_usable(struct workqueue *q) {
73 return atomic_load(&q->state) == WORKQUEUE_STATE_ACTIVE;
74}
75
76static inline size_t workqueue_workers(struct workqueue *wq) {
77 return atomic_load(&wq->num_workers);
78}
79
80static inline size_t workqueue_idlers(struct workqueue *wq) {
81 return atomic_load(&wq->idle_workers);
82}
83
84bool workqueue_try_spawn_worker(struct workqueue *queue);
85int32_t workqueue_dequeue_task(struct workqueue *queue, struct work **out,
86 struct work *oneshot_out);
87void workqueue_link_thread_and_worker(struct worker *worker,
88 struct thread *thread);
89bool workqueue_spawn_worker_internal(struct workqueue *queue);
90struct workqueue *workqueue_least_loaded_queue_except(int64_t except_core_num);
91struct workqueue *workqueue_get_least_loaded(void);
92struct workqueue *workqueue_get_least_loaded_remote(void);
93struct worker *workqueue_spawn_permanent_worker(struct workqueue *queue);
94struct workqueue *workqueue_create_internal(struct workqueue_attributes *attrs,
95 const char *fmt, va_list args);
96enum thread_request_decision workqueue_request_callback(struct thread *t,
97 void *data);
98struct thread *worker_create(struct cpu_mask mask, nice_t niceness);
99