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  }