github.com/docker/compose-on-kubernetes@v0.5.0/internal/registry/signaler.go (about) 1 package registry 2 3 import ( 4 "sync" 5 ) 6 7 // signaler is a single-shot notification system through channel and callbacks 8 type signaler struct { 9 callbacks map[int]func() 10 signals []chan struct{} 11 mutex sync.Mutex 12 triggered bool 13 nextIndex int 14 } 15 16 // newSignaler returns a new signaler 17 func newSignaler() *signaler { 18 return &signaler{ 19 callbacks: make(map[int]func()), 20 } 21 } 22 23 // Register registers a callback function on trigger and returns an uid 24 func (s *signaler) Register(f func()) int { 25 s.mutex.Lock() 26 if s.triggered { 27 s.mutex.Unlock() 28 f() 29 return -1 30 } 31 idx := s.nextIndex 32 s.nextIndex++ 33 s.callbacks[idx] = f 34 s.mutex.Unlock() 35 return idx 36 } 37 38 // Unregister unregisters a callback function by uid 39 func (s *signaler) Unregister(id int) { 40 s.mutex.Lock() 41 defer s.mutex.Unlock() 42 delete(s.callbacks, id) 43 } 44 45 // Channel registers a channel reader. 46 func (s *signaler) Channel() chan struct{} { 47 res := make(chan struct{}, 1) 48 s.mutex.Lock() 49 if s.triggered { 50 res <- struct{}{} 51 } else { 52 s.signals = append(s.signals, res) 53 } 54 s.mutex.Unlock() 55 return res 56 } 57 58 // Signal triggers the signaler 59 func (s *signaler) Signal() { 60 s.mutex.Lock() 61 if s.triggered { 62 s.mutex.Unlock() 63 return 64 } 65 cb := s.callbacks 66 s.triggered = true 67 for _, s := range s.signals { 68 s <- struct{}{} 69 } 70 s.mutex.Unlock() 71 // callbacks must be invoked without holding the lock since they might Unregister() 72 for _, f := range cb { 73 f() 74 } 75 } 76 77 // Triggered check if the signaler was triggered 78 func (s *signaler) Triggered() bool { 79 return s.triggered 80 }