1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2016 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 #ifndef __NV_KTHREAD_QUEUE_H__ 25 #define __NV_KTHREAD_QUEUE_H__ 26 27 struct nv_kthread_q; 28 struct nv_kthread_q_item; 29 typedef struct nv_kthread_q nv_kthread_q_t; 30 typedef struct nv_kthread_q_item nv_kthread_q_item_t; 31 32 typedef void (*nv_q_func_t)(void *args); 33 34 #include "nv-kthread-q-os.h" 35 36 //////////////////////////////////////////////////////////////////////////////// 37 // nv_kthread_q: 38 // 39 // 1. API and overview 40 // 41 // This "nv_kthread_q" system implements a simple queuing system for deferred 42 // work. The nv_kthread_q system has goals and use cases that are similar to 43 // the named workqueues in the Linux kernel, but nv_kthread_q is much (10x or 44 // so) smaller, simpler--and correspondingly less general. Deferred work 45 // items are put into a queue, and run within the context of a dedicated set 46 // of kernel threads (kthread). 47 // 48 // In order to avoid confusion with the Linux workqueue system, I have 49 // avoided using the term "work", and instead refer to "queues" (also called 50 // "q's") and "queue items" (also called "q_items"), in both variable names 51 // and comments. 52 // 53 // This module depends only upon the Linux kernel. 54 // 55 // Queue items that are submitted to separate nv_kthread_q instances are 56 // guaranteed to be run in different kthreads. 57 // 58 // Queue items that are submitted to the same nv_kthread_q are not guaranteed 59 // to be serialized, nor are they guaranteed to run concurrently. 60 // 61 // 2. Allocations 62 // 63 // The caller allocates queues and queue items. The nv_kthread_q APIs do 64 // the initialization (zeroing and setup) of queues and queue items. 65 // Allocation is handled that way, because one of the first use cases is a 66 // bottom half interrupt handler, and for that, queue items should be 67 // pre-allocated (for example, one per GPU), so that no allocation is 68 // required in the top-half interrupt handler. Relevant API calls: 69 // 70 // 3. Queue initialization 71 // 72 // nv_kthread_q_init() initializes a queue on the current NUMA node. 73 // 74 // or 75 // 76 // nv_kthread_q_init_on_node() initializes a queue on a specific NUMA node. 77 // 78 // 3. Scheduling things for the queue to run 79 // 80 // The nv_kthread_q_schedule_q_item() routine will schedule a q_item to run. 81 // 82 // 4. Stopping the queue(s) 83 // 84 // The nv_kthread_q_stop() routine will flush the queue, and safely stop 85 // the kthread, before returning. 86 // 87 //////////////////////////////////////////////////////////////////////////////// 88 89 // 90 // The queue must not be used before calling this routine. 91 // 92 // The caller allocates an nv_kthread_q_t item. This routine initializes 93 // the queue, and starts up a kernel thread ("kthread") to service the queue. 94 // The queue will initially be empty; there is intentionally no way to 95 // pre-initialize the queue with items to run. 96 // 97 // In order to avoid external dependencies (specifically, NV_STATUS codes), this 98 // returns a Linux kernel (negative) errno on failure, and zero on success. It 99 // is safe to call nv_kthread_q_stop() on a queue that nv_kthread_q_init() 100 // failed for. 101 // 102 // A short prefix of the qname arg will show up in []'s, via the ps(1) utility. 103 // 104 // The kernel thread stack is preferably allocated on the specified NUMA node, 105 // but fallback to another node is possible because kernel allocators do not 106 // guarantee affinity. Note that NUMA-affinity applies only to 107 // the kthread stack. This API does not do anything about limiting the CPU 108 // affinity of the kthread. That is left to the caller. 109 // 110 // Reusing a queue: once a queue is initialized, it must be safely shut down 111 // (see "Stopping the queue(s)", below), before it can be reused. So, for 112 // a simple queue use case, the following will work: 113 // 114 // nv_kthread_q_init_on_node(&some_q, "display_name", preferred_node); 115 // nv_kthread_q_stop(&some_q); 116 // nv_kthread_q_init_on_node(&some_q, "reincarnated", preferred_node); 117 // nv_kthread_q_stop(&some_q); 118 // 119 int nv_kthread_q_init_on_node(nv_kthread_q_t *q, 120 const char *qname, 121 int preferred_node); 122 123 // 124 // This routine is the same as nv_kthread_q_init_on_node() with the exception 125 // that the queue stack will be allocated on the NUMA node of the caller. 126 // 127 int nv_kthread_q_init(nv_kthread_q_t *q, const char *qname); 128 129 // 130 // The caller is responsible for stopping all queues, by calling this routine 131 // before, for example, kernel module unloading. This nv_kthread_q_stop() 132 // routine will flush the queue, and safely stop the kthread, before returning. 133 // 134 // You may ONLY call nv_kthread_q_stop() once, unless you reinitialize the 135 // queue in between, as shown in the nv_kthread_q_init() documentation, above. 136 // 137 // Do not add any more items to the queue after calling nv_kthread_q_stop. 138 // 139 // Calling nv_kthread_q_stop() on a queue which has been zero-initialized or 140 // for which nv_kthread_q_init() failed, is a no-op. 141 // 142 void nv_kthread_q_stop(nv_kthread_q_t *q); 143 144 // 145 // All items that were in the queue before nv_kthread_q_flush was called, and 146 // all items scheduled by those items, will get run before this function 147 // returns. 148 // 149 // You may NOT call nv_kthread_q_flush() after having called nv_kthread_q_stop. 150 // 151 // This actually flushes the queue twice. That ensures that the queue is fully 152 // flushed, for an important use case: rescheduling from within one's own 153 // callback. In order to do that safely, you need to: 154 // 155 // -- set a flag that tells the callback to stop rescheduling itself. 156 // 157 // -- call either nv_kthread_q_flush or nv_kthread_q_stop (which internally 158 // calls nv_kthread_q_flush). The nv_kthread_q_flush, in turn, actually 159 // flushes the queue *twice*. The first flush waits for any callbacks 160 // to finish, that missed seeing the "stop_rescheduling" flag. The 161 // second flush waits for callbacks that were already scheduled when the 162 // first flush finished. 163 // 164 void nv_kthread_q_flush(nv_kthread_q_t *q); 165 166 // Assigns function_to_run and function_args to the q_item. 167 // 168 // This must be called before calling nv_kthread_q_schedule_q_item. 169 void nv_kthread_q_item_init(nv_kthread_q_item_t *q_item, 170 nv_q_func_t function_to_run, 171 void *function_args); 172 173 // 174 // The caller must have already set up the queue, via nv_kthread_q_init(). 175 // The caller owns the lifetime of the q_item. The nv_kthread_q system runs 176 // q_items, and adds or removes them from the queue. However, due to the first 177 // law of q-dynamics, it neither creates nor destroys q_items. 178 // 179 // When the callback (the function_to_run argument) is actually run, it is OK 180 // to free the q_item from within that routine. The nv_kthread_q system 181 // promises to be done with the q_item before that point. 182 // 183 // nv_kthread_q_schedule_q_item may be called from multiple threads at once, 184 // without danger of corrupting anything. This routine may also be safely 185 // called from interrupt context, including top-half ISRs. 186 // 187 // It is OK to reschedule the same q_item from within its own callback function. 188 // 189 // It is also OK to attempt to reschedule the same q_item, if that q_item is 190 // already pending in the queue. The q_item will not be rescheduled if it is 191 // already pending. 192 // 193 // Returns true (non-zero) if the item was actually scheduled. Returns false if 194 // the item was not scheduled, which can happen if: 195 // 196 // -- The q_item was already pending in a queue, or 197 // -- The queue is shutting down (or not yet started up). 198 // 199 int nv_kthread_q_schedule_q_item(nv_kthread_q_t *q, 200 nv_kthread_q_item_t *q_item); 201 202 // Built-in test. Returns -1 if any subtest failed, or 0 upon success. 203 int nv_kthread_q_run_self_test(void); 204 205 #endif // __NV_KTHREAD_QUEUE_H__ 206