1 /* 2 * Copyright (c) 2020 Intel Corporation 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 #ifndef ZEPHYR_INCLUDE_SYS_P4WQ_H_ 7 #define ZEPHYR_INCLUDE_SYS_P4WQ_H_ 8 9 #include <zephyr/kernel.h> 10 #include <zephyr/sys/iterable_sections.h> 11 12 /* Zephyr Pooled Parallel Preemptible Priority-based Work Queues */ 13 14 struct k_p4wq_work; 15 16 /** 17 * P4 Queue handler callback 18 */ 19 typedef void (*k_p4wq_handler_t)(struct k_p4wq_work *work); 20 21 /** 22 * @brief P4 Queue Work Item 23 * 24 * User-populated struct representing a single work item. The 25 * priority and deadline fields are interpreted as thread scheduling 26 * priorities, exactly as per k_thread_priority_set() and 27 * k_thread_deadline_set(). 28 */ 29 struct k_p4wq_work { 30 /* Filled out by submitting code */ 31 int32_t priority; 32 int32_t deadline; 33 k_p4wq_handler_t handler; 34 bool sync; 35 struct k_sem done_sem; 36 37 /* reserved for implementation */ 38 union { 39 struct rbnode rbnode; 40 sys_dlist_t dlnode; 41 }; 42 struct k_thread *thread; 43 struct k_p4wq *queue; 44 }; 45 46 #define K_P4WQ_QUEUE_PER_THREAD BIT(0) 47 #define K_P4WQ_DELAYED_START BIT(1) 48 #define K_P4WQ_USER_CPU_MASK BIT(2) 49 50 /** 51 * @brief P4 Queue 52 * 53 * Kernel pooled parallel preemptible priority-based work queue 54 */ 55 struct k_p4wq { 56 struct k_spinlock lock; 57 58 /* Pending threads waiting for work items 59 * 60 * FIXME: a waitq isn't really the right data structure here. 61 * Wait queues are priority-sorted, but we don't want that 62 * sorting overhead since we're effectively doing it ourselves 63 * by directly mutating the priority when a thread is 64 * unpended. We just want "blocked threads on a list", but 65 * there's no clean scheduler API for that. 66 */ 67 _wait_q_t waitq; 68 69 /* Work items waiting for processing */ 70 struct rbtree queue; 71 72 /* Work items in progress */ 73 sys_dlist_t active; 74 75 /* K_P4WQ_* flags above */ 76 uint32_t flags; 77 }; 78 79 struct k_p4wq_initparam { 80 uint32_t num; 81 uintptr_t stack_size; 82 struct k_p4wq *queue; 83 struct k_thread *threads; 84 struct z_thread_stack_element *stacks; 85 uint32_t flags; 86 }; 87 88 /** 89 * @brief Statically initialize a P4 Work Queue 90 * 91 * Statically defines a struct k_p4wq object with the specified number 92 * of threads which will be initialized at boot and ready for use on 93 * entry to main(). 94 * 95 * @param name Symbol name of the struct k_p4wq that will be defined 96 * @param n_threads Number of threads in the work queue pool 97 * @param stack_sz Requested stack size of each thread, in bytes 98 */ 99 #define K_P4WQ_DEFINE(name, n_threads, stack_sz) \ 100 static K_THREAD_STACK_ARRAY_DEFINE(_p4stacks_##name, \ 101 n_threads, stack_sz); \ 102 static struct k_thread _p4threads_##name[n_threads]; \ 103 static struct k_p4wq name; \ 104 static const STRUCT_SECTION_ITERABLE(k_p4wq_initparam, \ 105 _init_##name) = { \ 106 .num = n_threads, \ 107 .stack_size = stack_sz, \ 108 .threads = _p4threads_##name, \ 109 .stacks = &(_p4stacks_##name[0][0]), \ 110 .queue = &name, \ 111 .flags = 0, \ 112 } 113 114 /** 115 * @brief Statically initialize an array of P4 Work Queues 116 * 117 * Statically defines an array of struct k_p4wq objects with the specified 118 * number of threads which will be initialized at boot and ready for use on 119 * entry to main(). 120 * 121 * @param name Symbol name of the struct k_p4wq array that will be defined 122 * @param n_threads Number of threads and work queues 123 * @param stack_sz Requested stack size of each thread, in bytes 124 * @param flg Flags 125 */ 126 #define K_P4WQ_ARRAY_DEFINE(name, n_threads, stack_sz, flg) \ 127 static K_THREAD_STACK_ARRAY_DEFINE(_p4stacks_##name, \ 128 n_threads, stack_sz); \ 129 static struct k_thread _p4threads_##name[n_threads]; \ 130 static struct k_p4wq name[n_threads]; \ 131 static const STRUCT_SECTION_ITERABLE(k_p4wq_initparam, \ 132 _init_##name) = { \ 133 .num = n_threads, \ 134 .stack_size = stack_sz, \ 135 .threads = _p4threads_##name, \ 136 .stacks = &(_p4stacks_##name[0][0]), \ 137 .queue = name, \ 138 .flags = K_P4WQ_QUEUE_PER_THREAD | flg, \ 139 } 140 141 /** 142 * @brief Initialize P4 Queue 143 * 144 * Initializes a P4 Queue object. These objects must be initialized 145 * via this function (or statically using K_P4WQ_DEFINE) before any 146 * other API calls are made on it. 147 * 148 * @param queue P4 Queue to initialize 149 */ 150 void k_p4wq_init(struct k_p4wq *queue); 151 152 /** 153 * @brief Dynamically add a thread object to a P4 Queue pool 154 * 155 * Adds a thread to the pool managed by a P4 queue. The thread object 156 * must not be in use. If k_thread_create() has previously been 157 * called on it, it must be aborted before being given to the queue. 158 * 159 * @param queue P4 Queue to which to add the thread 160 * @param thread Uninitialized/aborted thread object to add 161 * @param stack Thread stack memory 162 * @param stack_size Thread stack size 163 */ 164 void k_p4wq_add_thread(struct k_p4wq *queue, struct k_thread *thread, 165 k_thread_stack_t *stack, 166 size_t stack_size); 167 168 /** 169 * @brief Submit work item to a P4 queue 170 * 171 * Submits the specified work item to the queue. The caller must have 172 * already initialized the relevant fields of the struct. The queue 173 * will execute the handler when CPU time is available and when no 174 * higher-priority work items are available. The handler may be 175 * invoked on any CPU. 176 * 177 * The caller must not mutate the struct while it is stored in the 178 * queue. The memory should remain unchanged until k_p4wq_cancel() is 179 * called or until the entry to the handler function. 180 * 181 * @note This call is a scheduling point, so if the submitted item (or 182 * any other ready thread) has a higher priority than the current 183 * thread and the current thread has a preemptible priority then the 184 * caller will yield. 185 * 186 * @param queue P4 Queue to which to submit 187 * @param item P4 work item to be submitted 188 */ 189 void k_p4wq_submit(struct k_p4wq *queue, struct k_p4wq_work *item); 190 191 /** 192 * @brief Cancel submitted P4 work item 193 * 194 * Cancels a previously-submitted work item and removes it from the 195 * queue. Returns true if the item was found in the queue and 196 * removed. If the function returns false, either the item was never 197 * submitted, has already been executed, or is still running. 198 * 199 * @return true if the item was successfully removed, otherwise false 200 */ 201 bool k_p4wq_cancel(struct k_p4wq *queue, struct k_p4wq_work *item); 202 203 /** 204 * @brief Regain ownership of the work item, wait for completion if it's synchronous 205 */ 206 int k_p4wq_wait(struct k_p4wq_work *work, k_timeout_t timeout); 207 208 void k_p4wq_enable_static_thread(struct k_p4wq *queue, struct k_thread *thread, 209 uint32_t cpu_mask); 210 211 #endif /* ZEPHYR_INCLUDE_SYS_P4WQ_H_ */ 212