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