code: func (r *rx) init(mtu uint32, c *QueueConfig) error {
  	// Map in all buffers.
  	txPipe, err := getBuffer(c.TxPipeFD)
  	if err != nil {
  		return err
  	}
  
  	rxPipe, err := getBuffer(c.RxPipeFD)
  	if err != nil {
  		syscall.Munmap(txPipe)
  		return err
  	}
  
  	data, err := getBuffer(c.DataFD)
  	if err != nil {
  		syscall.Munmap(txPipe)
  		syscall.Munmap(rxPipe)
  		return err
  	}
  
  	sharedData, err := getBuffer(c.SharedDataFD)
  	if err != nil {
  		syscall.Munmap(txPipe)
  		syscall.Munmap(rxPipe)
  		syscall.Munmap(data)
  		return err
  	}
  
  	// Duplicate the eventFD so that caller can close it but we can still
  	// use it.
  	efd, err := syscall.Dup(c.EventFD)
  	if err != nil {
  		syscall.Munmap(txPipe)
  		syscall.Munmap(rxPipe)
  		syscall.Munmap(data)
  		syscall.Munmap(sharedData)
  		return err
  	}
  
  	// Set the eventfd as non-blocking.
  	if err := syscall.SetNonblock(efd, true); err != nil {
  		syscall.Munmap(txPipe)
  		syscall.Munmap(rxPipe)
  		syscall.Munmap(data)
  		syscall.Munmap(sharedData)
  		syscall.Close(efd)
  		return err
  	}
  
  	// Initialize state based on buffers.
  	r.q.Init(txPipe, rxPipe, sharedDataPointer(sharedData))
  	r.data = data
  	r.eventFD = efd
  	r.sharedData = sharedData
  
  	return nil
  }
docs: // init initializes all state needed by the rx queue based on the information
  // provided.
  //
  // The caller always retains ownership of all file descriptors passed in. The
  // queue implementation will duplicate any that it may need in the future.