1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  27  * Copyright (c) 2017 by Delphix. All rights reserved.
  28  */
  29 
  30 #ifndef _SYS_TASKQ_IMPL_H
  31 #define _SYS_TASKQ_IMPL_H
  32 
  33 #include <sys/taskq.h>
  34 #include <sys/inttypes.h>
  35 #include <sys/vmem.h>
  36 #include <sys/list.h>
  37 #include <sys/kstat.h>
  38 
  39 #ifdef  __cplusplus
  40 extern "C" {
  41 #endif
  42 
  43 typedef struct taskq_bucket taskq_bucket_t;
  44 
  45 typedef struct taskq_ent {
  46         struct taskq_ent        *tqent_next;
  47         struct taskq_ent        *tqent_prev;
  48         task_func_t             *tqent_func;
  49         void                    *tqent_arg;
  50         union {
  51                 taskq_bucket_t  *tqent_bucket;
  52                 uintptr_t       tqent_flags;
  53         }                       tqent_un;
  54         kthread_t               *tqent_thread;
  55         kcondvar_t              tqent_cv;
  56 } taskq_ent_t;
  57 
  58 #define TQENT_FLAG_PREALLOC     0x1
  59 
  60 /*
  61  * Taskq Statistics fields are not protected by any locks.
  62  */
  63 typedef struct tqstat {
  64         uint_t          tqs_hits;
  65         uint_t          tqs_misses;
  66         uint_t          tqs_overflow;   /* no threads to allocate   */
  67         uint_t          tqs_tcreates;   /* threads created      */
  68         uint_t          tqs_tdeaths;    /* threads died         */
  69         uint_t          tqs_maxthreads; /* max # of alive threads */
  70         uint_t          tqs_disptcreates;
  71 } tqstat_t;
  72 
  73 /*
  74  * Per-CPU hash bucket manages taskq_bent_t structures using freelist.
  75  */
  76 struct taskq_bucket {
  77         kmutex_t        tqbucket_lock;
  78         taskq_t         *tqbucket_taskq;        /* Enclosing taskq */
  79         taskq_ent_t     tqbucket_freelist;
  80         uint_t          tqbucket_nalloc;        /* # of allocated entries */
  81         uint_t          tqbucket_nfree;         /* # of free entries */
  82         kcondvar_t      tqbucket_cv;
  83         ushort_t        tqbucket_flags;
  84         hrtime_t        tqbucket_totaltime;
  85         tqstat_t        tqbucket_stat;
  86 };
  87 
  88 /*
  89  * Bucket flags.
  90  */
  91 #define TQBUCKET_CLOSE          0x01
  92 #define TQBUCKET_SUSPEND        0x02
  93 
  94 #define TASKQ_INTERFACE_FLAGS   0x0000ffff      /* defined in <sys/taskq.h> */
  95 
  96 /*
  97  * taskq implementation flags: bit range 16-31
  98  */
  99 #define TASKQ_CHANGING          0x00010000      /* nthreads != target */
 100 #define TASKQ_SUSPENDED         0x00020000      /* taskq is suspended */
 101 #define TASKQ_NOINSTANCE        0x00040000      /* no instance number */
 102 #define TASKQ_THREAD_CREATED    0x00080000      /* a thread has been created */
 103 #define TASKQ_DUTY_CYCLE        0x00100000      /* using the SDC class */
 104 
 105 struct taskq {
 106         char            tq_name[TASKQ_NAMELEN + 1];
 107         kmutex_t        tq_lock;
 108         krwlock_t       tq_threadlock;
 109         kcondvar_t      tq_dispatch_cv;
 110         kcondvar_t      tq_wait_cv;
 111         kcondvar_t      tq_exit_cv;
 112         pri_t           tq_pri;         /* Scheduling priority */
 113         uint_t          tq_flags;
 114         int             tq_active;
 115         int             tq_nthreads;
 116         int             tq_nthreads_target;
 117         int             tq_nthreads_max;
 118         int             tq_threads_ncpus_pct;
 119         int             tq_nalloc;
 120         int             tq_minalloc;
 121         int             tq_maxalloc;
 122         kcondvar_t      tq_maxalloc_cv;
 123         int             tq_maxalloc_wait;
 124         taskq_ent_t     *tq_freelist;
 125         taskq_ent_t     tq_task;
 126         int             tq_maxsize;
 127         taskq_bucket_t  *tq_buckets;    /* Per-cpu array of buckets */
 128         int             tq_instance;
 129         uint_t          tq_nbuckets;    /* # of buckets (2^n)       */
 130         union {
 131                 kthread_t *_tq_thread;
 132                 kthread_t **_tq_threadlist;
 133         }               tq_thr;
 134 
 135         list_node_t     tq_cpupct_link; /* linkage for taskq_cpupct_list */
 136         struct proc     *tq_proc;       /* process for taskq threads */
 137         int             tq_cpupart;     /* cpupart id bound to */
 138         uint_t          tq_DC;          /* duty cycle for SDC */
 139 
 140         /*
 141          * Statistics.
 142          */
 143         kstat_t         *tq_kstat;      /* Exported statistics */
 144         hrtime_t        tq_totaltime;   /* Time spent processing tasks */
 145         uint64_t        tq_nomem;       /* # of times there was no memory */
 146         uint64_t        tq_tasks;       /* Total # of tasks posted */
 147         uint64_t        tq_executed;    /* Total # of tasks executed */
 148         int             tq_maxtasks;    /* Max number of tasks in the queue */
 149         int             tq_tcreates;
 150         int             tq_tdeaths;
 151 };
 152 
 153 /* Special form of taskq dispatch that uses preallocated entries. */
 154 void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, taskq_ent_t *);
 155 
 156 
 157 #define tq_thread tq_thr._tq_thread
 158 #define tq_threadlist tq_thr._tq_threadlist
 159 
 160 /* The MAX guarantees we have at least one thread */
 161 #define TASKQ_THREADS_PCT(ncpus, pct)   MAX(((ncpus) * (pct)) / 100, 1)
 162 
 163 #ifdef  __cplusplus
 164 }
 165 #endif
 166 
 167 #endif  /* _SYS_TASKQ_IMPL_H */