gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/net/context/pre_go17.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build !go1.7
     6  // +build !go1.7
     7  
     8  package context
     9  
    10  import (
    11  	"errors"
    12  	"fmt"
    13  	"sync"
    14  	"time"
    15  )
    16  
    17  // An emptyCtx is never canceled, has no values, and has no deadline. It is not
    18  // struct{}, since vars of this type must have distinct addresses.
    19  type emptyCtx int
    20  
    21  func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
    22  	return
    23  }
    24  
    25  func (*emptyCtx) Done() <-chan struct{} {
    26  	return nil
    27  }
    28  
    29  func (*emptyCtx) Err() error {
    30  	return nil
    31  }
    32  
    33  func (*emptyCtx) Value(key interface{}) interface{} {
    34  	return nil
    35  }
    36  
    37  func (e *emptyCtx) String() string {
    38  	switch e {
    39  	case background:
    40  		return "context.Background"
    41  	case todo:
    42  		return "context.TODO"
    43  	}
    44  	return "unknown empty Context"
    45  }
    46  
    47  var (
    48  	background = new(emptyCtx)
    49  	todo       = new(emptyCtx)
    50  )
    51  
    52  // Canceled is the error returned by Context.Err when the context is canceled.
    53  var Canceled = errors.New("context canceled")
    54  
    55  // DeadlineExceeded is the error returned by Context.Err when the context's
    56  // deadline passes.
    57  var DeadlineExceeded = errors.New("context deadline exceeded")
    58  
    59  // WithCancel returns a copy of parent with a new Done channel. The returned
    60  // context's Done channel is closed when the returned cancel function is called
    61  // or when the parent context's Done channel is closed, whichever happens first.
    62  //
    63  // Canceling this context releases resources associated with it, so code should
    64  // call cancel as soon as the operations running in this Context complete.
    65  func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
    66  	c := newCancelCtx(parent)
    67  	propagateCancel(parent, c)
    68  	return c, func() { c.cancel(true, Canceled) }
    69  }
    70  
    71  // newCancelCtx returns an initialized cancelCtx.
    72  func newCancelCtx(parent Context) *cancelCtx {
    73  	return &cancelCtx{
    74  		Context: parent,
    75  		done:    make(chan struct{}),
    76  	}
    77  }
    78  
    79  // propagateCancel arranges for child to be canceled when parent is.
    80  func propagateCancel(parent Context, child canceler) {
    81  	if parent.Done() == nil {
    82  		return // parent is never canceled
    83  	}
    84  	if p, ok := parentCancelCtx(parent); ok {
    85  		p.mu.Lock()
    86  		if p.err != nil {
    87  			// parent has already been canceled
    88  			child.cancel(false, p.err)
    89  		} else {
    90  			if p.children == nil {
    91  				p.children = make(map[canceler]bool)
    92  			}
    93  			p.children[child] = true
    94  		}
    95  		p.mu.Unlock()
    96  	} else {
    97  		go func() {
    98  			select {
    99  			case <-parent.Done():
   100  				child.cancel(false, parent.Err())
   101  			case <-child.Done():
   102  			}
   103  		}()
   104  	}
   105  }
   106  
   107  // parentCancelCtx follows a chain of parent references until it finds a
   108  // *cancelCtx. This function understands how each of the concrete types in this
   109  // package represents its parent.
   110  func parentCancelCtx(parent Context) (*cancelCtx, bool) {
   111  	for {
   112  		switch c := parent.(type) {
   113  		case *cancelCtx:
   114  			return c, true
   115  		case *timerCtx:
   116  			return c.cancelCtx, true
   117  		case *valueCtx:
   118  			parent = c.Context
   119  		default:
   120  			return nil, false
   121  		}
   122  	}
   123  }
   124  
   125  // removeChild removes a context from its parent.
   126  func removeChild(parent Context, child canceler) {
   127  	p, ok := parentCancelCtx(parent)
   128  	if !ok {
   129  		return
   130  	}
   131  	p.mu.Lock()
   132  	if p.children != nil {
   133  		delete(p.children, child)
   134  	}
   135  	p.mu.Unlock()
   136  }
   137  
   138  // A canceler is a context type that can be canceled directly. The
   139  // implementations are *cancelCtx and *timerCtx.
   140  type canceler interface {
   141  	cancel(removeFromParent bool, err error)
   142  	Done() <-chan struct{}
   143  }
   144  
   145  // A cancelCtx can be canceled. When canceled, it also cancels any children
   146  // that implement canceler.
   147  type cancelCtx struct {
   148  	Context
   149  
   150  	done chan struct{} // closed by the first cancel call.
   151  
   152  	mu       sync.Mutex
   153  	children map[canceler]bool // set to nil by the first cancel call
   154  	err      error             // set to non-nil by the first cancel call
   155  }
   156  
   157  func (c *cancelCtx) Done() <-chan struct{} {
   158  	return c.done
   159  }
   160  
   161  func (c *cancelCtx) Err() error {
   162  	c.mu.Lock()
   163  	defer c.mu.Unlock()
   164  	return c.err
   165  }
   166  
   167  func (c *cancelCtx) String() string {
   168  	return fmt.Sprintf("%v.WithCancel", c.Context)
   169  }
   170  
   171  // cancel closes c.done, cancels each of c's children, and, if
   172  // removeFromParent is true, removes c from its parent's children.
   173  func (c *cancelCtx) cancel(removeFromParent bool, err error) {
   174  	if err == nil {
   175  		panic("context: internal error: missing cancel error")
   176  	}
   177  	c.mu.Lock()
   178  	if c.err != nil {
   179  		c.mu.Unlock()
   180  		return // already canceled
   181  	}
   182  	c.err = err
   183  	close(c.done)
   184  	for child := range c.children {
   185  		// NOTE: acquiring the child's lock while holding parent's lock.
   186  		child.cancel(false, err)
   187  	}
   188  	c.children = nil
   189  	c.mu.Unlock()
   190  
   191  	if removeFromParent {
   192  		removeChild(c.Context, c)
   193  	}
   194  }
   195  
   196  // WithDeadline returns a copy of the parent context with the deadline adjusted
   197  // to be no later than d. If the parent's deadline is already earlier than d,
   198  // WithDeadline(parent, d) is semantically equivalent to parent. The returned
   199  // context's Done channel is closed when the deadline expires, when the returned
   200  // cancel function is called, or when the parent context's Done channel is
   201  // closed, whichever happens first.
   202  //
   203  // Canceling this context releases resources associated with it, so code should
   204  // call cancel as soon as the operations running in this Context complete.
   205  func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
   206  	if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
   207  		// The current deadline is already sooner than the new one.
   208  		return WithCancel(parent)
   209  	}
   210  	c := &timerCtx{
   211  		cancelCtx: newCancelCtx(parent),
   212  		deadline:  deadline,
   213  	}
   214  	propagateCancel(parent, c)
   215  	d := deadline.Sub(time.Now())
   216  	if d <= 0 {
   217  		c.cancel(true, DeadlineExceeded) // deadline has already passed
   218  		return c, func() { c.cancel(true, Canceled) }
   219  	}
   220  	c.mu.Lock()
   221  	defer c.mu.Unlock()
   222  	if c.err == nil {
   223  		c.timer = time.AfterFunc(d, func() {
   224  			c.cancel(true, DeadlineExceeded)
   225  		})
   226  	}
   227  	return c, func() { c.cancel(true, Canceled) }
   228  }
   229  
   230  // A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
   231  // implement Done and Err. It implements cancel by stopping its timer then
   232  // delegating to cancelCtx.cancel.
   233  type timerCtx struct {
   234  	*cancelCtx
   235  	timer *time.Timer // Under cancelCtx.mu.
   236  
   237  	deadline time.Time
   238  }
   239  
   240  func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
   241  	return c.deadline, true
   242  }
   243  
   244  func (c *timerCtx) String() string {
   245  	return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now()))
   246  }
   247  
   248  func (c *timerCtx) cancel(removeFromParent bool, err error) {
   249  	c.cancelCtx.cancel(false, err)
   250  	if removeFromParent {
   251  		// Remove this timerCtx from its parent cancelCtx's children.
   252  		removeChild(c.cancelCtx.Context, c)
   253  	}
   254  	c.mu.Lock()
   255  	if c.timer != nil {
   256  		c.timer.Stop()
   257  		c.timer = nil
   258  	}
   259  	c.mu.Unlock()
   260  }
   261  
   262  // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
   263  //
   264  // Canceling this context releases resources associated with it, so code should
   265  // call cancel as soon as the operations running in this Context complete:
   266  //
   267  // 	func slowOperationWithTimeout(ctx context.Context) (Result, error) {
   268  // 		ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
   269  // 		defer cancel()  // releases resources if slowOperation completes before timeout elapses
   270  // 		return slowOperation(ctx)
   271  // 	}
   272  func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
   273  	return WithDeadline(parent, time.Now().Add(timeout))
   274  }
   275  
   276  // WithValue returns a copy of parent in which the value associated with key is
   277  // val.
   278  //
   279  // Use context Values only for request-scoped data that transits processes and
   280  // APIs, not for passing optional parameters to functions.
   281  func WithValue(parent Context, key interface{}, val interface{}) Context {
   282  	return &valueCtx{parent, key, val}
   283  }
   284  
   285  // A valueCtx carries a key-value pair. It implements Value for that key and
   286  // delegates all other calls to the embedded Context.
   287  type valueCtx struct {
   288  	Context
   289  	key, val interface{}
   290  }
   291  
   292  func (c *valueCtx) String() string {
   293  	return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
   294  }
   295  
   296  func (c *valueCtx) Value(key interface{}) interface{} {
   297  	if c.key == key {
   298  		return c.val
   299  	}
   300  	return c.Context.Value(key)
   301  }