github.com/weedge/lib@v0.0.0-20230424045628-a36dcc1d90e4/poller/netpoll/netpoll.go (about)

     1  /*
     2  Package netpoll provides a portable interface for network I/O event
     3  notification facility.
     4  
     5  Its API is intended for monitoring multiple file descriptors to see if I/O is
     6  possible on any of them. It supports edge-triggered and level-triggered
     7  interfaces.
     8  
     9  To get more info you could look at operating system API documentation of
    10  particular netpoll implementations:
    11  	- epoll on linux;
    12  	- kqueue on bsd;
    13  
    14  The Handle function creates netpoll.Desc for further use in Poller's methods:
    15  
    16  	desc, err := netpoll.Handle(conn, netpoll.EventRead | netpoll.EventEdgeTriggered)
    17  	if err != nil {
    18  		// handle error
    19  	}
    20  
    21  The Poller describes os-dependent network poller:
    22  
    23  	poller, err := netpoll.New(nil)
    24  	if err != nil {
    25  		// handle error
    26  	}
    27  
    28  	// Get netpoll descriptor with EventRead|EventEdgeTriggered.
    29  	desc := netpoll.Must(netpoll.HandleRead(conn))
    30  
    31  	poller.Start(desc, func(ev netpoll.Event) {
    32  		if ev&netpoll.EventReadHup != 0 {
    33  			poller.Stop(desc)
    34  			conn.Close()
    35  			return
    36  		}
    37  
    38  		_, err := ioutil.ReadAll(conn)
    39  		if err != nil {
    40  			// handle error
    41  		}
    42  	})
    43  
    44  Currently, Poller is implemented only for Linux.
    45  */
    46  package netpoll
    47  
    48  import (
    49  	"fmt"
    50  	"log"
    51  )
    52  
    53  var (
    54  	// ErrNotFiler is returned by Handle* functions to indicate that given
    55  	// net.Conn does not provide access to its file descriptor.
    56  	ErrNotFiler = fmt.Errorf("could not get file descriptor")
    57  
    58  	// ErrClosed is returned by Poller methods to indicate that instance is
    59  	// closed and operation could not be processed.
    60  	ErrClosed = fmt.Errorf("poller instance is closed")
    61  
    62  	// ErrRegistered is returned by Poller Start() method to indicate that
    63  	// connection with the same underlying file descriptor was already
    64  	// registered within the poller instance.
    65  	ErrRegistered = fmt.Errorf("file descriptor is already registered in poller instance")
    66  
    67  	// ErrNotRegistered is returned by Poller Stop() and Resume() methods to
    68  	// indicate that connection with the same underlying file descriptor was
    69  	// not registered before within the poller instance.
    70  	ErrNotRegistered = fmt.Errorf("file descriptor was not registered before in poller instance")
    71  )
    72  
    73  // Event represents netpoll configuration bit mask.
    74  type Event uint16
    75  
    76  // Event values that denote the type of events that caller want to receive.
    77  const (
    78  	EventRead  Event = 0x1
    79  	EventWrite       = 0x2
    80  )
    81  
    82  // Event values that configure the Poller's behavior.
    83  const (
    84  	EventOneShot       Event = 0x4
    85  	EventEdgeTriggered       = 0x8
    86  )
    87  
    88  // Event values that could be passed to CallbackFn as additional information
    89  // event.
    90  const (
    91  	// EventHup is indicates that some side of i/o operations (receive, send or
    92  	// both) is closed.
    93  	// Usually (depending on operating system and its version) the EventReadHup
    94  	// or EventWriteHup are also set int Event value.
    95  	EventHup Event = 0x10
    96  
    97  	EventReadHup  = 0x20
    98  	EventWriteHup = 0x40
    99  
   100  	EventErr = 0x80
   101  
   102  	// EventPollerClosed is a special Event value the receipt of which means that the
   103  	// Poller instance is closed.
   104  	EventPollerClosed = 0x8000
   105  )
   106  
   107  // String returns a string representation of Event.
   108  func (ev Event) String() (str string) {
   109  	name := func(event Event, name string) {
   110  		if ev&event == 0 {
   111  			return
   112  		}
   113  		if str != "" {
   114  			str += "|"
   115  		}
   116  		str += name
   117  	}
   118  
   119  	name(EventRead, "EventRead")
   120  	name(EventWrite, "EventWrite")
   121  	name(EventOneShot, "EventOneShot")
   122  	name(EventEdgeTriggered, "EventEdgeTriggered")
   123  	name(EventReadHup, "EventReadHup")
   124  	name(EventWriteHup, "EventWriteHup")
   125  	name(EventHup, "EventHup")
   126  	name(EventErr, "EventErr")
   127  	name(EventPollerClosed, "EventPollerClosed")
   128  
   129  	return
   130  }
   131  
   132  // Poller describes an object that implements event of polling connections for
   133  // i/o events such as availability of read() or write() operations.
   134  type Poller interface {
   135  	// Start adds desc to the observation list.
   136  	//
   137  	// Note that if desc was configured with OneShot event, then poller will
   138  	// remove it from its observation list. If you will be interested in
   139  	// receiving events after the callback, call Resume(desc).
   140  	//
   141  	// Note that Resume() call directly inside desc's callback could cause
   142  	// deadlock.
   143  	//
   144  	// Note that multiple calls with same desc will produce unexpected
   145  	// behavior.
   146  	Start(*Desc, CallbackFn) error
   147  
   148  	// Stop removes desc from the observation list.
   149  	//
   150  	// Note that it does not call desc.Close().
   151  	Stop(*Desc) error
   152  
   153  	// Resume enables observation of desc.
   154  	//
   155  	// It is useful when desc was configured with EventOneShot.
   156  	// It should be called only after Start().
   157  	//
   158  	// Note that if there no need to observe desc anymore, you should call
   159  	// Stop() to prevent memory leaks.
   160  	Resume(*Desc) error
   161  }
   162  
   163  // CallbackFn is a function that will be called on kernel i/o event
   164  // notification.
   165  type CallbackFn func(Event)
   166  
   167  // Config contains options for Poller configuration.
   168  type Config struct {
   169  	// OnWaitError will be called from goroutine, waiting for events.
   170  	OnWaitError func(error)
   171  }
   172  
   173  func (c *Config) withDefaults() (config Config) {
   174  	if c != nil {
   175  		config = *c
   176  	}
   177  	if config.OnWaitError == nil {
   178  		config.OnWaitError = defaultOnWaitError
   179  	}
   180  	return config
   181  }
   182  
   183  func defaultOnWaitError(err error) {
   184  	log.Printf("netpoll: wait loop error: %s", err)
   185  }