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