Browse Source

clist: remove unused waitgroup from clist implementation (#7843)

pull/7861/head
Sam Kleinman 2 years ago
committed by GitHub
parent
commit
6280f45460
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 9 additions and 31 deletions
  1. +9
    -31
      internal/libs/clist/clist.go

+ 9
- 31
internal/libs/clist/clist.go View File

@ -44,10 +44,8 @@ waiting on NextWait() (since it's just a read operation).
type CElement struct { type CElement struct {
mtx sync.RWMutex mtx sync.RWMutex
prev *CElement prev *CElement
prevWg *sync.WaitGroup
prevWaitCh chan struct{} prevWaitCh chan struct{}
next *CElement next *CElement
nextWg *sync.WaitGroup
nextWaitCh chan struct{} nextWaitCh chan struct{}
removed bool removed bool
@ -60,15 +58,15 @@ func (e *CElement) NextWait() *CElement {
for { for {
e.mtx.RLock() e.mtx.RLock()
next := e.next next := e.next
nextWg := e.nextWg
removed := e.removed removed := e.removed
signal := e.nextWaitCh
e.mtx.RUnlock() e.mtx.RUnlock()
if next != nil || removed { if next != nil || removed {
return next return next
} }
nextWg.Wait()
<-signal
// e.next doesn't necessarily exist here. // e.next doesn't necessarily exist here.
// That's why we need to continue a for-loop. // That's why we need to continue a for-loop.
} }
@ -80,15 +78,15 @@ func (e *CElement) PrevWait() *CElement {
for { for {
e.mtx.RLock() e.mtx.RLock()
prev := e.prev prev := e.prev
prevWg := e.prevWg
removed := e.removed removed := e.removed
signal := e.prevWaitCh
e.mtx.RUnlock() e.mtx.RUnlock()
if prev != nil || removed { if prev != nil || removed {
return prev return prev
} }
prevWg.Wait()
<-signal
} }
} }
@ -166,11 +164,9 @@ func (e *CElement) SetNext(newNext *CElement) {
// If a WaitGroup is reused to wait for several independent sets of // If a WaitGroup is reused to wait for several independent sets of
// events, new Add calls must happen after all previous Wait calls have // events, new Add calls must happen after all previous Wait calls have
// returned. // returned.
e.nextWg = waitGroup1() // WaitGroups are difficult to re-use.
e.nextWaitCh = make(chan struct{}) e.nextWaitCh = make(chan struct{})
} }
if oldNext == nil && newNext != nil { if oldNext == nil && newNext != nil {
e.nextWg.Done()
close(e.nextWaitCh) close(e.nextWaitCh)
} }
e.mtx.Unlock() e.mtx.Unlock()
@ -180,35 +176,31 @@ func (e *CElement) SetNext(newNext *CElement) {
// concurrent goroutines waiting on prevWg // concurrent goroutines waiting on prevWg
func (e *CElement) SetPrev(newPrev *CElement) { func (e *CElement) SetPrev(newPrev *CElement) {
e.mtx.Lock() e.mtx.Lock()
defer e.mtx.Unlock()
oldPrev := e.prev oldPrev := e.prev
e.prev = newPrev e.prev = newPrev
if oldPrev != nil && newPrev == nil { if oldPrev != nil && newPrev == nil {
e.prevWg = waitGroup1() // WaitGroups are difficult to re-use.
e.prevWaitCh = make(chan struct{}) e.prevWaitCh = make(chan struct{})
} }
if oldPrev == nil && newPrev != nil { if oldPrev == nil && newPrev != nil {
e.prevWg.Done()
close(e.prevWaitCh) close(e.prevWaitCh)
} }
e.mtx.Unlock()
} }
func (e *CElement) SetRemoved() { func (e *CElement) SetRemoved() {
e.mtx.Lock() e.mtx.Lock()
defer e.mtx.Unlock()
e.removed = true e.removed = true
// This wakes up anyone waiting in either direction. // This wakes up anyone waiting in either direction.
if e.prev == nil { if e.prev == nil {
e.prevWg.Done()
close(e.prevWaitCh) close(e.prevWaitCh)
} }
if e.next == nil { if e.next == nil {
e.nextWg.Done()
close(e.nextWaitCh) close(e.nextWaitCh)
} }
e.mtx.Unlock()
} }
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
@ -236,7 +228,6 @@ func newWithMax(maxLength int) *CList {
l := new(CList) l := new(CList)
l.maxLen = maxLength l.maxLen = maxLength
l.wg = waitGroup1()
l.waitCh = make(chan struct{}) l.waitCh = make(chan struct{})
l.head = nil l.head = nil
l.tail = nil l.tail = nil
@ -264,13 +255,13 @@ func (l *CList) FrontWait() *CElement {
for { for {
l.mtx.RLock() l.mtx.RLock()
head := l.head head := l.head
wg := l.wg
signal := l.waitCh
l.mtx.RUnlock() l.mtx.RUnlock()
if head != nil { if head != nil {
return head return head
} }
wg.Wait()
<-signal
// NOTE: If you think l.head exists here, think harder. // NOTE: If you think l.head exists here, think harder.
} }
} }
@ -314,10 +305,8 @@ func (l *CList) PushBack(v interface{}) *CElement {
// Construct a new element // Construct a new element
e := &CElement{ e := &CElement{
prev: nil, prev: nil,
prevWg: waitGroup1(),
prevWaitCh: make(chan struct{}), prevWaitCh: make(chan struct{}),
next: nil, next: nil,
nextWg: waitGroup1(),
nextWaitCh: make(chan struct{}), nextWaitCh: make(chan struct{}),
removed: false, removed: false,
Value: v, Value: v,
@ -325,7 +314,6 @@ func (l *CList) PushBack(v interface{}) *CElement {
// Release waiters on FrontWait/BackWait maybe // Release waiters on FrontWait/BackWait maybe
if l.len == 0 { if l.len == 0 {
l.wg.Done()
close(l.waitCh) close(l.waitCh)
} }
if l.len >= l.maxLen { if l.len >= l.maxLen {
@ -350,26 +338,23 @@ func (l *CList) PushBack(v interface{}) *CElement {
// NOTE: As per the contract of CList, removed elements cannot be added back. // NOTE: As per the contract of CList, removed elements cannot be added back.
func (l *CList) Remove(e *CElement) interface{} { func (l *CList) Remove(e *CElement) interface{} {
l.mtx.Lock() l.mtx.Lock()
defer l.mtx.Unlock()
prev := e.Prev() prev := e.Prev()
next := e.Next() next := e.Next()
if l.head == nil || l.tail == nil { if l.head == nil || l.tail == nil {
l.mtx.Unlock()
panic("Remove(e) on empty CList") panic("Remove(e) on empty CList")
} }
if prev == nil && l.head != e { if prev == nil && l.head != e {
l.mtx.Unlock()
panic("Remove(e) with false head") panic("Remove(e) with false head")
} }
if next == nil && l.tail != e { if next == nil && l.tail != e {
l.mtx.Unlock()
panic("Remove(e) with false tail") panic("Remove(e) with false tail")
} }
// If we're removing the only item, make CList FrontWait/BackWait wait. // If we're removing the only item, make CList FrontWait/BackWait wait.
if l.len == 1 { if l.len == 1 {
l.wg = waitGroup1() // WaitGroups are difficult to re-use.
l.waitCh = make(chan struct{}) l.waitCh = make(chan struct{})
} }
@ -391,12 +376,5 @@ func (l *CList) Remove(e *CElement) interface{} {
// Set .Done() on e, otherwise waiters will wait forever. // Set .Done() on e, otherwise waiters will wait forever.
e.SetRemoved() e.SetRemoved()
l.mtx.Unlock()
return e.Value return e.Value
} }
func waitGroup1() (wg *sync.WaitGroup) {
wg = &sync.WaitGroup{}
wg.Add(1)
return
}

Loading…
Cancel
Save