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