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