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