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/10/sys/cddl/compat/opensolaris/kern/opensolaris_taskq.c 335541 2018-06-22 09:23:06Z avg $"); 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 49260742Savg taskq_zone = uma_zcreate("taskq_zone", sizeof(taskq_ent_t), 50196295Spjd NULL, NULL, NULL, NULL, 0, 0); 51335541Savg system_taskq = taskq_create("system_taskq", mp_ncpus, minclsyspri, 52335541Savg 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{ 108260742Savg taskq_ent_t *task = arg; 109196295Spjd 110260742Savg 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{ 118260742Savg 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; 125260739Savg /* 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 135260742Savg task->tqent_func = func; 136260742Savg task->tqent_arg = arg; 137196295Spjd 138260742Savg TASK_INIT(&task->tqent_task, prio, taskq_run, task); 139260742Savg taskqueue_enqueue(tq->tq_queue, &task->tqent_task); 140196295Spjd 141196295Spjd return ((taskqid_t)(void *)task); 142196295Spjd} 143208147Spjd 144208147Spjdstatic void 145260742Savgtaskq_run_ent(void *arg, int pending __unused) 146208147Spjd{ 147260742Savg taskq_ent_t *task = arg; 148208147Spjd 149260742Savg task->tqent_func(task->tqent_arg); 150208147Spjd} 151208147Spjd 152260742Savgvoid 153260742Savgtaskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, u_int flags, 154260742Savg taskq_ent_t *task) 155208147Spjd{ 156219089Spjd int prio; 157208147Spjd 158260739Savg /* 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 164260742Savg task->tqent_func = func; 165260742Savg task->tqent_arg = arg; 166208147Spjd 167260742Savg TASK_INIT(&task->tqent_task, prio, taskq_run_ent, task); 168260742Savg taskqueue_enqueue(tq->tq_queue, &task->tqent_task); 169208147Spjd} 170262070Savg 171262070Savgvoid 172262070Savgtaskq_wait(taskq_t *tq) 173262070Savg{ 174262070Savg taskqueue_drain_all(tq->tq_queue); 175262070Savg} 176