Utilize quit ch only, shutdown with sync once
Vladimir Bauer
8 years ago
| 30 | 30 | type Bar struct { |
| 31 | 31 | priority int |
| 32 | 32 | index int |
| 33 | // quit channel to request b.server to quit | |
| 34 | quit chan struct{} | |
| 35 | // done channel is receiveable after b.server has been quit | |
| 36 | done chan struct{} | |
| 33 | ||
| 37 | 34 | operateState chan func(*bState) |
| 35 | quit chan struct{} | |
| 36 | once sync.Once | |
| 38 | 37 | |
| 39 | 38 | // cacheState is used after b.done is receiveable |
| 40 | 39 | cacheState *bState |
| 41 | ||
| 42 | once sync.Once | |
| 43 | 40 | } |
| 44 | 41 | |
| 45 | 42 | type ( |
| 98 | 95 | |
| 99 | 96 | b := &Bar{ |
| 100 | 97 | priority: id, |
| 98 | operateState: make(chan func(*bState)), | |
| 101 | 99 | quit: make(chan struct{}), |
| 102 | done: make(chan struct{}), | |
| 103 | operateState: make(chan func(*bState)), | |
| 104 | 100 | } |
| 105 | 101 | |
| 106 | 102 | go b.serve(s, wg, cancel) |
| 193 | 189 | select { |
| 194 | 190 | case b.operateState <- func(s *bState) { result <- len(s.appendFuncs) }: |
| 195 | 191 | return <-result |
| 196 | case <-b.done: | |
| 192 | case <-b.quit: | |
| 197 | 193 | return len(b.cacheState.appendFuncs) |
| 198 | 194 | } |
| 199 | 195 | } |
| 204 | 200 | select { |
| 205 | 201 | case b.operateState <- func(s *bState) { result <- len(s.prependFuncs) }: |
| 206 | 202 | return <-result |
| 207 | case <-b.done: | |
| 203 | case <-b.quit: | |
| 208 | 204 | return len(b.cacheState.prependFuncs) |
| 209 | 205 | } |
| 210 | 206 | } |
| 215 | 211 | select { |
| 216 | 212 | case b.operateState <- func(s *bState) { result <- s.id }: |
| 217 | 213 | return <-result |
| 218 | case <-b.done: | |
| 214 | case <-b.quit: | |
| 219 | 215 | return b.cacheState.id |
| 220 | 216 | } |
| 221 | 217 | } |
| 226 | 222 | select { |
| 227 | 223 | case b.operateState <- func(s *bState) { result <- s.current }: |
| 228 | 224 | return <-result |
| 229 | case <-b.done: | |
| 225 | case <-b.quit: | |
| 230 | 226 | return b.cacheState.current |
| 231 | 227 | } |
| 232 | 228 | } |
| 237 | 233 | select { |
| 238 | 234 | case b.operateState <- func(s *bState) { result <- s.total }: |
| 239 | 235 | return <-result |
| 240 | case <-b.done: | |
| 236 | case <-b.quit: | |
| 241 | 237 | return b.cacheState.total |
| 242 | 238 | } |
| 243 | 239 | } |
| 274 | 270 | } |
| 275 | 271 | |
| 276 | 272 | func (b *Bar) shutdown() { |
| 277 | close(b.quit) | |
| 273 | b.quit <- struct{}{} | |
| 274 | <-b.quit | |
| 278 | 275 | } |
| 279 | 276 | |
| 280 | 277 | func (b *Bar) serve(s *bState, wg *sync.WaitGroup, cancel <-chan struct{}) { |
| 281 | defer func() { | |
| 282 | b.cacheState = s | |
| 283 | close(b.done) | |
| 284 | wg.Done() | |
| 285 | }() | |
| 278 | defer wg.Done() | |
| 286 | 279 | |
| 287 | 280 | for { |
| 288 | 281 | select { |
| 291 | 284 | case <-cancel: |
| 292 | 285 | s.aborted = true |
| 293 | 286 | cancel = nil |
| 294 | b.Complete() | |
| 287 | go b.Complete() | |
| 295 | 288 | case <-b.quit: |
| 289 | b.cacheState = s | |
| 290 | close(b.quit) | |
| 296 | 291 | return |
| 297 | 292 | } |
| 298 | 293 | } |
| 318 | 313 | s.draw(tw, prependWs, appendWs) |
| 319 | 314 | ch <- &bufReader{io.MultiReader(s.bufP, s.bufB, s.bufA), s.completed} |
| 320 | 315 | }: |
| 321 | case <-b.done: | |
| 316 | case <-b.quit: | |
| 322 | 317 | s := b.cacheState |
| 323 | 318 | var r io.Reader |
| 324 | 319 | if s.panic != "" { |
| 25 | 25 | // External wg |
| 26 | 26 | ewg *sync.WaitGroup |
| 27 | 27 | |
| 28 | // quit channel to request p.server to quit | |
| 29 | quit chan struct{} | |
| 30 | // done channel is receiveable after p.server has been quit | |
| 31 | done chan struct{} | |
| 32 | 28 | operateState chan func(*pState) |
| 29 | quit chan struct{} | |
| 30 | once sync.Once | |
| 33 | 31 | } |
| 34 | 32 | |
| 35 | 33 | type ( |
| 81 | 79 | p := &Progress{ |
| 82 | 80 | ewg: s.ewg, |
| 83 | 81 | wg: new(sync.WaitGroup), |
| 84 | done: make(chan struct{}), | |
| 85 | 82 | operateState: make(chan func(*pState)), |
| 86 | 83 | quit: make(chan struct{}), |
| 87 | 84 | } |
| 159 | 156 | if p.ewg != nil { |
| 160 | 157 | p.ewg.Wait() |
| 161 | 158 | } |
| 162 | select { | |
| 163 | case <-p.quit: | |
| 164 | return | |
| 165 | default: | |
| 166 | // wait for all bars to quit | |
| 167 | p.wg.Wait() | |
| 168 | // request p.server to quit | |
| 169 | p.quitRequest() | |
| 170 | // wait for p.server to quit | |
| 171 | <-p.done | |
| 172 | } | |
| 173 | } | |
| 174 | ||
| 175 | func (p *Progress) quitRequest() { | |
| 176 | select { | |
| 177 | case <-p.quit: | |
| 178 | default: | |
| 179 | close(p.quit) | |
| 180 | } | |
| 159 | // wait for all bars to quit | |
| 160 | p.wg.Wait() | |
| 161 | p.once.Do(p.shutdown) | |
| 162 | } | |
| 163 | ||
| 164 | func (p *Progress) shutdown() { | |
| 165 | p.quit <- struct{}{} | |
| 166 | <-p.quit | |
| 181 | 167 | } |
| 182 | 168 | |
| 183 | 169 | func newWidthSync(timeout <-chan struct{}, numBars, numColumn int) *widthSync { |
| 15 | 15 | func (p *Progress) serve(s *pState) { |
| 16 | 16 | winch := make(chan os.Signal, 1) |
| 17 | 17 | signal.Notify(winch, syscall.SIGWINCH) |
| 18 | ||
| 19 | defer func() { | |
| 20 | if s.shutdownNotifier != nil { | |
| 21 | close(s.shutdownNotifier) | |
| 22 | } | |
| 23 | signal.Stop(winch) | |
| 24 | close(p.done) | |
| 25 | }() | |
| 26 | 18 | |
| 27 | 19 | var numP, numA int |
| 28 | 20 | var timer *time.Timer |
| 66 | 58 | case <-s.cancel: |
| 67 | 59 | s.ticker.Stop() |
| 68 | 60 | s.cancel = nil |
| 61 | // don't return here, p.Stop() must be called eventually | |
| 69 | 62 | case <-p.quit: |
| 70 | 63 | if s.cancel != nil { |
| 71 | 64 | s.ticker.Stop() |
| 72 | 65 | } |
| 66 | if s.shutdownNotifier != nil { | |
| 67 | close(s.shutdownNotifier) | |
| 68 | } | |
| 69 | signal.Stop(winch) | |
| 70 | close(p.quit) | |
| 73 | 71 | return |
| 74 | 72 | } |
| 75 | 73 | } |
| 10 | 10 | ) |
| 11 | 11 | |
| 12 | 12 | func (p *Progress) serve(s *pState) { |
| 13 | defer func() { | |
| 14 | if s.shutdownNotifier != nil { | |
| 15 | close(s.shutdownNotifier) | |
| 16 | } | |
| 17 | close(p.done) | |
| 18 | }() | |
| 19 | 13 | |
| 20 | 14 | var numP, numA int |
| 21 | 15 | |
| 41 | 35 | case <-s.cancel: |
| 42 | 36 | s.ticker.Stop() |
| 43 | 37 | s.cancel = nil |
| 38 | // don't return here, p.Stop() must be called eventually | |
| 44 | 39 | case <-p.quit: |
| 45 | 40 | if s.cancel != nil { |
| 46 | 41 | s.ticker.Stop() |
| 47 | 42 | } |
| 43 | if s.shutdownNotifier != nil { | |
| 44 | close(s.shutdownNotifier) | |
| 45 | } | |
| 46 | close(p.quit) | |
| 48 | 47 | return |
| 49 | 48 | } |
| 50 | 49 | } |