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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Routines to support shuttle synchronization objects 29 */ 30 31 #include <sys/types.h> 32 #include <sys/proc.h> 33 #include <sys/thread.h> 34 #include <sys/class.h> 35 #include <sys/debug.h> 36 #include <sys/sobject.h> 37 #include <sys/cpuvar.h> 38 #include <sys/schedctl.h> 39 #include <sys/sdt.h> 40 41 static disp_lock_t shuttle_lock; /* lock on shuttle objects */ 42 43 /* 44 * Place the thread in question on the run q. 45 */ 46 static void 47 shuttle_unsleep(kthread_t *t) 48 { 49 ASSERT(THREAD_LOCK_HELD(t)); 50 51 /* Waiting on a shuttle */ 52 ASSERT(t->t_wchan0 == (caddr_t)1 && t->t_wchan == NULL); 53 t->t_flag &= ~T_WAKEABLE; 54 t->t_wchan0 = NULL; 55 t->t_sobj_ops = NULL; 56 THREAD_TRANSITION(t); 57 CL_SETRUN(t); 58 } 59 60 static kthread_t * 61 shuttle_owner() 62 { 63 return (NULL); 64 } 65 66 /*ARGSUSED*/ 67 static void 68 shuttle_change_pri(kthread_t *t, pri_t p, pri_t *t_prip) 69 { 70 ASSERT(THREAD_LOCK_HELD(t)); 71 *t_prip = p; 72 } 73 74 static sobj_ops_t shuttle_sobj_ops = { 75 SOBJ_SHUTTLE, shuttle_owner, shuttle_unsleep, shuttle_change_pri 76 }; 77 78 /* 79 * Mark the current thread as sleeping on a shuttle object, and 80 * resume the specified thread. The 't' thread must be marked as ONPROC. 81 * 82 * No locks other than 'l' should be held at this point. 83 */ 84 void 85 shuttle_resume(kthread_t *t, kmutex_t *l) 86 { 87 klwp_t *lwp = ttolwp(curthread); 88 cpu_t *cp; 89 disp_lock_t *oldtlp; 90 91 thread_lock(curthread); 92 disp_lock_enter_high(&shuttle_lock); 93 if (lwp != NULL) { 94 lwp->lwp_asleep = 1; /* /proc */ 95 lwp->lwp_sysabort = 0; /* /proc */ 96 lwp->lwp_ru.nvcsw++; 97 } 98 curthread->t_flag |= T_WAKEABLE; 99 curthread->t_sobj_ops = &shuttle_sobj_ops; 100 /* 101 * setting cpu_dispthread before changing thread state 102 * so that kernel preemption will be deferred to after swtch_to() 103 */ 104 cp = CPU; 105 cp->cpu_dispthread = t; 106 cp->cpu_dispatch_pri = DISP_PRIO(t); 107 /* 108 * Set the wchan0 field so that /proc won't just do a setrun 109 * on this thread when trying to stop a process. Instead, 110 * /proc will mark the thread as VSTOPPED similar to threads 111 * that are blocked on user level condition variables. 112 */ 113 curthread->t_wchan0 = (caddr_t)1; 114 CL_INACTIVE(curthread); 115 DTRACE_SCHED1(wakeup, kthread_t *, t); 116 DTRACE_SCHED(sleep); 117 THREAD_SLEEP(curthread, &shuttle_lock); 118 disp_lock_exit_high(&shuttle_lock); 119 120 /* 121 * Update ustate records (there is no waitrq obviously) 122 */ 123 (void) new_mstate(curthread, LMS_SLEEP); 124 125 thread_lock_high(t); 126 oldtlp = t->t_lockp; 127 128 t->t_flag &= ~T_WAKEABLE; 129 t->t_wchan0 = NULL; 130 t->t_sobj_ops = NULL; 131 132 /* 133 * Make sure we end up on the right CPU if we are dealing with bound 134 * CPU's or processor partitions. 135 */ 136 if (t->t_bound_cpu != NULL || t->t_cpupart != cp->cpu_part) { 137 aston(t); 138 cp->cpu_runrun = 1; 139 } 140 141 /* 142 * We re-assign t_disp_queue and t_lockp of 't' here because 143 * 't' could have been preempted. 144 */ 145 if (t->t_disp_queue != cp->cpu_disp) { 146 t->t_disp_queue = cp->cpu_disp; 147 thread_onproc(t, cp); 148 } 149 150 /* 151 * We can't call thread_unlock_high() here because t's thread lock 152 * could have changed by thread_onproc() call above to point to 153 * CPU->cpu_thread_lock. 154 */ 155 disp_lock_exit_high(oldtlp); 156 157 mutex_exit(l); 158 /* 159 * Make sure we didn't receive any important events while 160 * we weren't looking 161 */ 162 if (lwp && (ISSIG(curthread, JUSTLOOKING) || 163 MUSTRETURN(curproc, curthread) || schedctl_cancel_pending())) 164 setrun(curthread); 165 166 swtch_to(t); 167 /* 168 * Caller must check for ISSIG/lwp_sysabort conditions 169 * and clear lwp->lwp_asleep/lwp->lwp_sysabort 170 */ 171 } 172 173 /* 174 * Mark the current thread as sleeping on a shuttle object, and 175 * switch to a new thread. 176 * No locks other than 'l' should be held at this point. 177 */ 178 void 179 shuttle_swtch(kmutex_t *l) 180 { 181 klwp_t *lwp = ttolwp(curthread); 182 183 thread_lock(curthread); 184 disp_lock_enter_high(&shuttle_lock); 185 lwp->lwp_asleep = 1; /* /proc */ 186 lwp->lwp_sysabort = 0; /* /proc */ 187 lwp->lwp_ru.nvcsw++; 188 curthread->t_flag |= T_WAKEABLE; 189 curthread->t_sobj_ops = &shuttle_sobj_ops; 190 curthread->t_wchan0 = (caddr_t)1; 191 CL_INACTIVE(curthread); 192 DTRACE_SCHED(sleep); 193 THREAD_SLEEP(curthread, &shuttle_lock); 194 (void) new_mstate(curthread, LMS_SLEEP); 195 disp_lock_exit_high(&shuttle_lock); 196 mutex_exit(l); 197 if (ISSIG(curthread, JUSTLOOKING) || 198 MUSTRETURN(curproc, curthread) || schedctl_cancel_pending()) 199 setrun(curthread); 200 swtch(); 201 /* 202 * Caller must check for ISSIG/lwp_sysabort conditions 203 * and clear lwp->lwp_asleep/lwp->lwp_sysabort 204 */ 205 } 206 207 /* 208 * Mark the specified thread as once again sleeping on a shuttle object. This 209 * routine is called to put a server thread -- one that was dequeued but for 210 * which shuttle_resume() was _not_ called -- back to sleep on a shuttle 211 * object. Because we don't hit the sched:::wakeup DTrace probe until 212 * shuttle_resume(), we do _not_ have a sched:::sleep probe here. 213 */ 214 void 215 shuttle_sleep(kthread_t *t) 216 { 217 klwp_t *lwp = ttolwp(t); 218 proc_t *p = ttoproc(t); 219 220 thread_lock(t); 221 disp_lock_enter_high(&shuttle_lock); 222 if (lwp != NULL) { 223 lwp->lwp_asleep = 1; /* /proc */ 224 lwp->lwp_sysabort = 0; /* /proc */ 225 lwp->lwp_ru.nvcsw++; 226 } 227 t->t_flag |= T_WAKEABLE; 228 t->t_sobj_ops = &shuttle_sobj_ops; 229 t->t_wchan0 = (caddr_t)1; 230 CL_INACTIVE(t); 231 ASSERT(t->t_mstate == LMS_SLEEP); 232 THREAD_SLEEP(t, &shuttle_lock); 233 disp_lock_exit_high(&shuttle_lock); 234 if (lwp && (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t))) 235 setrun(t); 236 } 237