diff --git a/include/znc/Socket.h b/include/znc/Socket.h index 36aec425..e379b63e 100644 --- a/include/znc/Socket.h +++ b/include/znc/Socket.h @@ -149,6 +149,11 @@ private: static void* TDNSThread(void* argument); static void DoDNS(TDNSArg *arg); + /** Must be called with threadStatus->mutex held. + * @returns false when the calling DNS thread should exit. + */ + static bool ThreadNeeded(struct TDNSStatus* status); + TDNSStatus m_threadStatus; #endif protected: diff --git a/src/Socket.cpp b/src/Socket.cpp index f8dc7d6e..8e356db9 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -56,6 +56,15 @@ public: } }; +bool CSockManager::ThreadNeeded(struct TDNSStatus* threadStatus) +{ + // We should keep a number of idle threads alive + if (threadStatus->num_idle > MAX_IDLE_THREADS) + return false; + // If ZNC is shutting down, all threads should exit + return !threadStatus->done; +} + void* CSockManager::TDNSThread(void* argument) { TDNSStatus *threadStatus = (TDNSStatus *) argument; @@ -63,18 +72,19 @@ void* CSockManager::TDNSThread(void* argument) { threadStatus->num_threads++; threadStatus->num_idle++; while (true) { - /* Wait for a DNS job for us to do */ - if (threadStatus->jobs.empty()) { - if (threadStatus->num_idle > MAX_IDLE_THREADS) + /* Wait for a DNS job for us to do. This is a while()-loop + * because POSIX allows spurious wakeups from pthread_cond_wait. + */ + while (threadStatus->jobs.empty()) { + if (!ThreadNeeded(threadStatus)) break; pthread_cond_wait(&threadStatus->cond, &threadStatus->mutex); } - if (threadStatus->done) + if (!ThreadNeeded(threadStatus)) break; /* Figure out a DNS job to do */ - assert(!threadStatus->jobs.empty()); assert(threadStatus->num_idle > 0); TDNSArg *job = threadStatus->jobs.front(); threadStatus->jobs.pop_front();