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 }