You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
2.5 KiB

9 years ago
  1. package common
  2. /*
  3. The purpose of CList is to provide a goroutine-safe linked-list.
  4. NOTE: Not all methods of container/list are (yet) implemented.
  5. */
  6. import (
  7. "sync"
  8. "sync/atomic"
  9. "unsafe"
  10. )
  11. // CElement is an element of a linked-list
  12. // Traversal from a CElement are goroutine-safe.
  13. type CElement struct {
  14. next unsafe.Pointer
  15. wg *sync.WaitGroup
  16. Value interface{}
  17. }
  18. // Blocking implementation of Next().
  19. // If return is nil, this element was removed from the list.
  20. func (e *CElement) NextWait() *CElement {
  21. e.wg.Wait()
  22. return e.Next()
  23. }
  24. func (e *CElement) Next() *CElement {
  25. next := atomic.LoadPointer(&e.next)
  26. if next == nil {
  27. return nil
  28. }
  29. return (*CElement)(next)
  30. }
  31. // CList represents a linked list.
  32. // The zero value for CList is an empty list ready to use.
  33. // Operations are goroutine-safe.
  34. type CList struct {
  35. mtx sync.Mutex
  36. wg *sync.WaitGroup
  37. head *CElement // first element
  38. tail *CElement // last element
  39. len int // list length
  40. }
  41. func (l *CList) Init() *CList {
  42. l.mtx.Lock()
  43. defer l.mtx.Unlock()
  44. l.wg = waitGroup1()
  45. l.head = nil
  46. l.tail = nil
  47. l.len = 0
  48. return l
  49. }
  50. func NewCList() *CList { return new(CList).Init() }
  51. func (l *CList) Len() int {
  52. l.mtx.Lock()
  53. defer l.mtx.Unlock()
  54. return l.len
  55. }
  56. func (l *CList) Front() *CElement {
  57. l.mtx.Lock()
  58. defer l.mtx.Unlock()
  59. return l.head
  60. }
  61. func (l *CList) FrontWait() *CElement {
  62. for {
  63. l.mtx.Lock()
  64. head := l.head
  65. wg := l.wg
  66. l.mtx.Unlock()
  67. if head == nil {
  68. wg.Wait()
  69. } else {
  70. return head
  71. }
  72. }
  73. }
  74. func (l *CList) Back() *CElement {
  75. l.mtx.Lock()
  76. defer l.mtx.Unlock()
  77. return l.tail
  78. }
  79. func (l *CList) BackWait() *CElement {
  80. for {
  81. l.mtx.Lock()
  82. tail := l.tail
  83. wg := l.wg
  84. l.mtx.Unlock()
  85. if tail == nil {
  86. wg.Wait()
  87. } else {
  88. return tail
  89. }
  90. }
  91. }
  92. func (l *CList) PushBack(v interface{}) *CElement {
  93. e := &CElement{
  94. next: nil,
  95. wg: waitGroup1(),
  96. Value: v,
  97. }
  98. l.mtx.Lock()
  99. defer l.mtx.Unlock()
  100. l.len += 1
  101. if l.tail == nil {
  102. l.head = e
  103. l.tail = e
  104. l.wg.Done()
  105. return e
  106. } else {
  107. oldTail := l.tail
  108. atomic.StorePointer(&oldTail.next, unsafe.Pointer(e))
  109. l.tail = e
  110. oldTail.wg.Done()
  111. return e
  112. }
  113. return e
  114. }
  115. func (l *CList) RemoveFront() interface{} {
  116. l.mtx.Lock()
  117. defer l.mtx.Unlock()
  118. if l.head == nil {
  119. return nil
  120. }
  121. oldFront := l.head
  122. next := (*CElement)(oldFront.next)
  123. l.head = next
  124. if next == nil {
  125. l.tail = nil
  126. l.wg = waitGroup1()
  127. }
  128. l.len -= 1
  129. atomic.StorePointer(&oldFront.next, unsafe.Pointer(nil))
  130. return oldFront.Value
  131. }
  132. func waitGroup1() (wg *sync.WaitGroup) {
  133. wg = &sync.WaitGroup{}
  134. wg.Add(1)
  135. return
  136. }