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