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  * Copyright 2017 RackTop Systems.
  29  */
  30 
  31 #ifndef _SYS_TASKQ_IMPL_H
  32 #define _SYS_TASKQ_IMPL_H
  33 
  34 #include <sys/taskq.h>
  35 #include <sys/inttypes.h>
  36 #include <sys/vmem.h>
  37 #include <sys/list.h>
  38 #include <sys/kstat.h>
  39 #include <sys/rwlock.h>
  40 
  41 #ifdef  __cplusplus
  42 extern "C" {
  43 #endif
  44 
  45 typedef struct taskq_bucket taskq_bucket_t;
  46 
  47 typedef struct taskq_ent {
  48         struct taskq_ent        *tqent_next;
  49         struct taskq_ent        *tqent_prev;
  50         task_func_t             *tqent_func;
  51         void                    *tqent_arg;
  52         union {
  53                 taskq_bucket_t  *tqent_bucket;
  54                 uintptr_t       tqent_flags;
  55         }                       tqent_un;
  56         kthread_t               *tqent_thread;
  57         kcondvar_t              tqent_cv;
  58 } taskq_ent_t;
  59 
  60 #define TQENT_FLAG_PREALLOC     0x1
  61 
  62 /*
  63  * Taskq Statistics fields are not protected by any locks.
  64  */
  65 typedef struct tqstat {
  66         uint_t          tqs_hits;
  67         uint_t          tqs_misses;
  68         uint_t          tqs_overflow;   /* no threads to allocate   */
  69         uint_t          tqs_tcreates;   /* threads created      */
  70         uint_t          tqs_tdeaths;    /* threads died         */
  71         uint_t          tqs_maxthreads; /* max # of alive threads */
  72         uint_t          tqs_disptcreates;
  73 } tqstat_t;
  74 
  75 /*
  76  * Per-CPU hash bucket manages taskq_bent_t structures using freelist.
  77  */
  78 struct taskq_bucket {
  79         kmutex_t        tqbucket_lock;
  80         taskq_t         *tqbucket_taskq;        /* Enclosing taskq */
  81         taskq_ent_t     tqbucket_freelist;
  82         uint_t          tqbucket_nalloc;        /* # of allocated entries */
  83         uint_t          tqbucket_nfree;         /* # of free entries */
  84         kcondvar_t      tqbucket_cv;
  85         ushort_t        tqbucket_flags;
  86         hrtime_t        tqbucket_totaltime;
  87         tqstat_t        tqbucket_stat;
  88 };
  89 
  90 /*
  91  * Bucket flags.
  92  */
  93 #define TQBUCKET_CLOSE          0x01
  94 #define TQBUCKET_SUSPEND        0x02
  95 
  96 #define TASKQ_INTERFACE_FLAGS   0x0000ffff      /* defined in <sys/taskq.h> */
  97 
  98 /*
  99  * taskq implementation flags: bit range 16-31
 100  */
 101 #define TASKQ_CHANGING          0x00010000      /* nthreads != target */
 102 #define TASKQ_SUSPENDED         0x00020000      /* taskq is suspended */
 103 #define TASKQ_NOINSTANCE        0x00040000      /* no instance number */
 104 #define TASKQ_THREAD_CREATED    0x00080000      /* a thread has been created */
 105 #define TASKQ_DUTY_CYCLE        0x00100000      /* using the SDC class */
 106 
 107 struct taskq {
 108         char            tq_name[TASKQ_NAMELEN + 1];
 109         kmutex_t        tq_lock;
 110         krwlock_t       tq_threadlock;
 111         kcondvar_t      tq_dispatch_cv;
 112         kcondvar_t      tq_wait_cv;
 113         kcondvar_t      tq_exit_cv;
 114         pri_t           tq_pri;         /* Scheduling priority */
 115         uint_t          tq_flags;
 116         int             tq_active;
 117         int             tq_nthreads;
 118         int             tq_nthreads_target;
 119         int             tq_nthreads_max;
 120         int             tq_threads_ncpus_pct;
 121         int             tq_nalloc;
 122         int             tq_minalloc;
 123         int             tq_maxalloc;
 124         kcondvar_t      tq_maxalloc_cv;
 125         int             tq_maxalloc_wait;
 126         taskq_ent_t     *tq_freelist;
 127         taskq_ent_t     tq_task;
 128         int             tq_maxsize;
 129         taskq_bucket_t  *tq_buckets;    /* Per-cpu array of buckets */
 130         int             tq_instance;
 131         uint_t          tq_nbuckets;    /* # of buckets (2^n)       */
 132         union {
 133                 kthread_t *_tq_thread;
 134                 kthread_t **_tq_threadlist;
 135         }               tq_thr;
 136 
 137         list_node_t     tq_cpupct_link; /* linkage for taskq_cpupct_list */
 138         struct proc     *tq_proc;       /* process for taskq threads */
 139         int             tq_cpupart;     /* cpupart id bound to */
 140         uint_t          tq_DC;          /* duty cycle for SDC */
 141 
 142         /*
 143          * Statistics.
 144          */
 145         kstat_t         *tq_kstat;      /* Exported statistics */
 146         hrtime_t        tq_totaltime;   /* Time spent processing tasks */
 147         uint64_t        tq_nomem;       /* # of times there was no memory */
 148         uint64_t        tq_tasks;       /* Total # of tasks posted */
 149         uint64_t        tq_executed;    /* Total # of tasks executed */
 150         int             tq_maxtasks;    /* Max number of tasks in the queue */
 151         int             tq_tcreates;
 152         int             tq_tdeaths;
 153 };
 154 
 155 /* Special form of taskq dispatch that uses preallocated entries. */
 156 void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, taskq_ent_t *);
 157 
 158 
 159 #define tq_thread tq_thr._tq_thread
 160 #define tq_threadlist tq_thr._tq_threadlist
 161 
 162 /* The MAX guarantees we have at least one thread */
 163 #define TASKQ_THREADS_PCT(ncpus, pct)   MAX(((ncpus) * (pct)) / 100, 1)
 164 
 165 #ifdef  __cplusplus
 166 }
 167 #endif
 168 
 169 #endif  /* _SYS_TASKQ_IMPL_H */