diff --git a/libs/clist/bench_test.go b/libs/clist/bench_test.go index 95973cc76..0288eb628 100644 --- a/libs/clist/bench_test.go +++ b/libs/clist/bench_test.go @@ -12,7 +12,6 @@ func BenchmarkDetaching(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { start.removed = true - start.DetachNext() start.DetachPrev() tmp := nxt nxt = nxt.Next() @@ -30,7 +29,6 @@ func BenchmarkRemoved(b *testing.B) { nxt := start.Next() b.ResetTimer() for i := 0; i < b.N; i++ { - start.Removed() tmp := nxt nxt = nxt.Next() start = tmp diff --git a/libs/clist/clist.go b/libs/clist/clist.go index a32098774..88b6ddb5f 100644 --- a/libs/clist/clist.go +++ b/libs/clist/clist.go @@ -44,14 +44,12 @@ waiting on NextWait() (since it's just a read operation). */ type CElement struct { - mtx tmsync.RWMutex - prev *CElement - prevWg *sync.WaitGroup - prevWaitCh chan struct{} - next *CElement - nextWg *sync.WaitGroup - nextWaitCh chan struct{} - removed bool + mtx tmsync.RWMutex + prev *CElement + prevWg *sync.WaitGroup + next *CElement + nextWg *sync.WaitGroup + removed bool Value interface{} // immutable } @@ -94,22 +92,36 @@ func (e *CElement) PrevWait() *CElement { } } -// PrevWaitChan can be used to wait until Prev becomes not nil. Once it does, -// channel will be closed. -func (e *CElement) PrevWaitChan() <-chan struct{} { - e.mtx.RLock() - defer e.mtx.RUnlock() - - return e.prevWaitCh -} - // NextWaitChan can be used to wait until Next becomes not nil. Once it does, // channel will be closed. func (e *CElement) NextWaitChan() <-chan struct{} { e.mtx.RLock() defer e.mtx.RUnlock() + wg := e.nextWg - return e.nextWaitCh + ret := make(chan struct{}) + go func() { + wg.Wait() + close(ret) + }() + + return ret +} + +// PrevWaitChan can be used to wait until Prev becomes not nil. Once it does, +// channel will be closed. +func (e *CElement) PrevWaitChan() <-chan struct{} { + e.mtx.RLock() + defer e.mtx.RUnlock() + wg := e.prevWg + + ret := make(chan struct{}) + go func() { + wg.Wait() + close(ret) + }() + + return ret } // Nonblocking, may return nil if at the end. @@ -128,23 +140,6 @@ func (e *CElement) Prev() *CElement { return prev } -func (e *CElement) Removed() bool { - e.mtx.RLock() - isRemoved := e.removed - e.mtx.RUnlock() - return isRemoved -} - -func (e *CElement) DetachNext() { - e.mtx.Lock() - if !e.removed { - e.mtx.Unlock() - panic("DetachNext() must be called after Remove(e)") - } - e.next = nil - e.mtx.Unlock() -} - func (e *CElement) DetachPrev() { e.mtx.Lock() if !e.removed { @@ -169,11 +164,9 @@ func (e *CElement) SetNext(newNext *CElement) { // events, new Add calls must happen after all previous Wait calls have // returned. e.nextWg = waitGroup1() // WaitGroups are difficult to re-use. - e.nextWaitCh = make(chan struct{}) } if oldNext == nil && newNext != nil { e.nextWg.Done() - close(e.nextWaitCh) } e.mtx.Unlock() } @@ -187,11 +180,9 @@ func (e *CElement) SetPrev(newPrev *CElement) { e.prev = newPrev if oldPrev != nil && newPrev == nil { e.prevWg = waitGroup1() // WaitGroups are difficult to re-use. - e.prevWaitCh = make(chan struct{}) } if oldPrev == nil && newPrev != nil { e.prevWg.Done() - close(e.prevWaitCh) } e.mtx.Unlock() } @@ -204,11 +195,9 @@ func (e *CElement) SetRemoved() { // This wakes up anyone waiting in either direction. if e.prev == nil { e.prevWg.Done() - close(e.prevWaitCh) } if e.next == nil { e.nextWg.Done() - close(e.nextWaitCh) } e.mtx.Unlock() } @@ -222,7 +211,6 @@ func (e *CElement) SetRemoved() { type CList struct { mtx tmsync.RWMutex wg *sync.WaitGroup - waitCh chan struct{} head *CElement // first element tail *CElement // last element len int // list length @@ -239,7 +227,6 @@ func newWithMax(maxLength int) *CList { l.maxLen = maxLength l.wg = waitGroup1() - l.waitCh = make(chan struct{}) l.head = nil l.tail = nil l.len = 0 @@ -306,7 +293,15 @@ func (l *CList) WaitChan() <-chan struct{} { l.mtx.Lock() defer l.mtx.Unlock() - return l.waitCh + wg := l.wg + + ret := make(chan struct{}) + go func() { + wg.Wait() + close(ret) + }() + + return ret } // Panics if list grows beyond its max length. @@ -315,20 +310,17 @@ func (l *CList) PushBack(v interface{}) *CElement { // Construct a new element e := &CElement{ - prev: nil, - prevWg: waitGroup1(), - prevWaitCh: make(chan struct{}), - next: nil, - nextWg: waitGroup1(), - nextWaitCh: make(chan struct{}), - removed: false, - Value: v, + prev: nil, + prevWg: waitGroup1(), + next: nil, + nextWg: waitGroup1(), + removed: false, + Value: v, } // Release waiters on FrontWait/BackWait maybe if l.len == 0 { l.wg.Done() - close(l.waitCh) } if l.len >= l.maxLen { panic(fmt.Sprintf("clist: maximum length list reached %d", l.maxLen)) @@ -372,7 +364,6 @@ func (l *CList) Remove(e *CElement) interface{} { // If we're removing the only item, make CList FrontWait/BackWait wait. if l.len == 1 { l.wg = waitGroup1() // WaitGroups are difficult to re-use. - l.waitCh = make(chan struct{}) } // Update l.len