github.com/lightlus/netstack@v1.2.0/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  	"sync"
    62  )
    63  
    64  // EventMask represents io events as used in the poll() syscall.
    65  type EventMask uint16
    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  
    76  	allEvents EventMask = 0x1f
    77  )
    78  
    79  // EventMaskFromLinux returns an EventMask representing the supported events
    80  // from the Linux events e, which is in the format used by poll(2).
    81  func EventMaskFromLinux(e uint32) EventMask {
    82  	// Our flag definitions are currently identical to Linux.
    83  	return EventMask(e) & allEvents
    84  }
    85  
    86  // ToLinux returns e in the format used by Linux poll(2).
    87  func (e EventMask) ToLinux() uint32 {
    88  	// Our flag definitions are currently identical to Linux.
    89  	return uint32(e)
    90  }
    91  
    92  // Waitable contains the methods that need to be implemented by waitable
    93  // objects.
    94  type Waitable interface {
    95  	// Readiness returns what the object is currently ready for. If it's
    96  	// not ready for a desired purpose, the caller may use EventRegister and
    97  	// EventUnregister to get notifications once the object becomes ready.
    98  	//
    99  	// Implementations should allow for events like EventHUp and EventErr
   100  	// to be returned regardless of whether they are in the input EventMask.
   101  	Readiness(mask EventMask) EventMask
   102  
   103  	// EventRegister registers the given waiter entry to receive
   104  	// notifications when an event occurs that makes the object ready for
   105  	// at least one of the events in mask.
   106  	EventRegister(e *Entry, mask EventMask)
   107  
   108  	// EventUnregister unregisters a waiter entry previously registered with
   109  	// EventRegister().
   110  	EventUnregister(e *Entry)
   111  }
   112  
   113  // EntryCallback provides a notify callback.
   114  type EntryCallback interface {
   115  	// Callback is the function to be called when the waiter entry is
   116  	// notified. It is responsible for doing whatever is needed to wake up
   117  	// the waiter.
   118  	//
   119  	// The callback is supposed to perform minimal work, and cannot call
   120  	// any method on the queue itself because it will be locked while the
   121  	// callback is running.
   122  	Callback(e *Entry)
   123  }
   124  
   125  // Entry represents a waiter that can be add to the a wait queue. It can
   126  // only be in one queue at a time, and is added "intrusively" to the queue with
   127  // no extra memory allocations.
   128  //
   129  // +stateify savable
   130  type Entry struct {
   131  	// Context stores any state the waiter may wish to store in the entry
   132  	// itself, which may be used at wake up time.
   133  	//
   134  	// Note that use of this field is optional and state may alternatively be
   135  	// stored in the callback itself.
   136  	Context interface{}
   137  
   138  	Callback EntryCallback
   139  
   140  	// The following fields are protected by the queue lock.
   141  	mask EventMask
   142  	waiterEntry
   143  }
   144  
   145  type channelCallback struct{}
   146  
   147  // Callback implements EntryCallback.Callback.
   148  func (*channelCallback) Callback(e *Entry) {
   149  	ch := e.Context.(chan struct{})
   150  	select {
   151  	case ch <- struct{}{}:
   152  	default:
   153  	}
   154  }
   155  
   156  // NewChannelEntry initializes a new Entry that does a non-blocking write to a
   157  // struct{} channel when the callback is called. It returns the new Entry
   158  // instance and the channel being used.
   159  //
   160  // If a channel isn't specified (i.e., if "c" is nil), then NewChannelEntry
   161  // allocates a new channel.
   162  func NewChannelEntry(c chan struct{}) (Entry, chan struct{}) {
   163  	if c == nil {
   164  		c = make(chan struct{}, 1)
   165  	}
   166  
   167  	return Entry{Context: c, Callback: &channelCallback{}}, c
   168  }
   169  
   170  // Queue represents the wait queue where waiters can be added and
   171  // notifiers can notify them when events happen.
   172  //
   173  // The zero value for waiter.Queue is an empty queue ready for use.
   174  //
   175  // +stateify savable
   176  type Queue struct {
   177  	list waiterList
   178  	mu   sync.RWMutex
   179  }
   180  
   181  // EventRegister adds a waiter to the wait queue; the waiter will be notified
   182  // when at least one of the events specified in mask happens.
   183  func (q *Queue) EventRegister(e *Entry, mask EventMask) {
   184  	q.mu.Lock()
   185  	e.mask = mask
   186  	q.list.PushBack(e)
   187  	q.mu.Unlock()
   188  }
   189  
   190  // EventUnregister removes the given waiter entry from the wait queue.
   191  func (q *Queue) EventUnregister(e *Entry) {
   192  	q.mu.Lock()
   193  	q.list.Remove(e)
   194  	q.mu.Unlock()
   195  }
   196  
   197  // Notify notifies all waiters in the queue whose masks have at least one bit
   198  // in common with the notification mask.
   199  func (q *Queue) Notify(mask EventMask) {
   200  	q.mu.RLock()
   201  	for e := q.list.Front(); e != nil; e = e.Next() {
   202  		if mask&e.mask != 0 {
   203  			e.Callback.Callback(e)
   204  		}
   205  	}
   206  	q.mu.RUnlock()
   207  }
   208  
   209  // Events returns the set of events being waited on. It is the union of the
   210  // masks of all registered entries.
   211  func (q *Queue) Events() EventMask {
   212  	ret := EventMask(0)
   213  
   214  	q.mu.RLock()
   215  	for e := q.list.Front(); e != nil; e = e.Next() {
   216  		ret |= e.mask
   217  	}
   218  	q.mu.RUnlock()
   219  
   220  	return ret
   221  }
   222  
   223  // IsEmpty returns if the wait queue is empty or not.
   224  func (q *Queue) IsEmpty() bool {
   225  	q.mu.Lock()
   226  	defer q.mu.Unlock()
   227  
   228  	return q.list.Front() == nil
   229  }
   230  
   231  // AlwaysReady implements the Waitable interface but is always ready. Embedding
   232  // this struct into another struct makes it implement the boilerplate empty
   233  // functions automatically.
   234  type AlwaysReady struct {
   235  }
   236  
   237  // Readiness always returns the input mask because this object is always ready.
   238  func (*AlwaysReady) Readiness(mask EventMask) EventMask {
   239  	return mask
   240  }
   241  
   242  // EventRegister doesn't do anything because this object doesn't need to issue
   243  // notifications because its readiness never changes.
   244  func (*AlwaysReady) EventRegister(*Entry, EventMask) {
   245  }
   246  
   247  // EventUnregister doesn't do anything because this object doesn't need to issue
   248  // notifications because its readiness never changes.
   249  func (*AlwaysReady) EventUnregister(e *Entry) {
   250  }