1/*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 29#ifndef _SYS_TASKQUEUE_H_ 30#define _SYS_TASKQUEUE_H_ 31 32#ifndef _KERNEL 33#error "no user-serviceable parts inside" 34#endif 35 36#include <sys/queue.h> 37#include <sys/_task.h> 38#include <sys/_callout.h> 39#include <sys/_cpuset.h> 40 41struct taskqueue; 42struct taskqgroup; 43struct proc; 44struct thread; 45 46struct timeout_task { 47 struct taskqueue *q; 48 struct task t; 49 struct callout c; 50 int f; 51}; 52 53enum taskqueue_callback_type { 54 TASKQUEUE_CALLBACK_TYPE_INIT, 55 TASKQUEUE_CALLBACK_TYPE_SHUTDOWN, 56}; 57#define TASKQUEUE_CALLBACK_TYPE_MIN TASKQUEUE_CALLBACK_TYPE_INIT 58#define TASKQUEUE_CALLBACK_TYPE_MAX TASKQUEUE_CALLBACK_TYPE_SHUTDOWN 59#define TASKQUEUE_NUM_CALLBACKS TASKQUEUE_CALLBACK_TYPE_MAX + 1 60#define TASKQUEUE_NAMELEN 32 61 62/* taskqueue_enqueue flags */ 63#define TASKQUEUE_FAIL_IF_PENDING (1 << 0) 64#define TASKQUEUE_FAIL_IF_CANCELING (1 << 1) 65 66typedef void (*taskqueue_callback_fn)(void *context); 67 68/* 69 * A notification callback function which is called from 70 * taskqueue_enqueue(). The context argument is given in the call to 71 * taskqueue_create(). This function would normally be used to allow the 72 * queue to arrange to run itself later (e.g., by scheduling a software 73 * interrupt or waking a kernel thread). 74 */ 75typedef void (*taskqueue_enqueue_fn)(void *context); 76 77struct taskqueue *taskqueue_create(const char *name, int mflags, 78 taskqueue_enqueue_fn enqueue, 79 void *context); 80int taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, 81 const char *name, ...) __printflike(4, 5); 82int taskqueue_start_threads_in_proc(struct taskqueue **tqp, int count, 83 int pri, struct proc *p, const char *name, ...) __printflike(5, 6); 84int taskqueue_start_threads_cpuset(struct taskqueue **tqp, int count, 85 int pri, cpuset_t *mask, const char *name, ...) __printflike(5, 6); 86int taskqueue_enqueue(struct taskqueue *queue, struct task *task); 87int taskqueue_enqueue_flags(struct taskqueue *queue, struct task *task, 88 int flags); 89int taskqueue_enqueue_timeout(struct taskqueue *queue, 90 struct timeout_task *timeout_task, int ticks); 91int taskqueue_enqueue_timeout_sbt(struct taskqueue *queue, 92 struct timeout_task *timeout_task, sbintime_t sbt, sbintime_t pr, 93 int flags); 94int taskqueue_poll_is_busy(struct taskqueue *queue, struct task *task); 95int taskqueue_cancel(struct taskqueue *queue, struct task *task, 96 u_int *pendp); 97int taskqueue_cancel_timeout(struct taskqueue *queue, 98 struct timeout_task *timeout_task, u_int *pendp); 99void taskqueue_drain(struct taskqueue *queue, struct task *task); 100void taskqueue_drain_timeout(struct taskqueue *queue, 101 struct timeout_task *timeout_task); 102void taskqueue_drain_all(struct taskqueue *queue); 103void taskqueue_quiesce(struct taskqueue *queue); 104void taskqueue_free(struct taskqueue *queue); 105void taskqueue_run(struct taskqueue *queue); 106void taskqueue_block(struct taskqueue *queue); 107void taskqueue_unblock(struct taskqueue *queue); 108int taskqueue_member(struct taskqueue *queue, struct thread *td); 109void taskqueue_set_callback(struct taskqueue *queue, 110 enum taskqueue_callback_type cb_type, 111 taskqueue_callback_fn callback, void *context); 112 113#define TASK_INITIALIZER(priority, func, context) \ 114 { .ta_priority = (priority), \ 115 .ta_func = (func), \ 116 .ta_context = (context) } 117 118/* 119 * Functions for dedicated thread taskqueues 120 */ 121void taskqueue_thread_loop(void *arg); 122void taskqueue_thread_enqueue(void *context); 123 124/* 125 * Initialise a task structure. 126 */ 127#define TASK_INIT_FLAGS(task, priority, func, context, flags) do { \ 128 (task)->ta_pending = 0; \ 129 (task)->ta_priority = (priority); \ 130 (task)->ta_flags = (flags); \ 131 (task)->ta_func = (func); \ 132 (task)->ta_context = (context); \ 133} while (0) 134 135#define TASK_INIT(t, p, f, c) TASK_INIT_FLAGS(t, p, f, c, 0) 136 137void _timeout_task_init(struct taskqueue *queue, 138 struct timeout_task *timeout_task, int priority, task_fn_t func, 139 void *context); 140#define TIMEOUT_TASK_INIT(queue, timeout_task, priority, func, context) do { \ 141 _Static_assert((priority) >= 0 && (priority) <= 255, \ 142 "struct task priority is 8 bit in size"); \ 143 _timeout_task_init(queue, timeout_task, priority, func, context); \ 144} while (0) 145 146/* 147 * Declare a reference to a taskqueue. 148 */ 149#define TASKQUEUE_DECLARE(name) \ 150extern struct taskqueue *taskqueue_##name 151 152/* 153 * Define and initialise a global taskqueue that uses sleep mutexes. 154 */ 155#define TASKQUEUE_DEFINE(name, enqueue, context, init) \ 156 \ 157struct taskqueue *taskqueue_##name; \ 158 \ 159static void \ 160taskqueue_define_##name(void *arg) \ 161{ \ 162 taskqueue_##name = \ 163 taskqueue_create(#name, M_WAITOK, (enqueue), (context)); \ 164 init; \ 165} \ 166 \ 167SYSINIT(taskqueue_##name, SI_SUB_TASKQ, SI_ORDER_SECOND, \ 168 taskqueue_define_##name, NULL); \ 169 \ 170struct __hack 171#define TASKQUEUE_DEFINE_THREAD(name) \ 172TASKQUEUE_DEFINE(name, taskqueue_thread_enqueue, &taskqueue_##name, \ 173 taskqueue_start_threads(&taskqueue_##name, 1, PWAIT, \ 174 "%s taskq", #name)) 175 176/* 177 * Define and initialise a global taskqueue that uses spin mutexes. 178 */ 179#define TASKQUEUE_FAST_DEFINE(name, enqueue, context, init) \ 180 \ 181struct taskqueue *taskqueue_##name; \ 182 \ 183static void \ 184taskqueue_define_##name(void *arg) \ 185{ \ 186 taskqueue_##name = \ 187 taskqueue_create_fast(#name, M_WAITOK, (enqueue), \ 188 (context)); \ 189 init; \ 190} \ 191 \ 192SYSINIT(taskqueue_##name, SI_SUB_TASKQ, SI_ORDER_SECOND, \ 193 taskqueue_define_##name, NULL); \ 194 \ 195struct __hack 196#define TASKQUEUE_FAST_DEFINE_THREAD(name) \ 197TASKQUEUE_FAST_DEFINE(name, taskqueue_thread_enqueue, \ 198 &taskqueue_##name, taskqueue_start_threads(&taskqueue_##name, \ 199 1, PWAIT, "%s taskq", #name)) 200 201/* 202 * These queues are serviced by software interrupt handlers. To enqueue 203 * a task, call taskqueue_enqueue(taskqueue_swi, &task) or 204 * taskqueue_enqueue(taskqueue_swi_giant, &task). 205 */ 206TASKQUEUE_DECLARE(swi_giant); 207TASKQUEUE_DECLARE(swi); 208 209/* 210 * This queue is serviced by a kernel thread. To enqueue a task, call 211 * taskqueue_enqueue(taskqueue_thread, &task). 212 */ 213TASKQUEUE_DECLARE(thread); 214 215/* 216 * Queue for swi handlers dispatched from fast interrupt handlers. 217 * These are necessarily different from the above because the queue 218 * must be locked with spinlocks since sleep mutex's cannot be used 219 * from a fast interrupt handler context. 220 */ 221TASKQUEUE_DECLARE(fast); 222struct taskqueue *taskqueue_create_fast(const char *name, int mflags, 223 taskqueue_enqueue_fn enqueue, 224 void *context); 225 226#endif /* !_SYS_TASKQUEUE_H_ */ 227