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