operations.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package webrtc
  2. import (
  3. "container/list"
  4. "sync"
  5. )
  6. // Operation is a function
  7. type operation func()
  8. // Operations is a task executor.
  9. type operations struct {
  10. mu sync.Mutex
  11. busy bool
  12. ops *list.List
  13. }
  14. func newOperations() *operations {
  15. return &operations{
  16. ops: list.New(),
  17. }
  18. }
  19. // Enqueue adds a new action to be executed. If there are no actions scheduled,
  20. // the execution will start immediately in a new goroutine.
  21. func (o *operations) Enqueue(op operation) {
  22. if op == nil {
  23. return
  24. }
  25. o.mu.Lock()
  26. running := o.busy
  27. o.ops.PushBack(op)
  28. o.busy = true
  29. o.mu.Unlock()
  30. if !running {
  31. go o.start()
  32. }
  33. }
  34. // IsEmpty checks if there are tasks in the queue
  35. func (o *operations) IsEmpty() bool {
  36. o.mu.Lock()
  37. defer o.mu.Unlock()
  38. return o.ops.Len() == 0
  39. }
  40. // Done blocks until all currently enqueued operations are finished executing.
  41. // For more complex synchronization, use Enqueue directly.
  42. func (o *operations) Done() {
  43. var wg sync.WaitGroup
  44. wg.Add(1)
  45. o.Enqueue(func() {
  46. wg.Done()
  47. })
  48. wg.Wait()
  49. }
  50. func (o *operations) pop() func() {
  51. o.mu.Lock()
  52. defer o.mu.Unlock()
  53. if o.ops.Len() == 0 {
  54. return nil
  55. }
  56. e := o.ops.Front()
  57. o.ops.Remove(e)
  58. if op, ok := e.Value.(operation); ok {
  59. return op
  60. }
  61. return nil
  62. }
  63. func (o *operations) start() {
  64. defer func() {
  65. o.mu.Lock()
  66. defer o.mu.Unlock()
  67. if o.ops.Len() == 0 {
  68. o.busy = false
  69. return
  70. }
  71. // either a new operation was enqueued while we
  72. // were busy, or an operation panicked
  73. go o.start()
  74. }()
  75. fn := o.pop()
  76. for fn != nil {
  77. fn()
  78. fn = o.pop()
  79. }
  80. }