Line data Source code
1 0 : /* 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 1 : 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 1 : struct k_p4wq_work { 30 : /* Filled out by submitting code */ 31 0 : int32_t priority; 32 0 : int32_t deadline; 33 0 : k_p4wq_handler_t handler; 34 0 : bool sync; 35 0 : struct k_sem done_sem; 36 : 37 : /* reserved for implementation */ 38 : union { 39 0 : struct rbnode rbnode; 40 0 : sys_dlist_t dlnode; 41 0 : }; 42 0 : struct k_thread *thread; 43 0 : struct k_p4wq *queue; 44 : }; 45 : 46 0 : #define K_P4WQ_QUEUE_PER_THREAD BIT(0) 47 0 : #define K_P4WQ_DELAYED_START BIT(1) 48 0 : #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 1 : struct k_p4wq { 56 0 : 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 0 : _wait_q_t waitq; 68 : 69 : /* Work items waiting for processing */ 70 0 : struct rbtree queue; 71 : 72 : /* Work items in progress */ 73 0 : sys_dlist_t active; 74 : 75 : /* K_P4WQ_* flags above */ 76 0 : uint32_t flags; 77 : }; 78 : 79 0 : struct k_p4wq_initparam { 80 0 : uint32_t num; 81 0 : uintptr_t stack_size; 82 0 : struct k_p4wq *queue; 83 0 : struct k_thread *threads; 84 0 : struct z_thread_stack_element *stacks; 85 0 : 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 1 : #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 1 : #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 1 : 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 1 : 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 1 : 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 1 : 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 1 : int k_p4wq_wait(struct k_p4wq_work *work, k_timeout_t timeout); 207 : 208 0 : 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_ */