make sure Abort is holding untill inner goroutine finishes
Vladimir Bauer
4 years ago
| 267 | 267 | // if bar is already in complete state. If drop is true bar will be |
| 268 | 268 | // removed as well. |
| 269 | 269 | func (b *Bar) Abort(drop bool) { |
| 270 | done := make(chan struct{}) | |
| 270 | 271 | select { |
| 271 | 272 | case b.operateState <- func(s *bState) { |
| 272 | 273 | if s.completed == true { |
| 274 | close(done) | |
| 273 | 275 | return |
| 274 | 276 | } |
| 275 | if drop { | |
| 276 | go b.container.dropBar(b) | |
| 277 | } else { | |
| 278 | go func() { | |
| 277 | // container must be run during lifetime of this inner goroutine | |
| 278 | // we control this by done channel declared above | |
| 279 | go func() { | |
| 280 | if drop { | |
| 281 | b.container.dropBar(b) | |
| 282 | } else { | |
| 279 | 283 | var uncompleted int |
| 280 | 284 | b.container.traverseBars(func(bar *Bar) bool { |
| 281 | 285 | if b != bar && !bar.Completed() { |
| 285 | 289 | return true |
| 286 | 290 | }) |
| 287 | 291 | if uncompleted == 0 { |
| 288 | select { | |
| 289 | case b.container.refreshCh <- time.Now(): | |
| 290 | case <-b.container.done: | |
| 291 | } | |
| 292 | b.container.refreshCh <- time.Now() | |
| 292 | 293 | } |
| 293 | }() | |
| 294 | } | |
| 294 | } | |
| 295 | close(done) // release hold of Abort | |
| 296 | }() | |
| 295 | 297 | b.cancel() |
| 296 | 298 | }: |
| 297 | <-b.done | |
| 299 | // guarantee: container is alive during lifetime of this hold | |
| 300 | <-done | |
| 298 | 301 | case <-b.done: |
| 299 | 302 | } |
| 300 | 303 | } |