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 9 * http://www.opensource.org/licenses/cddl1.txt. 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 (c) 2004-2011 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <emlxs.h> 28 29 30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 31 EMLXS_MSG_DEF(EMLXS_THREAD_C); 32 33 static void emlxs_thread(emlxs_thread_t *ethread); 34 static void emlxs_taskq_thread(emlxs_taskq_thread_t *tthread); 35 36 37 static void 38 emlxs_taskq_thread(emlxs_taskq_thread_t *tthread) 39 { 40 emlxs_taskq_t *taskq; 41 void (*func) (); 42 void *arg; 43 44 taskq = tthread->taskq; 45 46 mutex_enter(&tthread->lock); 47 tthread->flags |= EMLXS_THREAD_STARTED; 48 49 while (!(tthread->flags & EMLXS_THREAD_KILLED)) { 50 mutex_enter(&taskq->put_lock); 51 tthread->next = taskq->put_head; 52 taskq->put_head = tthread; 53 taskq->put_count++; 54 mutex_exit(&taskq->put_lock); 55 56 tthread->flags |= EMLXS_THREAD_ASLEEP; 57 cv_wait(&tthread->cv_flag, &tthread->lock); 58 tthread->flags &= ~EMLXS_THREAD_ASLEEP; 59 60 if (tthread->func) { 61 func = tthread->func; 62 arg = tthread->arg; 63 64 tthread->flags |= EMLXS_THREAD_BUSY; 65 mutex_exit(&tthread->lock); 66 67 func(taskq->hba, arg); 68 69 mutex_enter(&tthread->lock); 70 tthread->flags &= ~EMLXS_THREAD_BUSY; 71 } 72 } 73 74 tthread->flags |= EMLXS_THREAD_ENDED; 75 mutex_exit(&tthread->lock); 76 77 thread_exit(); 78 79 } /* emlxs_taskq_thread() */ 80 81 82 83 uint32_t 84 emlxs_taskq_dispatch(emlxs_taskq_t *taskq, void (*func) (), void *arg) 85 { 86 emlxs_taskq_thread_t *tthread = NULL; 87 88 mutex_enter(&taskq->get_lock); 89 90 /* Make sure taskq is open for business */ 91 if (!taskq->open) { 92 mutex_exit(&taskq->get_lock); 93 return (0); 94 } 95 96 /* Check get_list for a thread */ 97 if (taskq->get_head) { 98 /* Get the next thread */ 99 tthread = taskq->get_head; 100 taskq->get_count--; 101 taskq->get_head = (taskq->get_count) ? tthread->next : NULL; 102 tthread->next = NULL; 103 } 104 105 /* Else check put_list for a thread */ 106 else if (taskq->put_head) { 107 108 /* Move put_list to get_list */ 109 mutex_enter(&taskq->put_lock); 110 taskq->get_head = taskq->put_head; 111 taskq->get_count = taskq->put_count; 112 taskq->put_head = NULL; 113 taskq->put_count = 0; 114 mutex_exit(&taskq->put_lock); 115 116 /* Get the next thread */ 117 tthread = taskq->get_head; 118 taskq->get_count--; 119 taskq->get_head = (taskq->get_count) ? tthread->next : NULL; 120 tthread->next = NULL; 121 } 122 123 mutex_exit(&taskq->get_lock); 124 125 /* Wake up the thread if one exists */ 126 if (tthread) { 127 mutex_enter(&tthread->lock); 128 tthread->func = func; 129 tthread->arg = arg; 130 cv_signal(&tthread->cv_flag); 131 mutex_exit(&tthread->lock); 132 133 return (1); 134 } 135 136 return (0); 137 138 } /* emlxs_taskq_dispatch() */ 139 140 141 142 void 143 emlxs_taskq_create(emlxs_hba_t *hba, emlxs_taskq_t *taskq) 144 { 145 emlxs_taskq_thread_t *tthread; 146 uint32_t i; 147 148 149 /* If taskq is already open then quit */ 150 if (taskq->open) { 151 return; 152 } 153 154 /* Zero the taskq */ 155 bzero(taskq, sizeof (emlxs_taskq_t)); 156 157 mutex_init(&taskq->get_lock, NULL, MUTEX_DRIVER, 158 DDI_INTR_PRI(hba->intr_arg)); 159 160 mutex_enter(&taskq->get_lock); 161 162 taskq->hba = hba; 163 164 mutex_init(&taskq->put_lock, NULL, MUTEX_DRIVER, 165 DDI_INTR_PRI(hba->intr_arg)); 166 167 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) { 168 tthread = &taskq->thread_list[i]; 169 tthread->taskq = taskq; 170 171 mutex_init(&tthread->lock, NULL, MUTEX_DRIVER, 172 DDI_INTR_PRI(hba->intr_arg)); 173 174 cv_init(&tthread->cv_flag, NULL, CV_DRIVER, NULL); 175 176 tthread->flags |= EMLXS_THREAD_INITD; 177 tthread->thread = 178 thread_create(NULL, 0, emlxs_taskq_thread, 179 (char *)tthread, 0, &p0, TS_RUN, v.v_maxsyspri - 2); 180 } 181 182 /* Open the taskq */ 183 taskq->open = 1; 184 185 mutex_exit(&taskq->get_lock); 186 187 return; 188 189 } /* emlxs_taskq_create() */ 190 191 192 void 193 emlxs_taskq_destroy(emlxs_taskq_t *taskq) 194 { 195 emlxs_taskq_thread_t *tthread; 196 uint32_t i; 197 198 /* If taskq already closed, then quit */ 199 if (!taskq->open) { 200 return; 201 } 202 203 mutex_enter(&taskq->get_lock); 204 205 /* If taskq already closed, then quit */ 206 if (!taskq->open) { 207 mutex_exit(&taskq->get_lock); 208 return; 209 } 210 211 taskq->open = 0; 212 mutex_exit(&taskq->get_lock); 213 214 215 /* No more threads can be dispatched now */ 216 217 /* Kill the threads */ 218 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) { 219 tthread = &taskq->thread_list[i]; 220 221 /* 222 * If the thread lock can be acquired, 223 * it is in one of these states: 224 * 1. Thread not started. 225 * 2. Thread asleep. 226 * 3. Thread busy. 227 * 4. Thread ended. 228 */ 229 mutex_enter(&tthread->lock); 230 tthread->flags |= EMLXS_THREAD_KILLED; 231 cv_signal(&tthread->cv_flag); 232 233 /* Wait for thread to die */ 234 while (!(tthread->flags & EMLXS_THREAD_ENDED)) { 235 mutex_exit(&tthread->lock); 236 delay(drv_usectohz(10000)); 237 mutex_enter(&tthread->lock); 238 } 239 mutex_exit(&tthread->lock); 240 241 /* Clean up thread */ 242 mutex_destroy(&tthread->lock); 243 cv_destroy(&tthread->cv_flag); 244 } 245 246 /* Clean up taskq */ 247 mutex_destroy(&taskq->put_lock); 248 mutex_destroy(&taskq->get_lock); 249 250 return; 251 252 } /* emlxs_taskq_destroy() */ 253 254 255 256 static void 257 emlxs_thread(emlxs_thread_t *ethread) 258 { 259 emlxs_hba_t *hba; 260 void (*func) (); 261 void *arg1; 262 void *arg2; 263 264 if (ethread->flags & EMLXS_THREAD_RUN_ONCE) { 265 hba = ethread->hba; 266 ethread->flags |= EMLXS_THREAD_STARTED; 267 268 if (!(ethread->flags & EMLXS_THREAD_KILLED)) { 269 func = ethread->func; 270 arg1 = ethread->arg1; 271 arg2 = ethread->arg2; 272 273 func(hba, arg1, arg2); 274 } 275 276 ethread->flags |= EMLXS_THREAD_ENDED; 277 ethread->flags &= ~EMLXS_THREAD_INITD; 278 279 /* Remove the thread from the spawn thread list */ 280 mutex_enter(&EMLXS_SPAWN_LOCK); 281 if (hba->spawn_thread_head == ethread) 282 hba->spawn_thread_head = ethread->next; 283 if (hba->spawn_thread_tail == ethread) 284 hba->spawn_thread_tail = ethread->prev; 285 286 if (ethread->prev) 287 ethread->prev->next = ethread->next; 288 if (ethread->next) 289 ethread->next->prev = ethread->prev; 290 291 ethread->next = ethread->prev = NULL; 292 293 kmem_free(ethread, sizeof (emlxs_thread_t)); 294 295 mutex_exit(&EMLXS_SPAWN_LOCK); 296 } 297 else 298 { 299 /* 300 * If the thread lock can be acquired, 301 * it is in one of these states: 302 * 1. Thread not started. 303 * 2. Thread asleep. 304 * 3. Thread busy. 305 * 4. Thread ended. 306 */ 307 mutex_enter(ðread->lock); 308 ethread->flags |= EMLXS_THREAD_STARTED; 309 310 while (!(ethread->flags & EMLXS_THREAD_KILLED)) { 311 if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) { 312 ethread->flags |= EMLXS_THREAD_ASLEEP; 313 cv_wait(ðread->cv_flag, ðread->lock); 314 } 315 316 ethread->flags &= 317 ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED); 318 319 if (ethread->func) { 320 func = ethread->func; 321 arg1 = ethread->arg1; 322 arg2 = ethread->arg2; 323 ethread->func = NULL; 324 ethread->arg1 = NULL; 325 ethread->arg2 = NULL; 326 327 ethread->flags |= EMLXS_THREAD_BUSY; 328 mutex_exit(ðread->lock); 329 330 func(ethread->hba, arg1, arg2); 331 332 mutex_enter(ðread->lock); 333 ethread->flags &= ~EMLXS_THREAD_BUSY; 334 } 335 } 336 337 ethread->flags |= EMLXS_THREAD_ENDED; 338 mutex_exit(ðread->lock); 339 } 340 341 thread_exit(); 342 343 } /* emlxs_thread() */ 344 345 346 void 347 emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread) 348 { 349 uint16_t pri; 350 351 if (ethread->flags & EMLXS_THREAD_INITD) { 352 return; 353 } 354 355 bzero(ethread, sizeof (emlxs_thread_t)); 356 357 mutex_init(ðread->lock, NULL, MUTEX_DRIVER, 358 DDI_INTR_PRI(hba->intr_arg)); 359 360 cv_init(ðread->cv_flag, NULL, CV_DRIVER, NULL); 361 362 ethread->hba = hba; 363 ethread->flags |= EMLXS_THREAD_INITD; 364 365 pri = v.v_maxsyspri - 2; 366 367 ethread->thread = 368 thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0, 369 TS_RUN, pri); 370 371 } /* emlxs_thread_create() */ 372 373 374 void 375 emlxs_thread_destroy(emlxs_thread_t *ethread) 376 { 377 /* 378 * If the thread lock can be acquired, 379 * it is in one of these states: 380 * 1. Thread not started. 381 * 2. Thread asleep. 382 * 3. Thread busy. 383 * 4. Thread ended. 384 */ 385 if (!(ethread->flags & EMLXS_THREAD_INITD)) { 386 return; 387 } 388 389 390 mutex_enter(ðread->lock); 391 392 if (ethread->flags & EMLXS_THREAD_ENDED) { 393 mutex_exit(ðread->lock); 394 return; 395 } 396 397 ethread->flags &= ~EMLXS_THREAD_INITD; 398 ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED); 399 ethread->func = NULL; 400 ethread->arg1 = NULL; 401 ethread->arg2 = NULL; 402 cv_signal(ðread->cv_flag); 403 404 /* Wait for thread to end */ 405 while (!(ethread->flags & EMLXS_THREAD_ENDED)) { 406 mutex_exit(ðread->lock); 407 delay(drv_usectohz(10000)); 408 mutex_enter(ðread->lock); 409 } 410 411 mutex_exit(ðread->lock); 412 413 cv_destroy(ðread->cv_flag); 414 mutex_destroy(ðread->lock); 415 416 return; 417 418 } /* emlxs_thread_destroy() */ 419 420 421 void 422 emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ()) 423 { 424 425 /* 426 * If the thread lock can be acquired, 427 * it is in one of these states: 428 * 1. Thread not started. 429 * 2. Thread asleep. 430 * 3. Thread busy. 431 * 4. Thread ended. 432 */ 433 if (!(ethread->flags & EMLXS_THREAD_INITD)) { 434 return; 435 } 436 437 mutex_enter(ðread->lock); 438 439 if (ethread->flags & EMLXS_THREAD_ENDED) { 440 return; 441 } 442 443 while (!(ethread->flags & EMLXS_THREAD_STARTED)) { 444 mutex_exit(ðread->lock); 445 delay(drv_usectohz(10000)); 446 mutex_enter(ðread->lock); 447 448 if (ethread->flags & EMLXS_THREAD_ENDED) { 449 return; 450 } 451 } 452 453 ethread->flags |= EMLXS_THREAD_TRIGGERED; 454 ethread->func = func; 455 ethread->arg1 = NULL; 456 ethread->arg2 = NULL; 457 458 if (ethread->flags & EMLXS_THREAD_ASLEEP) { 459 cv_signal(ðread->cv_flag); 460 } 461 462 mutex_exit(ðread->lock); 463 464 return; 465 466 } /* emlxs_thread_trigger1() */ 467 468 469 void 470 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), CHANNEL *cp) 471 { 472 473 /* 474 * If the thread lock can be acquired, 475 * it is in one of these states: 476 * 1. Thread not started. 477 * 2. Thread asleep. 478 * 3. Thread busy. 479 * 4. Thread ended. 480 */ 481 if (!(ethread->flags & EMLXS_THREAD_INITD)) { 482 return; 483 } 484 485 mutex_enter(ðread->lock); 486 487 if (ethread->flags & EMLXS_THREAD_ENDED) { 488 return; 489 } 490 491 while (!(ethread->flags & EMLXS_THREAD_STARTED)) { 492 mutex_exit(ðread->lock); 493 delay(drv_usectohz(10000)); 494 mutex_enter(ðread->lock); 495 496 if (ethread->flags & EMLXS_THREAD_ENDED) { 497 return; 498 } 499 } 500 501 ethread->flags |= EMLXS_THREAD_TRIGGERED; 502 ethread->func = func; 503 ethread->arg1 = (void *)cp; 504 ethread->arg2 = NULL; 505 506 if (ethread->flags & EMLXS_THREAD_ASLEEP) { 507 cv_signal(ðread->cv_flag); 508 } 509 510 mutex_exit(ðread->lock); 511 512 return; 513 514 } /* emlxs_thread_trigger2() */ 515 516 517 void 518 emlxs_thread_spawn(emlxs_hba_t *hba, void (*func) (), void *arg1, void *arg2) 519 { 520 emlxs_port_t *port = &PPORT; 521 emlxs_thread_t *ethread; 522 523 /* Create a thread */ 524 ethread = (emlxs_thread_t *)kmem_alloc(sizeof (emlxs_thread_t), 525 KM_NOSLEEP); 526 527 if (ethread == NULL) { 528 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg, 529 "Unable to allocate thread object."); 530 531 return; 532 } 533 534 bzero(ethread, sizeof (emlxs_thread_t)); 535 ethread->hba = hba; 536 ethread->flags = EMLXS_THREAD_INITD | EMLXS_THREAD_RUN_ONCE; 537 ethread->func = func; 538 ethread->arg1 = arg1; 539 ethread->arg2 = arg2; 540 541 /* Queue the thread on the spawn thread list */ 542 mutex_enter(&EMLXS_SPAWN_LOCK); 543 544 /* Dont spawn the thread if the spawn list is closed */ 545 if (hba->spawn_open == 0) { 546 mutex_exit(&EMLXS_SPAWN_LOCK); 547 548 /* destroy the thread */ 549 kmem_free(ethread, sizeof (emlxs_thread_t)); 550 return; 551 } 552 553 if (hba->spawn_thread_head == NULL) { 554 hba->spawn_thread_head = ethread; 555 } 556 else 557 { 558 hba->spawn_thread_tail->next = ethread; 559 ethread->prev = hba->spawn_thread_tail; 560 } 561 562 hba->spawn_thread_tail = ethread; 563 mutex_exit(&EMLXS_SPAWN_LOCK); 564 565 (void) thread_create(NULL, 0, &emlxs_thread, (char *)ethread, 0, &p0, 566 TS_RUN, v.v_maxsyspri - 2); 567 568 } /* emlxs_thread_spawn() */ 569 570 571 void 572 emlxs_thread_spawn_create(emlxs_hba_t *hba) 573 { 574 mutex_enter(&EMLXS_SPAWN_LOCK); 575 if (hba->spawn_open) { 576 mutex_exit(&EMLXS_SPAWN_LOCK); 577 return; 578 } 579 580 hba->spawn_thread_head = NULL; 581 hba->spawn_thread_tail = NULL; 582 583 hba->spawn_open = 1; 584 mutex_exit(&EMLXS_SPAWN_LOCK); 585 586 } 587 588 589 void 590 emlxs_thread_spawn_destroy(emlxs_hba_t *hba) 591 { 592 emlxs_thread_t *ethread; 593 594 mutex_enter(&EMLXS_SPAWN_LOCK); 595 if (hba->spawn_open == 0) { 596 mutex_exit(&EMLXS_SPAWN_LOCK); 597 return; 598 } 599 600 hba->spawn_open = 0; 601 602 for (ethread = hba->spawn_thread_head; ethread; 603 ethread = ethread->next) { 604 ethread->flags |= EMLXS_THREAD_KILLED; 605 } 606 607 /* Wait for all the spawned threads to complete */ 608 while (hba->spawn_thread_head) { 609 mutex_exit(&EMLXS_SPAWN_LOCK); 610 delay(drv_usectohz(10000)); 611 mutex_enter(&EMLXS_SPAWN_LOCK); 612 } 613 614 mutex_exit(&EMLXS_SPAWN_LOCK); 615 } 616