github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/waiter/waiter.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 waiter provides the implementation of a wait queue, where waiters can 16 // be enqueued to be notified when an event of interest happens. 17 // 18 // Becoming readable and/or writable are examples of events. Waiters are 19 // expected to use a pattern similar to this to make a blocking function out of 20 // a non-blocking one: 21 // 22 // func (o *object) blockingRead(...) error { 23 // err := o.nonBlockingRead(...) 24 // if err != ErrAgain { 25 // // Completed with no need to wait! 26 // return err 27 // } 28 // 29 // e := createOrGetWaiterEntry(...) 30 // o.EventRegister(&e, waiter.EventIn) 31 // defer o.EventUnregister(&e) 32 // 33 // // We need to try to read again after registration because the 34 // // object may have become readable between the last attempt to 35 // // read and read registration. 36 // err = o.nonBlockingRead(...) 37 // for err == ErrAgain { 38 // wait() 39 // err = o.nonBlockingRead(...) 40 // } 41 // 42 // return err 43 // } 44 // 45 // Another goroutine needs to notify waiters when events happen. For example: 46 // 47 // func (o *object) Write(...) ... { 48 // // Do write work. 49 // [...] 50 // 51 // if oldDataAvailableSize == 0 && dataAvailableSize > 0 { 52 // // If no data was available and now some data is 53 // // available, the object became readable, so notify 54 // // potential waiters about this. 55 // o.Notify(waiter.EventIn) 56 // } 57 // } 58 package waiter 59 60 import ( 61 "github.com/nicocha30/gvisor-ligolo/pkg/sync" 62 ) 63 64 // EventMask represents io events as used in the poll() syscall. 65 type EventMask uint64 66 67 // Events that waiters can wait on. The meaning is the same as those in the 68 // poll() syscall. 69 const ( 70 EventIn EventMask = 0x01 // POLLIN 71 EventPri EventMask = 0x02 // POLLPRI 72 EventOut EventMask = 0x04 // POLLOUT 73 EventErr EventMask = 0x08 // POLLERR 74 EventHUp EventMask = 0x10 // POLLHUP 75 EventRdNorm EventMask = 0x0040 // POLLRDNORM 76 EventWrNorm EventMask = 0x0100 // POLLWRNORM 77 EventInternal EventMask = 0x1000 78 EventRdHUp EventMask = 0x2000 // POLLRDHUP 79 80 allEvents EventMask = 0x1f | EventRdNorm | EventWrNorm | EventRdHUp 81 ReadableEvents EventMask = EventIn | EventRdNorm 82 WritableEvents EventMask = EventOut | EventWrNorm 83 ) 84 85 // EventMaskFromLinux returns an EventMask representing the supported events 86 // from the Linux events e, which is in the format used by poll(2). 87 func EventMaskFromLinux(e uint32) EventMask { 88 // Our flag definitions are currently identical to Linux. 89 return EventMask(e) & allEvents 90 } 91 92 // ToLinux returns e in the format used by Linux poll(2). 93 func (e EventMask) ToLinux() uint32 { 94 // Our flag definitions are currently identical to Linux. 95 return uint32(e) 96 } 97 98 // Waitable contains the methods that need to be implemented by waitable 99 // objects. 100 type Waitable interface { 101 // Readiness returns what the object is currently ready for. If it's 102 // not ready for a desired purpose, the caller may use EventRegister and 103 // EventUnregister to get notifications once the object becomes ready. 104 // 105 // Implementations should allow for events like EventHUp and EventErr 106 // to be returned regardless of whether they are in the input EventMask. 107 Readiness(mask EventMask) EventMask 108 109 // EventRegister registers the given waiter entry to receive 110 // notifications when an event occurs that makes the object ready for 111 // at least one of the events in mask. 112 EventRegister(e *Entry) error 113 114 // EventUnregister unregisters a waiter entry previously registered with 115 // EventRegister(). 116 EventUnregister(e *Entry) 117 } 118 119 // EventListener provides a notify callback. 120 type EventListener interface { 121 // NotifyEvent is the function to be called when the waiter entry is 122 // notified. It is responsible for doing whatever is needed to wake up 123 // the waiter. 124 // 125 // The callback is supposed to perform minimal work, and cannot call 126 // any method on the queue itself because it will be locked while the 127 // callback is running. 128 // 129 // The mask indicates the events that occurred and that the entry is 130 // interested in. 131 NotifyEvent(mask EventMask) 132 } 133 134 // Entry represents a waiter that can be add to the a wait queue. It can 135 // only be in one queue at a time, and is added "intrusively" to the queue with 136 // no extra memory allocations. 137 // 138 // +stateify savable 139 type Entry struct { 140 waiterEntry 141 142 // eventListener receives the notification. 143 eventListener EventListener 144 145 // mask should be immutable once queued. 146 mask EventMask 147 } 148 149 // Init initializes the Entry. 150 // 151 // This must only be called when unregistered. 152 func (e *Entry) Init(eventListener EventListener, mask EventMask) { 153 e.eventListener = eventListener 154 e.mask = mask 155 } 156 157 // Mask returns the entry mask. 158 func (e *Entry) Mask() EventMask { 159 return e.mask 160 } 161 162 // NotifyEvent notifies the event listener. 163 // 164 // Mask should be the full set of active events. 165 func (e *Entry) NotifyEvent(mask EventMask) { 166 if m := mask & e.mask; m != 0 { 167 e.eventListener.NotifyEvent(m) 168 } 169 } 170 171 // ChannelNotifier is a simple channel-based notification. 172 type ChannelNotifier chan struct{} 173 174 // NotifyEvent implements waiter.EventListener.NotifyEvent. 175 func (c ChannelNotifier) NotifyEvent(EventMask) { 176 select { 177 case c <- struct{}{}: 178 default: 179 } 180 } 181 182 // NewChannelEntry initializes a new Entry that does a non-blocking write to a 183 // struct{} channel when the callback is called. It returns the new Entry 184 // instance and the channel being used. 185 func NewChannelEntry(mask EventMask) (e Entry, ch chan struct{}) { 186 ch = make(chan struct{}, 1) 187 e.Init(ChannelNotifier(ch), mask) 188 return e, ch 189 } 190 191 type functionNotifier func(EventMask) 192 193 // NotifyEvent implements waiter.EventListener.NotifyEvent. 194 func (f functionNotifier) NotifyEvent(mask EventMask) { 195 f(mask) 196 } 197 198 // NewFunctionEntry initializes a new Entry that calls the given function. 199 func NewFunctionEntry(mask EventMask, fn func(EventMask)) (e Entry) { 200 e.Init(functionNotifier(fn), mask) 201 return e 202 } 203 204 // Queue represents the wait queue where waiters can be added and 205 // notifiers can notify them when events happen. 206 // 207 // The zero value for waiter.Queue is an empty queue ready for use. 208 // 209 // +stateify savable 210 type Queue struct { 211 list waiterList 212 mu sync.RWMutex `state:"nosave"` 213 } 214 215 // EventRegister adds a waiter to the wait queue. 216 func (q *Queue) EventRegister(e *Entry) { 217 q.mu.Lock() 218 q.list.PushBack(e) 219 q.mu.Unlock() 220 } 221 222 // EventUnregister removes the given waiter entry from the wait queue. 223 func (q *Queue) EventUnregister(e *Entry) { 224 q.mu.Lock() 225 q.list.Remove(e) 226 q.mu.Unlock() 227 } 228 229 // Notify notifies all waiters in the queue whose masks have at least one bit 230 // in common with the notification mask. 231 func (q *Queue) Notify(mask EventMask) { 232 q.mu.RLock() 233 for e := q.list.Front(); e != nil; e = e.Next() { 234 m := mask & e.mask 235 if m == 0 { 236 continue 237 } 238 e.eventListener.NotifyEvent(m) // Skip intermediate call. 239 } 240 q.mu.RUnlock() 241 } 242 243 // Events returns the set of events being waited on. It is the union of the 244 // masks of all registered entries. 245 func (q *Queue) Events() EventMask { 246 q.mu.RLock() 247 defer q.mu.RUnlock() 248 ret := EventMask(0) 249 for e := q.list.Front(); e != nil; e = e.Next() { 250 ret |= e.mask 251 } 252 return ret 253 } 254 255 // IsEmpty returns if the wait queue is empty or not. 256 func (q *Queue) IsEmpty() bool { 257 q.mu.RLock() 258 defer q.mu.RUnlock() 259 return q.list.Front() == nil 260 } 261 262 // AlwaysReady implements the Waitable interface but is always ready. Embedding 263 // this struct into another struct makes it implement the boilerplate empty 264 // functions automatically. 265 type AlwaysReady struct { 266 } 267 268 // Readiness always returns the input mask because this object is always ready. 269 func (*AlwaysReady) Readiness(mask EventMask) EventMask { 270 return mask 271 } 272 273 // EventRegister doesn't do anything because this object doesn't need to issue 274 // notifications because its readiness never changes. 275 func (*AlwaysReady) EventRegister(*Entry) error { 276 return nil 277 } 278 279 // EventUnregister doesn't do anything because this object doesn't need to issue 280 // notifications because its readiness never changes. 281 func (*AlwaysReady) EventUnregister(e *Entry) { 282 } 283 284 // NeverReady implements the Waitable interface but is never ready. Otherwise, 285 // this is exactly the same as AlwaysReady. 286 type NeverReady struct { 287 } 288 289 // Readiness always returns the input mask because this object is always ready. 290 func (*NeverReady) Readiness(mask EventMask) EventMask { 291 return mask 292 } 293 294 // EventRegister doesn't do anything because this object doesn't need to issue 295 // notifications because its readiness never changes. 296 func (*NeverReady) EventRegister(e *Entry) error { 297 return nil 298 } 299 300 // EventUnregister doesn't do anything because this object doesn't need to issue 301 // notifications because its readiness never changes. 302 func (*NeverReady) EventUnregister(e *Entry) { 303 }