|
@ -72,27 +72,9 @@ func (e *CElement) NextWait() *CElement { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Blocking implementation of Prev().
|
|
|
|
|
|
// May return nil iff CElement was head and got removed.
|
|
|
|
|
|
func (e *CElement) PrevWait() *CElement { |
|
|
|
|
|
for { |
|
|
|
|
|
e.mtx.RLock() |
|
|
|
|
|
prev := e.prev |
|
|
|
|
|
removed := e.removed |
|
|
|
|
|
signal := e.prevWaitCh |
|
|
|
|
|
e.mtx.RUnlock() |
|
|
|
|
|
|
|
|
|
|
|
if prev != nil || removed { |
|
|
|
|
|
return prev |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
<-signal |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// PrevWaitChan can be used to wait until Prev becomes not nil. Once it does,
|
|
|
|
|
|
|
|
|
// prevWaitChan can be used to wait until Prev becomes not nil. Once it does,
|
|
|
// channel will be closed.
|
|
|
// channel will be closed.
|
|
|
func (e *CElement) PrevWaitChan() <-chan struct{} { |
|
|
|
|
|
|
|
|
func (e *CElement) prevWaitChan() <-chan struct{} { |
|
|
e.mtx.RLock() |
|
|
e.mtx.RLock() |
|
|
defer e.mtx.RUnlock() |
|
|
defer e.mtx.RUnlock() |
|
|
|
|
|
|
|
@ -131,7 +113,7 @@ func (e *CElement) Removed() bool { |
|
|
return isRemoved |
|
|
return isRemoved |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (e *CElement) DetachNext() { |
|
|
|
|
|
|
|
|
func (e *CElement) detachNext() { |
|
|
e.mtx.Lock() |
|
|
e.mtx.Lock() |
|
|
if !e.removed { |
|
|
if !e.removed { |
|
|
e.mtx.Unlock() |
|
|
e.mtx.Unlock() |
|
@ -153,7 +135,7 @@ func (e *CElement) DetachPrev() { |
|
|
|
|
|
|
|
|
// NOTE: This function needs to be safe for
|
|
|
// NOTE: This function needs to be safe for
|
|
|
// concurrent goroutines waiting on nextWg.
|
|
|
// concurrent goroutines waiting on nextWg.
|
|
|
func (e *CElement) SetNext(newNext *CElement) { |
|
|
|
|
|
|
|
|
func (e *CElement) setNext(newNext *CElement) { |
|
|
e.mtx.Lock() |
|
|
e.mtx.Lock() |
|
|
|
|
|
|
|
|
oldNext := e.next |
|
|
oldNext := e.next |
|
@ -174,7 +156,7 @@ func (e *CElement) SetNext(newNext *CElement) { |
|
|
|
|
|
|
|
|
// NOTE: This function needs to be safe for
|
|
|
// NOTE: This function needs to be safe for
|
|
|
// 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() |
|
|
defer e.mtx.Unlock() |
|
|
|
|
|
|
|
@ -188,7 +170,7 @@ func (e *CElement) SetPrev(newPrev *CElement) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (e *CElement) SetRemoved() { |
|
|
|
|
|
|
|
|
func (e *CElement) setRemoved() { |
|
|
e.mtx.Lock() |
|
|
e.mtx.Lock() |
|
|
defer e.mtx.Unlock() |
|
|
defer e.mtx.Unlock() |
|
|
|
|
|
|
|
@ -250,7 +232,7 @@ func (l *CList) Front() *CElement { |
|
|
return head |
|
|
return head |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (l *CList) FrontWait() *CElement { |
|
|
|
|
|
|
|
|
func (l *CList) frontWait() *CElement { |
|
|
// Loop until the head is non-nil else wait and try again
|
|
|
// Loop until the head is non-nil else wait and try again
|
|
|
for { |
|
|
for { |
|
|
l.mtx.RLock() |
|
|
l.mtx.RLock() |
|
@ -273,22 +255,6 @@ func (l *CList) Back() *CElement { |
|
|
return back |
|
|
return back |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (l *CList) BackWait() *CElement { |
|
|
|
|
|
for { |
|
|
|
|
|
l.mtx.RLock() |
|
|
|
|
|
tail := l.tail |
|
|
|
|
|
wg := l.wg |
|
|
|
|
|
l.mtx.RUnlock() |
|
|
|
|
|
|
|
|
|
|
|
if tail != nil { |
|
|
|
|
|
return tail |
|
|
|
|
|
} |
|
|
|
|
|
wg.Wait() |
|
|
|
|
|
// l.tail doesn't necessarily exist here.
|
|
|
|
|
|
// That's why we need to continue a for-loop.
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// WaitChan can be used to wait until Front or Back becomes not nil. Once it
|
|
|
// WaitChan can be used to wait until Front or Back becomes not nil. Once it
|
|
|
// does, channel will be closed.
|
|
|
// does, channel will be closed.
|
|
|
func (l *CList) WaitChan() <-chan struct{} { |
|
|
func (l *CList) WaitChan() <-chan struct{} { |
|
@ -326,8 +292,8 @@ func (l *CList) PushBack(v interface{}) *CElement { |
|
|
l.head = e |
|
|
l.head = e |
|
|
l.tail = e |
|
|
l.tail = e |
|
|
} else { |
|
|
} else { |
|
|
e.SetPrev(l.tail) // We must init e first.
|
|
|
|
|
|
l.tail.SetNext(e) // This will make e accessible.
|
|
|
|
|
|
|
|
|
e.setPrev(l.tail) // We must init e first.
|
|
|
|
|
|
l.tail.setNext(e) // This will make e accessible.
|
|
|
l.tail = e // Update the list.
|
|
|
l.tail = e // Update the list.
|
|
|
} |
|
|
} |
|
|
l.mtx.Unlock() |
|
|
l.mtx.Unlock() |
|
@ -365,16 +331,16 @@ func (l *CList) Remove(e *CElement) interface{} { |
|
|
if prev == nil { |
|
|
if prev == nil { |
|
|
l.head = next |
|
|
l.head = next |
|
|
} else { |
|
|
} else { |
|
|
prev.SetNext(next) |
|
|
|
|
|
|
|
|
prev.setNext(next) |
|
|
} |
|
|
} |
|
|
if next == nil { |
|
|
if next == nil { |
|
|
l.tail = prev |
|
|
l.tail = prev |
|
|
} else { |
|
|
} else { |
|
|
next.SetPrev(prev) |
|
|
|
|
|
|
|
|
next.setPrev(prev) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Set .Done() on e, otherwise waiters will wait forever.
|
|
|
// Set .Done() on e, otherwise waiters will wait forever.
|
|
|
e.SetRemoved() |
|
|
|
|
|
|
|
|
e.setRemoved() |
|
|
|
|
|
|
|
|
return e.Value |
|
|
return e.Value |
|
|
} |
|
|
} |