1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2000 Doug Rabson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #ifndef _SYS_TASKQUEUE_H_ 32 #define _SYS_TASKQUEUE_H_ 33 34 #ifndef _KERNEL 35 #error "no user-serviceable parts inside" 36 #endif 37 38 #include <sys/queue.h> 39 #include <sys/_task.h> 40 #include <sys/_callout.h> 41 #include <sys/_cpuset.h> 42 43 struct taskqueue; 44 struct taskqgroup; 45 struct thread; 46 47 struct timeout_task { 48 struct taskqueue *q; 49 struct task t; 50 struct callout c; 51 int f; 52 }; 53 54 enum taskqueue_callback_type { 55 TASKQUEUE_CALLBACK_TYPE_INIT, 56 TASKQUEUE_CALLBACK_TYPE_SHUTDOWN, 57 }; 58 #define TASKQUEUE_CALLBACK_TYPE_MIN TASKQUEUE_CALLBACK_TYPE_INIT 59 #define TASKQUEUE_CALLBACK_TYPE_MAX TASKQUEUE_CALLBACK_TYPE_SHUTDOWN 60 #define TASKQUEUE_NUM_CALLBACKS TASKQUEUE_CALLBACK_TYPE_MAX + 1 61 #define TASKQUEUE_NAMELEN 32 62 63 typedef void (*taskqueue_callback_fn)(void *context); 64 65 /* 66 * A notification callback function which is called from 67 * taskqueue_enqueue(). The context argument is given in the call to 68 * taskqueue_create(). This function would normally be used to allow the 69 * queue to arrange to run itself later (e.g., by scheduling a software 70 * interrupt or waking a kernel thread). 71 */ 72 typedef void (*taskqueue_enqueue_fn)(void *context); 73 74 struct taskqueue *taskqueue_create(const char *name, int mflags, 75 taskqueue_enqueue_fn enqueue, 76 void *context); 77 int taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, 78 const char *name, ...) __printflike(4, 5); 79 int taskqueue_start_threads_cpuset(struct taskqueue **tqp, int count, 80 int pri, cpuset_t *mask, const char *name, ...) __printflike(5, 6); 81 int taskqueue_enqueue(struct taskqueue *queue, struct task *task); 82 int taskqueue_enqueue_timeout(struct taskqueue *queue, 83 struct timeout_task *timeout_task, int ticks); 84 int taskqueue_enqueue_timeout_sbt(struct taskqueue *queue, 85 struct timeout_task *timeout_task, sbintime_t sbt, sbintime_t pr, 86 int flags); 87 int taskqueue_poll_is_busy(struct taskqueue *queue, struct task *task); 88 int taskqueue_cancel(struct taskqueue *queue, struct task *task, 89 u_int *pendp); 90 int taskqueue_cancel_timeout(struct taskqueue *queue, 91 struct timeout_task *timeout_task, u_int *pendp); 92 void taskqueue_drain(struct taskqueue *queue, struct task *task); 93 void taskqueue_drain_timeout(struct taskqueue *queue, 94 struct timeout_task *timeout_task); 95 void taskqueue_drain_all(struct taskqueue *queue); 96 void taskqueue_quiesce(struct taskqueue *queue); 97 void taskqueue_free(struct taskqueue *queue); 98 void taskqueue_run(struct taskqueue *queue); 99 void taskqueue_block(struct taskqueue *queue); 100 void taskqueue_unblock(struct taskqueue *queue); 101 int taskqueue_member(struct taskqueue *queue, struct thread *td); 102 void taskqueue_set_callback(struct taskqueue *queue, 103 enum taskqueue_callback_type cb_type, 104 taskqueue_callback_fn callback, void *context); 105 106 #define TASK_INITIALIZER(priority, func, context) \ 107 { .ta_pending = 0, \ 108 .ta_priority = (priority), \ 109 .ta_func = (func), \ 110 .ta_context = (context) } 111 112 /* 113 * Functions for dedicated thread taskqueues 114 */ 115 void taskqueue_thread_loop(void *arg); 116 void taskqueue_thread_enqueue(void *context); 117 118 /* 119 * Initialise a task structure. 120 */ 121 #define TASK_INIT(task, priority, func, context) do { \ 122 (task)->ta_pending = 0; \ 123 (task)->ta_priority = (priority); \ 124 (task)->ta_func = (func); \ 125 (task)->ta_context = (context); \ 126 } while (0) 127 128 void _timeout_task_init(struct taskqueue *queue, 129 struct timeout_task *timeout_task, int priority, task_fn_t func, 130 void *context); 131 #define TIMEOUT_TASK_INIT(queue, timeout_task, priority, func, context) \ 132 _timeout_task_init(queue, timeout_task, priority, func, context); 133 134 /* 135 * Declare a reference to a taskqueue. 136 */ 137 #define TASKQUEUE_DECLARE(name) \ 138 extern struct taskqueue *taskqueue_##name 139 140 /* 141 * Define and initialise a global taskqueue that uses sleep mutexes. 142 */ 143 #define TASKQUEUE_DEFINE(name, enqueue, context, init) \ 144 \ 145 struct taskqueue *taskqueue_##name; \ 146 \ 147 static void \ 148 taskqueue_define_##name(void *arg) \ 149 { \ 150 taskqueue_##name = \ 151 taskqueue_create(#name, M_WAITOK, (enqueue), (context)); \ 152 init; \ 153 } \ 154 \ 155 SYSINIT(taskqueue_##name, SI_SUB_TASKQ, SI_ORDER_SECOND, \ 156 taskqueue_define_##name, NULL); \ 157 \ 158 struct __hack 159 #define TASKQUEUE_DEFINE_THREAD(name) \ 160 TASKQUEUE_DEFINE(name, taskqueue_thread_enqueue, &taskqueue_##name, \ 161 taskqueue_start_threads(&taskqueue_##name, 1, PWAIT, \ 162 "%s taskq", #name)) 163 164 /* 165 * Define and initialise a global taskqueue that uses spin mutexes. 166 */ 167 #define TASKQUEUE_FAST_DEFINE(name, enqueue, context, init) \ 168 \ 169 struct taskqueue *taskqueue_##name; \ 170 \ 171 static void \ 172 taskqueue_define_##name(void *arg) \ 173 { \ 174 taskqueue_##name = \ 175 taskqueue_create_fast(#name, M_WAITOK, (enqueue), \ 176 (context)); \ 177 init; \ 178 } \ 179 \ 180 SYSINIT(taskqueue_##name, SI_SUB_TASKQ, SI_ORDER_SECOND, \ 181 taskqueue_define_##name, NULL); \ 182 \ 183 struct __hack 184 #define TASKQUEUE_FAST_DEFINE_THREAD(name) \ 185 TASKQUEUE_FAST_DEFINE(name, taskqueue_thread_enqueue, \ 186 &taskqueue_##name, taskqueue_start_threads(&taskqueue_##name \ 187 1, PWAIT, "%s taskq", #name)) 188 189 /* 190 * These queues are serviced by software interrupt handlers. To enqueue 191 * a task, call taskqueue_enqueue(taskqueue_swi, &task) or 192 * taskqueue_enqueue(taskqueue_swi_giant, &task). 193 */ 194 TASKQUEUE_DECLARE(swi_giant); 195 TASKQUEUE_DECLARE(swi); 196 197 /* 198 * This queue is serviced by a kernel thread. To enqueue a task, call 199 * taskqueue_enqueue(taskqueue_thread, &task). 200 */ 201 TASKQUEUE_DECLARE(thread); 202 203 /* 204 * Queue for swi handlers dispatched from fast interrupt handlers. 205 * These are necessarily different from the above because the queue 206 * must be locked with spinlocks since sleep mutex's cannot be used 207 * from a fast interrupt handler context. 208 */ 209 TASKQUEUE_DECLARE(fast); 210 struct taskqueue *taskqueue_create_fast(const char *name, int mflags, 211 taskqueue_enqueue_fn enqueue, 212 void *context); 213 214 #endif /* !_SYS_TASKQUEUE_H_ */ 215