context.go raw

   1  // Copyright 2018 The gVisor Authors.
   2  //
   3  // Licensed under the Apache License, Version 2.0 (the "License");
   4  // you may not use this file except in compliance with the License.
   5  // You may obtain a copy of the License at
   6  //
   7  //     http://www.apache.org/licenses/LICENSE-2.0
   8  //
   9  // Unless required by applicable law or agreed to in writing, software
  10  // distributed under the License is distributed on an "AS IS" BASIS,
  11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12  // See the License for the specific language governing permissions and
  13  // limitations under the License.
  14  
  15  // Package context defines an internal context type.
  16  //
  17  // The given Context conforms to the standard Go context, but mandates
  18  // additional methods that are specific to the kernel internals. Note however,
  19  // that the Context described by this package carries additional constraints
  20  // regarding concurrent access and retaining beyond the scope of a call.
  21  //
  22  // See the Context type for complete details.
  23  package context
  24  
  25  import (
  26  	"context"
  27  	"errors"
  28  	"sync"
  29  	"time"
  30  
  31  	"gvisor.dev/gvisor/pkg/log"
  32  	"gvisor.dev/gvisor/pkg/waiter"
  33  )
  34  
  35  // Blocker represents an object with control flow hooks.
  36  //
  37  // These may be used to perform blocking operations, sleep or otherwise
  38  // wait, since there may be asynchronous events that require processing.
  39  type Blocker interface {
  40  	// Interrupt interrupts any Block operations.
  41  	Interrupt()
  42  
  43  	// Interrupted notes whether this context is Interrupted.
  44  	Interrupted() bool
  45  
  46  	// BlockOn blocks until one of the previously registered events occurs,
  47  	// or some external interrupt (cancellation).
  48  	//
  49  	// The return value should indicate whether the wake-up occurred as a
  50  	// result of the requested event (versus an external interrupt).
  51  	BlockOn(waiter.Waitable, waiter.EventMask) bool
  52  
  53  	// Block blocks until an event is received from C, or some external
  54  	// interrupt. It returns nil if an event is received from C and an err if t
  55  	// is interrupted.
  56  	Block(C <-chan struct{}) error
  57  
  58  	// BlockWithTimeoutOn blocks until either the conditions of Block are
  59  	// satisfied, or the timeout is hit. Note that deadlines are not supported
  60  	// since the notion of "with respect to what clock" is not resolved.
  61  	//
  62  	// The return value is per BlockOn.
  63  	BlockWithTimeoutOn(waiter.Waitable, waiter.EventMask, time.Duration) (time.Duration, bool)
  64  
  65  	// UninterruptibleSleepStart indicates the beginning of an uninterruptible
  66  	// sleep state (equivalent to Linux's TASK_UNINTERRUPTIBLE). If deactivate
  67  	// is true and the Context represents a Task, the Task's AddressSpace is
  68  	// deactivated.
  69  	UninterruptibleSleepStart(deactivate bool)
  70  
  71  	// UninterruptibleSleepFinish indicates the end of an uninterruptible sleep
  72  	// state that was begun by a previous call to UninterruptibleSleepStart. If
  73  	// activate is true and the Context represents a Task, the Task's
  74  	// AddressSpace is activated. Normally activate is the same value as the
  75  	// deactivate parameter passed to UninterruptibleSleepStart.
  76  	UninterruptibleSleepFinish(activate bool)
  77  }
  78  
  79  // NoTask is an implementation of Blocker that does not block.
  80  type NoTask struct {
  81  	cancel chan struct{}
  82  }
  83  
  84  // Interrupt implements Blocker.Interrupt.
  85  func (nt *NoTask) Interrupt() {
  86  	select {
  87  	case nt.cancel <- struct{}{}:
  88  	default:
  89  	}
  90  }
  91  
  92  // Interrupted implements Blocker.Interrupted.
  93  func (nt *NoTask) Interrupted() bool {
  94  	return nt.cancel != nil && len(nt.cancel) > 0
  95  }
  96  
  97  // Block implements Blocker.Block.
  98  func (nt *NoTask) Block(C <-chan struct{}) error {
  99  	if nt.cancel == nil {
 100  		nt.cancel = make(chan struct{}, 1)
 101  	}
 102  	select {
 103  	case <-nt.cancel:
 104  		return errors.New("interrupted system call") // Interrupted.
 105  	case <-C:
 106  		return nil
 107  	}
 108  }
 109  
 110  // BlockOn implements Blocker.BlockOn.
 111  func (nt *NoTask) BlockOn(w waiter.Waitable, mask waiter.EventMask) bool {
 112  	if nt.cancel == nil {
 113  		nt.cancel = make(chan struct{}, 1)
 114  	}
 115  	e, ch := waiter.NewChannelEntry(mask)
 116  	w.EventRegister(&e)
 117  	defer w.EventUnregister(&e)
 118  	select {
 119  	case <-nt.cancel:
 120  		return false // Interrupted.
 121  	case _, ok := <-ch:
 122  		return ok
 123  	}
 124  }
 125  
 126  // BlockWithTimeoutOn implements Blocker.BlockWithTimeoutOn.
 127  func (nt *NoTask) BlockWithTimeoutOn(w waiter.Waitable, mask waiter.EventMask, duration time.Duration) (time.Duration, bool) {
 128  	if nt.cancel == nil {
 129  		nt.cancel = make(chan struct{}, 1)
 130  	}
 131  	e, ch := waiter.NewChannelEntry(mask)
 132  	w.EventRegister(&e)
 133  	defer w.EventUnregister(&e)
 134  	start := time.Now() // In system time.
 135  	t := time.AfterFunc(duration, func() { ch <- struct{}{} })
 136  	select {
 137  	case <-nt.cancel:
 138  		return time.Since(start), false // Interrupted.
 139  	case _, ok := <-ch:
 140  		if ok && t.Stop() {
 141  			// Timer never fired.
 142  			return time.Since(start), ok
 143  		}
 144  		// Timer fired, remain is zero.
 145  		return time.Duration(0), ok
 146  	}
 147  }
 148  
 149  // UninterruptibleSleepStart implmenents Blocker.UninterruptedSleepStart.
 150  func (*NoTask) UninterruptibleSleepStart(bool) {}
 151  
 152  // UninterruptibleSleepFinish implmenents Blocker.UninterruptibleSleepFinish.
 153  func (*NoTask) UninterruptibleSleepFinish(bool) {}
 154  
 155  // Context represents a thread of execution (hereafter "goroutine" to reflect
 156  // Go idiosyncrasy). It carries state associated with the goroutine across API
 157  // boundaries.
 158  //
 159  // While Context exists for essentially the same reasons as Go's standard
 160  // context.Context, the standard type represents the state of an operation
 161  // rather than that of a goroutine. This is a critical distinction:
 162  //
 163  //   - Unlike context.Context, which "may be passed to functions running in
 164  //     different goroutines", it is *not safe* to use the same Context in multiple
 165  //     concurrent goroutines.
 166  //
 167  //   - It is *not safe* to retain a Context passed to a function beyond the scope
 168  //     of that function call.
 169  //
 170  // In both cases, values extracted from the Context should be used instead.
 171  type Context interface {
 172  	context.Context
 173  	log.Logger
 174  	Blocker
 175  }
 176  
 177  // logContext implements basic logging.
 178  type logContext struct {
 179  	NoTask
 180  	log.Logger
 181  	context.Context
 182  }
 183  
 184  // bgContext is the context returned by context.Background.
 185  var bgContext Context
 186  var bgOnce sync.Once
 187  
 188  // Background returns an empty context using the default logger.
 189  // Generally, one should use the Task as their context when available, or avoid
 190  // having to use a context in places where a Task is unavailable.
 191  //
 192  // Using a Background context for tests is fine, as long as no values are
 193  // needed from the context in the tested code paths.
 194  //
 195  // The global log.SetTarget() must be called before context.Background()
 196  func Background() Context {
 197  	bgOnce.Do(func() {
 198  		bgContext = &logContext{
 199  			Context: context.Background(),
 200  			Logger:  log.Log(),
 201  		}
 202  	})
 203  	return bgContext
 204  }
 205  
 206  // WithValue returns a copy of parent in which the value associated with key is
 207  // val.
 208  func WithValue(parent Context, key, val any) Context {
 209  	return &withValue{
 210  		Context: parent,
 211  		key:     key,
 212  		val:     val,
 213  	}
 214  }
 215  
 216  type withValue struct {
 217  	Context
 218  	key any
 219  	val any
 220  }
 221  
 222  // Value implements Context.Value.
 223  func (ctx *withValue) Value(key any) any {
 224  	if key == ctx.key {
 225  		return ctx.val
 226  	}
 227  	return ctx.Context.Value(key)
 228  }
 229