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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include "iscsi_thread.h" 27 28 static void iscsi_threads_entry(void *arg); 29 30 /* 31 * iscsi_thread_create - Creates the needed resources to handle a thread 32 */ 33 iscsi_thread_t * 34 iscsi_thread_create(dev_info_t *dip, char *name, 35 iscsi_thread_ep_t entry_point, void *arg) 36 { 37 iscsi_thread_t *thread; 38 39 thread = kmem_zalloc(sizeof (iscsi_thread_t), KM_SLEEP); 40 41 if (thread != NULL) { 42 43 thread->tq = ddi_taskq_create(dip, name, 1, 44 TASKQ_DEFAULTPRI, 0); 45 46 if (thread->tq != NULL) { 47 thread->signature = SIG_ISCSI_THREAD; 48 thread->dip = dip; 49 thread->entry_point = entry_point; 50 thread->arg = arg; 51 thread->state = ISCSI_THREAD_STATE_STOPPED; 52 thread->sign.bitmap = 0; 53 mutex_init(&thread->mgnt.mtx, NULL, MUTEX_DRIVER, NULL); 54 mutex_init(&thread->sign.mtx, NULL, MUTEX_DRIVER, NULL); 55 cv_init(&thread->sign.cdv, NULL, CV_DRIVER, NULL); 56 } else { 57 kmem_free(thread, sizeof (iscsi_thread_t)); 58 thread = NULL; 59 } 60 } 61 62 return (thread); 63 } 64 65 /* 66 * iscsi_thread_destroy - Releases the needed resources to handle a thread 67 */ 68 void 69 iscsi_thread_destroy( 70 iscsi_thread_t *thread 71 ) 72 { 73 ASSERT(thread != NULL); 74 ASSERT(thread->signature == SIG_ISCSI_THREAD); 75 76 mutex_enter(&thread->mgnt.mtx); 77 78 switch (thread->state) { 79 80 case ISCSI_THREAD_STATE_STARTED: 81 82 /* A kill signal is sent first. */ 83 thread->state = ISCSI_THREAD_STATE_DESTROYING; 84 mutex_enter(&thread->sign.mtx); 85 if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL)) { 86 thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_KILL; 87 cv_signal(&thread->sign.cdv); 88 } 89 mutex_exit(&thread->sign.mtx); 90 ddi_taskq_wait(thread->tq); 91 break; 92 93 case ISCSI_THREAD_STATE_STOPPED: 94 95 /* Switch the state and wait for the thread to exit. */ 96 thread->state = ISCSI_THREAD_STATE_DESTROYING; 97 break; 98 99 default: 100 ASSERT(0); 101 break; 102 } 103 104 mutex_exit(&thread->mgnt.mtx); 105 ddi_taskq_destroy(thread->tq); 106 cv_destroy(&thread->sign.cdv); 107 mutex_destroy(&thread->sign.mtx); 108 mutex_destroy(&thread->mgnt.mtx); 109 thread->signature = (uint32_t)~SIG_ISCSI_THREAD; 110 kmem_free(thread, sizeof (iscsi_thread_t)); 111 } 112 113 /* 114 * iscsi_thread_start - Starts the thread given as an entry parameter 115 */ 116 boolean_t 117 iscsi_thread_start( 118 iscsi_thread_t *thread 119 ) 120 { 121 boolean_t ret = B_FALSE; 122 123 ASSERT(thread != NULL); 124 ASSERT(thread->signature == SIG_ISCSI_THREAD); 125 126 mutex_enter(&thread->mgnt.mtx); 127 128 switch (thread->state) { 129 130 case ISCSI_THREAD_STATE_STARTED: 131 132 mutex_enter(&thread->sign.mtx); 133 134 thread->state = ISCSI_THREAD_STATE_STOPPING; 135 136 if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL)) { 137 thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_KILL; 138 cv_signal(&thread->sign.cdv); 139 } 140 mutex_exit(&thread->sign.mtx); 141 ddi_taskq_wait(thread->tq); 142 thread->state = ISCSI_THREAD_STATE_STOPPED; 143 /* FALLTHRU */ 144 145 case ISCSI_THREAD_STATE_STOPPED: 146 147 thread->sign.bitmap = 0; 148 thread->state = ISCSI_THREAD_STATE_STARTING; 149 150 if (ddi_taskq_dispatch(thread->tq, iscsi_threads_entry, 151 thread, DDI_SLEEP) == DDI_SUCCESS) { 152 /* 153 * The dispatch succeeded. 154 */ 155 thread->state = ISCSI_THREAD_STATE_STARTED; 156 ret = B_TRUE; 157 } 158 break; 159 160 default: 161 ASSERT(0); 162 break; 163 } 164 mutex_exit(&thread->mgnt.mtx); 165 return (ret); 166 } 167 168 /* 169 * iscsi_thread_stop - 170 */ 171 boolean_t 172 iscsi_thread_stop( 173 iscsi_thread_t *thread 174 ) 175 { 176 boolean_t ret = B_FALSE; 177 178 ASSERT(thread != NULL); 179 ASSERT(thread->signature == SIG_ISCSI_THREAD); 180 181 mutex_enter(&thread->mgnt.mtx); 182 183 switch (thread->state) { 184 185 case ISCSI_THREAD_STATE_STARTED: 186 187 mutex_enter(&thread->sign.mtx); 188 189 thread->state = ISCSI_THREAD_STATE_STOPPING; 190 191 if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL)) { 192 thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_KILL; 193 cv_signal(&thread->sign.cdv); 194 } 195 mutex_exit(&thread->sign.mtx); 196 ddi_taskq_wait(thread->tq); 197 thread->state = ISCSI_THREAD_STATE_STOPPED; 198 ret = B_TRUE; 199 break; 200 201 case ISCSI_THREAD_STATE_STOPPED: 202 ret = B_TRUE; 203 break; 204 205 default: 206 ASSERT(0); 207 break; 208 } 209 mutex_exit(&thread->mgnt.mtx); 210 return (ret); 211 } 212 213 /* 214 * iscsi_thread_send_kill - 215 */ 216 void 217 iscsi_thread_send_kill( 218 iscsi_thread_t *thread 219 ) 220 { 221 ASSERT(thread != NULL); 222 ASSERT(thread->signature == SIG_ISCSI_THREAD); 223 224 mutex_enter(&thread->mgnt.mtx); 225 226 switch (thread->state) { 227 228 case ISCSI_THREAD_STATE_STARTED: 229 230 mutex_enter(&thread->sign.mtx); 231 if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL)) { 232 thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_KILL; 233 cv_signal(&thread->sign.cdv); 234 } 235 mutex_exit(&thread->sign.mtx); 236 break; 237 238 default: 239 ASSERT(0); 240 break; 241 } 242 mutex_exit(&thread->mgnt.mtx); 243 } 244 245 /* 246 * iscsi_thread_send_wakeup - 247 */ 248 boolean_t 249 iscsi_thread_send_wakeup( 250 iscsi_thread_t *thread 251 ) 252 { 253 boolean_t ret = B_FALSE; 254 255 ASSERT(thread != NULL); 256 ASSERT(thread->signature == SIG_ISCSI_THREAD); 257 258 mutex_enter(&thread->mgnt.mtx); 259 260 switch (thread->state) { 261 262 case ISCSI_THREAD_STATE_STARTED: 263 264 mutex_enter(&thread->sign.mtx); 265 if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_WAKEUP)) { 266 thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_WAKEUP; 267 cv_signal(&thread->sign.cdv); 268 } 269 mutex_exit(&thread->sign.mtx); 270 ret = B_TRUE; 271 break; 272 273 default: 274 break; 275 } 276 mutex_exit(&thread->mgnt.mtx); 277 return (ret); 278 } 279 280 /* 281 * iscsi_thread_check_signals - 282 */ 283 uint32_t 284 iscsi_thread_check_signals( 285 iscsi_thread_t *thread 286 ) 287 { 288 uint32_t bitmap; 289 290 ASSERT(thread != NULL); 291 ASSERT(thread->signature == SIG_ISCSI_THREAD); 292 293 /* Acquire the mutex before anychecking. */ 294 mutex_enter(&thread->sign.mtx); 295 bitmap = thread->sign.bitmap; 296 mutex_exit(&thread->sign.mtx); 297 return (bitmap); 298 } 299 /* 300 * iscsi_thread_wait - 301 */ 302 int 303 iscsi_thread_wait( 304 iscsi_thread_t *thread, 305 clock_t timeout 306 ) 307 { 308 int rtn = 1; 309 310 ASSERT(thread != NULL); 311 ASSERT(thread->signature == SIG_ISCSI_THREAD); 312 313 /* Acquire the mutex before anychecking. */ 314 mutex_enter(&thread->sign.mtx); 315 316 /* Check the signals. */ 317 if (thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL) { 318 goto signal_kill; 319 } else if (thread->sign.bitmap & ISCSI_THREAD_SIGNAL_WAKEUP) { 320 goto signal_wakeup; 321 } else if (timeout == 0) { 322 goto iscsi_thread_sleep_exit; 323 } 324 325 if (timeout == -1) { 326 cv_wait(&thread->sign.cdv, &thread->sign.mtx); 327 } else { 328 rtn = cv_reltimedwait(&thread->sign.cdv, &thread->sign.mtx, 329 timeout, TR_CLOCK_TICK); 330 } 331 332 /* Check the signals. */ 333 if (thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL) { 334 goto signal_kill; 335 } else if (thread->sign.bitmap & ISCSI_THREAD_SIGNAL_WAKEUP) { 336 goto signal_wakeup; 337 } 338 339 iscsi_thread_sleep_exit: 340 mutex_exit(&thread->sign.mtx); 341 return (rtn); 342 343 signal_kill: 344 mutex_exit(&thread->sign.mtx); 345 return (0); 346 347 signal_wakeup: 348 thread->sign.bitmap &= ~ISCSI_THREAD_SIGNAL_WAKEUP; 349 mutex_exit(&thread->sign.mtx); 350 return (1); 351 } 352 353 /* 354 * iscsi_threads_entry - Common entry point for all threads 355 */ 356 static 357 void 358 iscsi_threads_entry( 359 void *arg 360 ) 361 { 362 iscsi_thread_t *thread; 363 364 thread = (iscsi_thread_t *)arg; 365 366 ASSERT(thread != NULL); 367 ASSERT(thread->signature == SIG_ISCSI_THREAD); 368 369 (thread->entry_point)(thread, thread->arg); 370 } 371