1196295Spjd/*- 2196295Spjd * Copyright (c) 2009 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3196295Spjd * All rights reserved. 4196295Spjd * 5196295Spjd * Redistribution and use in source and binary forms, with or without 6196295Spjd * modification, are permitted provided that the following conditions 7196295Spjd * are met: 8196295Spjd * 1. Redistributions of source code must retain the above copyright 9196295Spjd * notice, this list of conditions and the following disclaimer. 10196295Spjd * 2. Redistributions in binary form must reproduce the above copyright 11196295Spjd * notice, this list of conditions and the following disclaimer in the 12196295Spjd * documentation and/or other materials provided with the distribution. 13196295Spjd * 14196295Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15196295Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16196295Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17196295Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18196295Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19196295Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20196295Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21196295Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22196295Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23196295Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24196295Spjd * SUCH DAMAGE. 25196295Spjd */ 26196295Spjd 27196295Spjd#include <sys/cdefs.h> 28196295Spjd__FBSDID("$FreeBSD: stable/11/sys/cddl/compat/opensolaris/kern/opensolaris_taskq.c 346699 2019-04-25 18:49:29Z mav $"); 29196295Spjd 30196295Spjd#include <sys/param.h> 31196295Spjd#include <sys/kernel.h> 32196295Spjd#include <sys/kmem.h> 33196295Spjd#include <sys/lock.h> 34196295Spjd#include <sys/mutex.h> 35196295Spjd#include <sys/queue.h> 36196295Spjd#include <sys/taskqueue.h> 37196295Spjd#include <sys/taskq.h> 38196295Spjd 39196295Spjd#include <vm/uma.h> 40196295Spjd 41196295Spjdstatic uma_zone_t taskq_zone; 42196295Spjd 43196295Spjdtaskq_t *system_taskq = NULL; 44196295Spjd 45196295Spjdstatic void 46196295Spjdsystem_taskq_init(void *arg) 47196295Spjd{ 48196295Spjd 49258630Savg taskq_zone = uma_zcreate("taskq_zone", sizeof(taskq_ent_t), 50196295Spjd NULL, NULL, NULL, NULL, 0, 0); 51335540Savg system_taskq = taskq_create("system_taskq", mp_ncpus, minclsyspri, 52335540Savg 0, 0, 0); 53196295Spjd} 54196295SpjdSYSINIT(system_taskq_init, SI_SUB_CONFIGURE, SI_ORDER_ANY, system_taskq_init, NULL); 55196295Spjd 56196295Spjdstatic void 57196295Spjdsystem_taskq_fini(void *arg) 58196295Spjd{ 59196295Spjd 60206838Sdelphij taskq_destroy(system_taskq); 61196295Spjd uma_zdestroy(taskq_zone); 62196295Spjd} 63196295SpjdSYSUNINIT(system_taskq_fini, SI_SUB_CONFIGURE, SI_ORDER_ANY, system_taskq_fini, NULL); 64196295Spjd 65196295Spjdtaskq_t * 66196295Spjdtaskq_create(const char *name, int nthreads, pri_t pri, int minalloc __unused, 67196295Spjd int maxalloc __unused, uint_t flags) 68196295Spjd{ 69196295Spjd taskq_t *tq; 70196295Spjd 71206838Sdelphij if ((flags & TASKQ_THREADS_CPU_PCT) != 0) 72206838Sdelphij nthreads = MAX((mp_ncpus * nthreads) / 100, 1); 73196295Spjd 74196295Spjd tq = kmem_alloc(sizeof(*tq), KM_SLEEP); 75196295Spjd tq->tq_queue = taskqueue_create(name, M_WAITOK, taskqueue_thread_enqueue, 76196295Spjd &tq->tq_queue); 77213791Srpaulo (void) taskqueue_start_threads(&tq->tq_queue, nthreads, pri, "%s", name); 78196295Spjd 79196295Spjd return ((taskq_t *)tq); 80196295Spjd} 81196295Spjd 82206838Sdelphijtaskq_t * 83206838Sdelphijtaskq_create_proc(const char *name, int nthreads, pri_t pri, int minalloc, 84206838Sdelphij int maxalloc, proc_t *proc __unused, uint_t flags) 85206838Sdelphij{ 86206838Sdelphij 87206838Sdelphij return (taskq_create(name, nthreads, pri, minalloc, maxalloc, flags)); 88206838Sdelphij} 89206838Sdelphij 90196295Spjdvoid 91196295Spjdtaskq_destroy(taskq_t *tq) 92196295Spjd{ 93196295Spjd 94196295Spjd taskqueue_free(tq->tq_queue); 95196295Spjd kmem_free(tq, sizeof(*tq)); 96196295Spjd} 97196295Spjd 98196295Spjdint 99196295Spjdtaskq_member(taskq_t *tq, kthread_t *thread) 100196295Spjd{ 101196295Spjd 102196295Spjd return (taskqueue_member(tq->tq_queue, thread)); 103196295Spjd} 104196295Spjd 105196295Spjdstatic void 106196295Spjdtaskq_run(void *arg, int pending __unused) 107196295Spjd{ 108258630Savg taskq_ent_t *task = arg; 109196295Spjd 110258630Savg task->tqent_func(task->tqent_arg); 111196295Spjd 112196295Spjd uma_zfree(taskq_zone, task); 113196295Spjd} 114196295Spjd 115196295Spjdtaskqid_t 116196295Spjdtaskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags) 117196295Spjd{ 118258630Savg taskq_ent_t *task; 119219089Spjd int mflag, prio; 120196295Spjd 121196295Spjd if ((flags & (TQ_SLEEP | TQ_NOQUEUE)) == TQ_SLEEP) 122196295Spjd mflag = M_WAITOK; 123196295Spjd else 124196295Spjd mflag = M_NOWAIT; 125258628Savg /* 126219089Spjd * If TQ_FRONT is given, we want higher priority for this task, so it 127219089Spjd * can go at the front of the queue. 128219089Spjd */ 129219089Spjd prio = !!(flags & TQ_FRONT); 130196295Spjd 131196295Spjd task = uma_zalloc(taskq_zone, mflag); 132196295Spjd if (task == NULL) 133196295Spjd return (0); 134196295Spjd 135258630Savg task->tqent_func = func; 136258630Savg task->tqent_arg = arg; 137196295Spjd 138258630Savg TASK_INIT(&task->tqent_task, prio, taskq_run, task); 139258630Savg taskqueue_enqueue(tq->tq_queue, &task->tqent_task); 140196295Spjd 141196295Spjd return ((taskqid_t)(void *)task); 142196295Spjd} 143208147Spjd 144208147Spjdstatic void 145258630Savgtaskq_run_ent(void *arg, int pending __unused) 146208147Spjd{ 147258630Savg taskq_ent_t *task = arg; 148208147Spjd 149258630Savg task->tqent_func(task->tqent_arg); 150208147Spjd} 151208147Spjd 152258630Savgvoid 153258630Savgtaskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, u_int flags, 154258630Savg taskq_ent_t *task) 155208147Spjd{ 156219089Spjd int prio; 157208147Spjd 158258628Savg /* 159219089Spjd * If TQ_FRONT is given, we want higher priority for this task, so it 160219089Spjd * can go at the front of the queue. 161219089Spjd */ 162219089Spjd prio = !!(flags & TQ_FRONT); 163219089Spjd 164258630Savg task->tqent_func = func; 165258630Savg task->tqent_arg = arg; 166208147Spjd 167258630Savg TASK_INIT(&task->tqent_task, prio, taskq_run_ent, task); 168258630Savg taskqueue_enqueue(tq->tq_queue, &task->tqent_task); 169208147Spjd} 170258715Savg 171258715Savgvoid 172258715Savgtaskq_wait(taskq_t *tq) 173258715Savg{ 174346699Smav taskqueue_quiesce(tq->tq_queue); 175258715Savg} 176339034Ssef 177339034Ssefvoid 178339034Sseftaskq_wait_id(taskq_t *tq, taskqid_t id) 179339034Ssef{ 180346699Smav taskqueue_drain_all(tq->tq_queue); 181339034Ssef} 182