| 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 | |
| 9 | static 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 | |
| 19 | static inline uint64_t workqueue_current_worker_count(struct workqueue *q) { |
| 20 | return atomic_load(&q->num_workers); |
| 21 | } |
| 22 | |
| 23 | static 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 | |
| 30 | static inline bool workqueue_empty(struct workqueue *queue) { |
| 31 | return atomic_load(&queue->num_tasks) == 0; |
| 32 | } |
| 33 | |
| 34 | static inline void workqueue_set_needs_spawn(struct workqueue *queue, |
| 35 | bool needs) { |
| 36 | atomic_store(&queue->spawn_pending, needs); |
| 37 | } |
| 38 | |
| 39 | static inline bool workqueue_needs_spawn(struct workqueue *queue) { |
| 40 | return atomic_load(&queue->spawn_pending); |
| 41 | } |
| 42 | |
| 43 | static inline bool workqueue_get(struct workqueue *queue) { |
| 44 | return refcount_inc(rc: &queue->refcount); |
| 45 | } |
| 46 | |
| 47 | static 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 */ |
| 54 | static 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 | |
| 61 | static 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 | |
| 68 | static inline bool ignore_timeouts(struct workqueue *q) { |
| 69 | return atomic_load(&q->ignore_timeouts); |
| 70 | } |
| 71 | |
| 72 | static inline bool workqueue_usable(struct workqueue *q) { |
| 73 | return atomic_load(&q->state) == WORKQUEUE_STATE_ACTIVE; |
| 74 | } |
| 75 | |
| 76 | static inline size_t workqueue_workers(struct workqueue *wq) { |
| 77 | return atomic_load(&wq->num_workers); |
| 78 | } |
| 79 | |
| 80 | static inline size_t workqueue_idlers(struct workqueue *wq) { |
| 81 | return atomic_load(&wq->idle_workers); |
| 82 | } |
| 83 | |
| 84 | bool workqueue_try_spawn_worker(struct workqueue *queue); |
| 85 | int32_t workqueue_dequeue_task(struct workqueue *queue, struct work **out, |
| 86 | struct work *oneshot_out); |
| 87 | void workqueue_link_thread_and_worker(struct worker *worker, |
| 88 | struct thread *thread); |
| 89 | bool workqueue_spawn_worker_internal(struct workqueue *queue); |
| 90 | struct workqueue *workqueue_least_loaded_queue_except(int64_t except_core_num); |
| 91 | struct workqueue *workqueue_get_least_loaded(void); |
| 92 | struct workqueue *workqueue_get_least_loaded_remote(void); |
| 93 | struct worker *workqueue_spawn_permanent_worker(struct workqueue *queue); |
| 94 | struct workqueue *workqueue_create_internal(struct workqueue_attributes *attrs, |
| 95 | const char *fmt, va_list args); |
| 96 | enum thread_request_decision workqueue_request_callback(struct thread *t, |
| 97 | void *data); |
| 98 | struct thread *worker_create(struct cpu_mask mask, nice_t niceness); |
| 99 | |