| 566 | } |
| 567 | |
| 568 | Event * |
| 569 | EventProcessor::spawn_thread(Continuation *cont, const char *thr_name, size_t stacksize) |
| 570 | { |
| 571 | /* Spawning threads in a live system - There are two potential race conditions in this logic. The |
| 572 | first is multiple calls to this method. In that case @a all_dthreads can end up in a bad state |
| 573 | as the same entry is overwritten while another is left uninitialized. |
| 574 | |
| 575 | The other is read/write contention where another thread (e.g. the stats collection thread) is |
| 576 | iterating over the threads while the active count (@a n_dthreads) is being updated causing use |
| 577 | of a not yet initialized array element. |
| 578 | |
| 579 | This logic covers both situations. For write/write the actual array update is locked. The |
| 580 | potentially expensive set up is done outside the lock making the time spent locked small. For |
| 581 | read/write it suffices to do the active count increment after initializing the array |
| 582 | element. It's not a problem if, for one cycle, a new thread is skipped. |
| 583 | */ |
| 584 | |
| 585 | // Do as much as possible outside the lock. Until the array element and count is changed |
| 586 | // this is thread safe. |
| 587 | Event *e = eventAllocator.alloc(); |
| 588 | e->init(cont, 0, 0); |
| 589 | e->ethread = new EThread(DEDICATED, e); |
| 590 | e->mutex = e->ethread->mutex; |
| 591 | cont->mutex = e->ethread->mutex; |
| 592 | { |
| 593 | ink_scoped_mutex_lock lock(dedicated_thread_spawn_mutex); |
| 594 | ink_release_assert(n_dthreads < MAX_EVENT_THREADS); |
| 595 | all_dthreads[n_dthreads] = e->ethread; |
| 596 | ++n_dthreads; // Be very sure this is after the array element update. |
| 597 | } |
| 598 | |
| 599 | e->ethread->start(thr_name, nullptr, stacksize); |
| 600 | |
| 601 | return e; |
| 602 | } |
| 603 | |
| 604 | bool |
| 605 | EventProcessor::has_tg_started(int etype) |
no test coverage detected