From a2c106378a868b8365aa5a3315652936fa25f1d1 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 29 May 2019 10:55:16 -0700 Subject: [PATCH] avoid deadlock involving fair_queue::clear() Avoid destroying items while the queue lock is held. --- src/utils/pv/fairQueue.h | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/utils/pv/fairQueue.h b/src/utils/pv/fairQueue.h index 20447ff..0cafe46 100644 --- a/src/utils/pv/fairQueue.h +++ b/src/utils/pv/fairQueue.h @@ -7,6 +7,8 @@ #ifndef FAIRQUEUE_H #define FAIRQUEUE_H +#include + #ifdef epicsExportSharedSymbols # define fairQueueExportSharedSymbols # undef epicsExportSharedSymbols @@ -103,13 +105,31 @@ public: assert(ellCount(&list)==0); } + //! Remove all items. + //! @post empty()==true void clear() { - value_type C; - guard_t G(mutex); - do { - pop_front_try(C); - } while(C); + // destroy after unlock + std::vector garbage; + { + guard_t G(mutex); + + garbage.resize(unsigned(ellCount(&list))); + size_t i=0; + + while(ELLNODE *cur = ellGet(&list)) { + typedef typename entry::enode_t enode_t; + enode_t *PN = CONTAINER(cur, enode_t, node); + entry *P = PN->self; + assert(P->owner==this); + assert(P->Qcnt>0); + + PN->node.previous = PN->node.next = NULL; + P->owner = NULL; + P->Qcnt = 0u; + garbage[i++].swap(P->holder); + } + } } bool empty() const {