github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/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 "errors" 28 "sync" 29 "time" 30 31 "github.com/nicocha30/gvisor-ligolo/pkg/log" 32 "github.com/nicocha30/gvisor-ligolo/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 }