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 2004 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 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 extern disp_lock_t shuttle_lock; 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 119 /* Update ustate records (there is no waitrq obviously) */ 120 121 (void) new_mstate(curthread, LMS_SLEEP); 122 restore_mstate(t); 123 t->t_flag &= ~T_WAKEABLE; 124 t->t_wchan0 = NULL; 125 t->t_sobj_ops = NULL; 126 127 /* 128 * We re-assign t_disp_queue and t_lockp of 't' here because 129 * 't' could have been preempted. 130 */ 131 if (t->t_disp_queue != cp->cpu_disp) { 132 t->t_disp_queue = cp->cpu_disp; 133 thread_onproc(t, cp); 134 } 135 136 /* 137 * Make sure we end up on the right CPU if we are dealing with bound 138 * CPU's or processor partitions. 139 */ 140 if (t->t_bound_cpu != NULL || t->t_cpupart != cp->cpu_part) { 141 aston(t); 142 cp->cpu_runrun = 1; 143 } 144 145 disp_lock_exit_high(&shuttle_lock); 146 mutex_exit(l); 147 /* 148 * Make sure we didn't receive any important events while 149 * we weren't looking 150 */ 151 if (lwp && 152 (ISSIG(curthread, JUSTLOOKING) || MUSTRETURN(curproc, curthread))) 153 setrun(curthread); 154 swtch_to(t); 155 /* 156 * Caller must check for ISSIG/lwp_sysabort conditions 157 * and clear lwp->lwp_asleep/lwp->lwp_sysabort 158 */ 159 } 160 161 /* 162 * Mark the current thread as sleeping on a shuttle object, and 163 * switch to a new thread. 164 * No locks other than 'l' should be held at this point. 165 */ 166 void 167 shuttle_swtch(kmutex_t *l) 168 { 169 klwp_t *lwp = ttolwp(curthread); 170 extern disp_lock_t shuttle_lock; 171 172 thread_lock(curthread); 173 disp_lock_enter_high(&shuttle_lock); 174 lwp->lwp_asleep = 1; /* /proc */ 175 lwp->lwp_sysabort = 0; /* /proc */ 176 lwp->lwp_ru.nvcsw++; 177 curthread->t_flag |= T_WAKEABLE; 178 curthread->t_sobj_ops = &shuttle_sobj_ops; 179 curthread->t_wchan0 = (caddr_t)1; 180 CL_INACTIVE(curthread); 181 DTRACE_SCHED(sleep); 182 THREAD_SLEEP(curthread, &shuttle_lock); 183 (void) new_mstate(curthread, LMS_SLEEP); 184 disp_lock_exit_high(&shuttle_lock); 185 mutex_exit(l); 186 if (ISSIG(curthread, JUSTLOOKING) || MUSTRETURN(curproc, curthread)) 187 setrun(curthread); 188 swtch(); 189 /* 190 * Caller must check for ISSIG/lwp_sysabort conditions 191 * and clear lwp->lwp_asleep/lwp->lwp_sysabort 192 */ 193 } 194 195 /* 196 * Mark the specified thread as once again sleeping on a shuttle object. This 197 * routine is called to put a server thread -- one that was dequeued but for 198 * which shuttle_resume() was _not_ called -- back to sleep on a shuttle 199 * object. Because we don't hit the sched:::wakeup DTrace probe until 200 * shuttle_resume(), we do _not_ have a sched:::sleep probe here. 201 */ 202 void 203 shuttle_sleep(kthread_t *t) 204 { 205 klwp_t *lwp = ttolwp(t); 206 proc_t *p = ttoproc(t); 207 208 extern disp_lock_t shuttle_lock; 209 210 thread_lock(t); 211 disp_lock_enter_high(&shuttle_lock); 212 if (lwp != NULL) { 213 lwp->lwp_asleep = 1; /* /proc */ 214 lwp->lwp_sysabort = 0; /* /proc */ 215 lwp->lwp_ru.nvcsw++; 216 } 217 t->t_flag |= T_WAKEABLE; 218 t->t_sobj_ops = &shuttle_sobj_ops; 219 t->t_wchan0 = (caddr_t)1; 220 CL_INACTIVE(t); 221 (void) new_mstate(t, LMS_SLEEP); 222 THREAD_SLEEP(t, &shuttle_lock); 223 disp_lock_exit_high(&shuttle_lock); 224 if (lwp && (ISSIG(t, JUSTLOOKING) || MUSTRETURN(p, t))) 225 setrun(t); 226 } 227