mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	add cancellation code to util, like context but just the cancellation parts + some error logic
This commit is contained in:
		
							parent
							
								
									c36da7b814
								
							
						
					
					
						commit
						06e8403aaf
					
				
					 1 changed files with 83 additions and 0 deletions
				
			
		
							
								
								
									
										83
									
								
								src/util/cancellation.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/util/cancellation.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,83 @@
 | 
				
			||||||
 | 
					package util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
					  "errors"
 | 
				
			||||||
 | 
					  "sync"
 | 
				
			||||||
 | 
					  "time"
 | 
				
			||||||
 | 
					  "runtime"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Cancellation interface {
 | 
				
			||||||
 | 
					  Finished() <-chan struct{}
 | 
				
			||||||
 | 
					  Cancel(error) error
 | 
				
			||||||
 | 
					  Error() error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func CancellationFinalizer(c Cancellation) {
 | 
				
			||||||
 | 
					  c.Cancel(errors.New("finalizer called"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type cancellation struct {
 | 
				
			||||||
 | 
					  signal chan error
 | 
				
			||||||
 | 
					  cancel chan struct{}
 | 
				
			||||||
 | 
					  errMtx sync.RWMutex
 | 
				
			||||||
 | 
					  err error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *cancellation) worker() {
 | 
				
			||||||
 | 
					    // Launch this in a separate goroutine when creating a cancellation
 | 
				
			||||||
 | 
					    err := <-c.signal
 | 
				
			||||||
 | 
					    c.errMtx.Lock()
 | 
				
			||||||
 | 
					    c.err = err
 | 
				
			||||||
 | 
					    c.errMtx.Unlock()
 | 
				
			||||||
 | 
					    close(c.cancel)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewCancellation() Cancellation {
 | 
				
			||||||
 | 
					  c := cancellation{
 | 
				
			||||||
 | 
					    signal: make(chan error),
 | 
				
			||||||
 | 
					    cancel: make(chan struct{}),
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  runtime.SetFinalizer(&c, CancellationFinalizer)
 | 
				
			||||||
 | 
					  go c.worker()
 | 
				
			||||||
 | 
					  return &c
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *cancellation) Finished() <-chan struct{} {
 | 
				
			||||||
 | 
					  return c.cancel
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *cancellation) Cancel(err error) error {
 | 
				
			||||||
 | 
					  select {
 | 
				
			||||||
 | 
					  case c.signal<-err:
 | 
				
			||||||
 | 
					    return nil
 | 
				
			||||||
 | 
					  case <-c.cancel:
 | 
				
			||||||
 | 
					    return c.Error()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *cancellation) Error() error {
 | 
				
			||||||
 | 
					  c.errMtx.RLock()
 | 
				
			||||||
 | 
					  err := c.err
 | 
				
			||||||
 | 
					  c.errMtx.RUnlock()
 | 
				
			||||||
 | 
					  return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func CancellationWithTimeout(parent Cancellation, timeout time.Duration) Cancellation {
 | 
				
			||||||
 | 
					  child := NewCancellation()
 | 
				
			||||||
 | 
					  go func() {
 | 
				
			||||||
 | 
					    timer := time.NewTimer(timeout)
 | 
				
			||||||
 | 
					    defer TimerStop(timer)
 | 
				
			||||||
 | 
					    select {
 | 
				
			||||||
 | 
					    case <-parent.Finished():
 | 
				
			||||||
 | 
					      child.Cancel(parent.Error())
 | 
				
			||||||
 | 
					    case <-timer.C:
 | 
				
			||||||
 | 
					      child.Cancel(errors.New("timeout"))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }()
 | 
				
			||||||
 | 
					  return child
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func CancellationWithDeadline(parent Cancellation, deadline time.Time) Cancellation {
 | 
				
			||||||
 | 
					  return CancellationWithTimeout(parent, deadline.Sub(time.Now()))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue