github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/context/context.go (about)

     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  	"time"
    28  
    29  	"github.com/SagerNet/gvisor/pkg/log"
    30  )
    31  
    32  type contextID int
    33  
    34  // Globally accessible values from a context. These keys are defined in the
    35  // context package to resolve dependency cycles by not requiring the caller to
    36  // import packages usually required to get these information.
    37  const (
    38  	// CtxThreadGroupID is the current thread group ID when a context represents
    39  	// a task context. The value is represented as an int32.
    40  	CtxThreadGroupID contextID = iota
    41  )
    42  
    43  // ThreadGroupIDFromContext returns the current thread group ID when ctx
    44  // represents a task context.
    45  func ThreadGroupIDFromContext(ctx Context) (tgid int32, ok bool) {
    46  	if tgid := ctx.Value(CtxThreadGroupID); tgid != nil {
    47  		return tgid.(int32), true
    48  	}
    49  	return 0, false
    50  }
    51  
    52  // A Context represents a thread of execution (hereafter "goroutine" to reflect
    53  // Go idiosyncrasy). It carries state associated with the goroutine across API
    54  // boundaries.
    55  //
    56  // While Context exists for essentially the same reasons as Go's standard
    57  // context.Context, the standard type represents the state of an operation
    58  // rather than that of a goroutine. This is a critical distinction:
    59  //
    60  // - Unlike context.Context, which "may be passed to functions running in
    61  // different goroutines", it is *not safe* to use the same Context in multiple
    62  // concurrent goroutines.
    63  //
    64  // - It is *not safe* to retain a Context passed to a function beyond the scope
    65  // of that function call.
    66  //
    67  // In both cases, values extracted from the Context should be used instead.
    68  type Context interface {
    69  	log.Logger
    70  	context.Context
    71  
    72  	ChannelSleeper
    73  
    74  	// UninterruptibleSleepStart indicates the beginning of an uninterruptible
    75  	// sleep state (equivalent to Linux's TASK_UNINTERRUPTIBLE). If deactivate
    76  	// is true and the Context represents a Task, the Task's AddressSpace is
    77  	// deactivated.
    78  	UninterruptibleSleepStart(deactivate bool)
    79  
    80  	// UninterruptibleSleepFinish indicates the end of an uninterruptible sleep
    81  	// state that was begun by a previous call to UninterruptibleSleepStart. If
    82  	// activate is true and the Context represents a Task, the Task's
    83  	// AddressSpace is activated. Normally activate is the same value as the
    84  	// deactivate parameter passed to UninterruptibleSleepStart.
    85  	UninterruptibleSleepFinish(activate bool)
    86  }
    87  
    88  // A ChannelSleeper represents a goroutine that may sleep interruptibly, where
    89  // interruption is indicated by a channel becoming readable.
    90  type ChannelSleeper interface {
    91  	// SleepStart is called before going to sleep interruptibly. If SleepStart
    92  	// returns a non-nil channel and that channel becomes ready for receiving
    93  	// while the goroutine is sleeping, the goroutine should be woken, and
    94  	// SleepFinish(false) should be called. Otherwise, SleepFinish(true) should
    95  	// be called after the goroutine stops sleeping.
    96  	SleepStart() <-chan struct{}
    97  
    98  	// SleepFinish is called after an interruptibly-sleeping goroutine stops
    99  	// sleeping, as documented by SleepStart.
   100  	SleepFinish(success bool)
   101  
   102  	// Interrupted returns true if the channel returned by SleepStart is
   103  	// ready for receiving.
   104  	Interrupted() bool
   105  }
   106  
   107  // NoopSleeper is a noop implementation of ChannelSleeper and
   108  // Context.UninterruptibleSleep* methods for anonymous embedding in other types
   109  // that do not implement special behavior around sleeps.
   110  type NoopSleeper struct{}
   111  
   112  // SleepStart implements ChannelSleeper.SleepStart.
   113  func (NoopSleeper) SleepStart() <-chan struct{} {
   114  	return nil
   115  }
   116  
   117  // SleepFinish implements ChannelSleeper.SleepFinish.
   118  func (NoopSleeper) SleepFinish(success bool) {}
   119  
   120  // Interrupted implements ChannelSleeper.Interrupted.
   121  func (NoopSleeper) Interrupted() bool {
   122  	return false
   123  }
   124  
   125  // UninterruptibleSleepStart implements Context.UninterruptibleSleepStart.
   126  func (NoopSleeper) UninterruptibleSleepStart(deactivate bool) {}
   127  
   128  // UninterruptibleSleepFinish implements Context.UninterruptibleSleepFinish.
   129  func (NoopSleeper) UninterruptibleSleepFinish(activate bool) {}
   130  
   131  // Deadline implements context.Context.Deadline.
   132  func (NoopSleeper) Deadline() (time.Time, bool) {
   133  	return time.Time{}, false
   134  }
   135  
   136  // Done implements context.Context.Done.
   137  func (NoopSleeper) Done() <-chan struct{} {
   138  	return nil
   139  }
   140  
   141  // Err returns context.Context.Err.
   142  func (NoopSleeper) Err() error {
   143  	return nil
   144  }
   145  
   146  // logContext implements basic logging.
   147  type logContext struct {
   148  	log.Logger
   149  	NoopSleeper
   150  }
   151  
   152  // Value implements Context.Value.
   153  func (logContext) Value(key interface{}) interface{} {
   154  	return nil
   155  }
   156  
   157  // bgContext is the context returned by context.Background.
   158  var bgContext = &logContext{Logger: log.Log()}
   159  
   160  // Background returns an empty context using the default logger.
   161  // Generally, one should use the Task as their context when available, or avoid
   162  // having to use a context in places where a Task is unavailable.
   163  //
   164  // Using a Background context for tests is fine, as long as no values are
   165  // needed from the context in the tested code paths.
   166  func Background() Context {
   167  	return bgContext
   168  }
   169  
   170  // WithValue returns a copy of parent in which the value associated with key is
   171  // val.
   172  func WithValue(parent Context, key, val interface{}) Context {
   173  	return &withValue{
   174  		Context: parent,
   175  		key:     key,
   176  		val:     val,
   177  	}
   178  }
   179  
   180  type withValue struct {
   181  	Context
   182  	key interface{}
   183  	val interface{}
   184  }
   185  
   186  // Value implements Context.Value.
   187  func (ctx *withValue) Value(key interface{}) interface{} {
   188  	if key == ctx.key {
   189  		return ctx.val
   190  	}
   191  	return ctx.Context.Value(key)
   192  }