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 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  26  *
  27  * Copyright 2018 Joyent, Inc.
  28  */
  29 
  30 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  31 /*        All Rights Reserved   */
  32 
  33 
  34 #ifndef _SYS_DISP_H
  35 #define _SYS_DISP_H
  36 
  37 #include <sys/priocntl.h>
  38 #include <sys/thread.h>
  39 #include <sys/class.h>
  40 
  41 #ifdef  __cplusplus
  42 extern "C" {
  43 #endif
  44 
  45 /*
  46  * The following is the format of a dispatcher queue entry.
  47  */
  48 typedef struct dispq {
  49         kthread_t       *dq_first;      /* first thread on queue or NULL */
  50         kthread_t       *dq_last;       /* last thread on queue or NULL */
  51         int             dq_sruncnt;     /* number of loaded, runnable */
  52                                         /*    threads on queue */
  53 } dispq_t;
  54 
  55 /*
  56  * Dispatch queue structure.
  57  */
  58 typedef struct _disp {
  59         disp_lock_t     disp_lock;      /* protects dispatching fields */
  60         pri_t           disp_npri;      /* # of priority levels in queue */
  61         dispq_t         *disp_q;                /* the dispatch queue */
  62         dispq_t         *disp_q_limit;  /* ptr past end of dispatch queue */
  63         ulong_t         *disp_qactmap;  /* bitmap of active dispatch queues */
  64 
  65         /*
  66          * Priorities:
  67          *      disp_maxrunpri is the maximum run priority of runnable threads
  68          *      on this queue.  It is -1 if nothing is runnable.
  69          *
  70          *      disp_max_unbound_pri is the maximum run priority of threads on
  71          *      this dispatch queue but runnable by any CPU.  This may be left
  72          *      artificially high, then corrected when some CPU tries to take
  73          *      an unbound thread.  It is -1 if nothing is runnable.
  74          */
  75         pri_t           disp_maxrunpri; /* maximum run priority */
  76         pri_t           disp_max_unbound_pri;   /* max pri of unbound threads */
  77 
  78         volatile int    disp_nrunnable; /* runnable threads in cpu dispq */
  79 
  80         struct cpu      *disp_cpu;      /* cpu owning this queue or NULL */
  81         hrtime_t        disp_steal;     /* time when threads become stealable */
  82 } disp_t;
  83 
  84 #if defined(_KERNEL) || defined(_FAKE_KERNEL)
  85 
  86 #define MAXCLSYSPRI     99
  87 #define MINCLSYSPRI     60
  88 
  89 
  90 /*
  91  * Global scheduling variables.
  92  *      - See sys/cpuvar.h for CPU-local variables.
  93  */
  94 extern int      nswapped;       /* number of swapped threads */
  95                                 /* nswapped protected by swap_lock */
  96 
  97 extern  pri_t   minclsyspri;    /* minimum level of any system class */
  98 extern  pri_t   maxclsyspri;    /* maximum level of any system class */
  99 extern  pri_t   intr_pri;       /* interrupt thread priority base level */
 100 
 101 #endif  /* _KERNEL || _FAKE_KERNEL */
 102 #if defined(_KERNEL)
 103 
 104 /*
 105  * Minimum amount of time that a thread can remain runnable before it can
 106  * be stolen by another CPU (in nanoseconds).
 107  */
 108 extern hrtime_t nosteal_nsec;
 109 
 110 /*
 111  * Kernel preemption occurs if a higher-priority thread is runnable with
 112  * a priority at or above kpreemptpri.
 113  *
 114  * So that other processors can watch for such threads, a separate
 115  * dispatch queue with unbound work above kpreemptpri is maintained.
 116  * This is part of the CPU partition structure (cpupart_t).
 117  */
 118 extern  pri_t   kpreemptpri;    /* level above which preemption takes place */
 119 
 120 extern void             disp_kp_alloc(disp_t *, pri_t); /* allocate kp queue */
 121 extern void             disp_kp_free(disp_t *);         /* free kp queue */
 122 
 123 /*
 124  * Macro for use by scheduling classes to decide whether the thread is about
 125  * to be scheduled or not.  This returns the maximum run priority.
 126  */
 127 #define DISP_MAXRUNPRI(t)       ((t)->t_disp_queue->disp_maxrunpri)
 128 
 129 /*
 130  * Platform callbacks for various dispatcher operations
 131  *
 132  * idle_cpu() is invoked when a cpu goes idle, and has nothing to do.
 133  * disp_enq_thread() is invoked when a thread is placed on a run queue.
 134  */
 135 extern void     (*idle_cpu)();
 136 extern void     (*disp_enq_thread)(struct cpu *, int);
 137 
 138 
 139 extern int              dispdeq(kthread_t *);
 140 extern void             dispinit(void);
 141 extern void             disp_add(sclass_t *);
 142 extern int              intr_active(struct cpu *, int);
 143 extern int              servicing_interrupt(void);
 144 extern void             preempt(void);
 145 extern void             setbackdq(kthread_t *);
 146 extern void             setfrontdq(kthread_t *);
 147 extern void             swtch(void);
 148 extern void             swtch_to(kthread_t *);
 149 extern void             swtch_from_zombie(void)
 150                                 __NORETURN;
 151 extern void             dq_sruninc(kthread_t *);
 152 extern void             dq_srundec(kthread_t *);
 153 extern void             cpu_rechoose(kthread_t *);
 154 extern void             cpu_surrender(kthread_t *);
 155 extern void             kpreempt(int);
 156 extern struct cpu       *disp_lowpri_cpu(struct cpu *, kthread_t *, pri_t);
 157 extern int              disp_bound_threads(struct cpu *, int);
 158 extern int              disp_bound_anythreads(struct cpu *, int);
 159 extern int              disp_bound_partition(struct cpu *, int);
 160 extern void             disp_cpu_init(struct cpu *);
 161 extern void             disp_cpu_fini(struct cpu *);
 162 extern void             disp_cpu_inactive(struct cpu *);
 163 extern void             disp_adjust_unbound_pri(kthread_t *);
 164 extern void             resume(kthread_t *);
 165 extern void             resume_from_intr(kthread_t *);
 166 extern void             resume_from_zombie(kthread_t *)
 167                                 __NORETURN;
 168 extern void             disp_swapped_enq(kthread_t *);
 169 extern int              disp_anywork(void);
 170 
 171 extern struct cpu       *disp_choose_best_cpu(void);
 172 
 173 #define KPREEMPT_SYNC           (-1)
 174 #define kpreempt_disable()                              \
 175         {                                               \
 176                 curthread->t_preempt++;                      \
 177                 ASSERT(curthread->t_preempt >= 1);        \
 178         }
 179 #define kpreempt_enable()                               \
 180         {                                               \
 181                 ASSERT(curthread->t_preempt >= 1);        \
 182                 if (--curthread->t_preempt == 0 &&   \
 183                     CPU->cpu_kprunrun)                       \
 184                         kpreempt(KPREEMPT_SYNC);        \
 185         }
 186 
 187 #endif  /* _KERNEL */
 188 
 189 #define CPU_IDLE_PRI (-1)
 190 
 191 #ifdef  __cplusplus
 192 }
 193 #endif
 194 
 195 #endif  /* _SYS_DISP_H */