github.com/iceber/iouring-go@v0.0.0-20230403020409-002cfd2e2a90/poller.go (about)

     1  // +build linux
     2  
     3  package iouring
     4  
     5  import (
     6  	"os"
     7  	"sync"
     8  
     9  	"golang.org/x/sys/unix"
    10  )
    11  
    12  const initEpollEvents = 1
    13  
    14  type iourPoller struct {
    15  	sync.Mutex
    16  
    17  	fd     int
    18  	iours  map[int]*IOURing
    19  	events []unix.EpollEvent
    20  }
    21  
    22  var (
    23  	poller         *iourPoller
    24  	initpollerLock sync.Mutex
    25  )
    26  
    27  func initpoller() error {
    28  	// fast path
    29  	if poller != nil {
    30  		return nil
    31  	}
    32  
    33  	initpollerLock.Lock()
    34  	defer initpollerLock.Unlock()
    35  	if poller != nil {
    36  		return nil
    37  	}
    38  
    39  	epfd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
    40  	if err != nil {
    41  		return os.NewSyscallError("epoll_create1", err)
    42  	}
    43  
    44  	poller = &iourPoller{
    45  		fd:     epfd,
    46  		iours:  make(map[int]*IOURing),
    47  		events: make([]unix.EpollEvent, initEpollEvents),
    48  	}
    49  
    50  	go poller.run()
    51  	return nil
    52  }
    53  
    54  func registerIOURing(iour *IOURing) error {
    55  	if err := initpoller(); err != nil {
    56  		return err
    57  	}
    58  
    59  	if err := unix.EpollCtl(poller.fd, unix.EPOLL_CTL_ADD, iour.eventfd,
    60  		&unix.EpollEvent{Fd: int32(iour.eventfd), Events: unix.EPOLLIN | unix.EPOLLET},
    61  	); err != nil {
    62  		return os.NewSyscallError("epoll_ctl_add", err)
    63  	}
    64  
    65  	poller.Lock()
    66  	poller.iours[iour.eventfd] = iour
    67  	poller.Unlock()
    68  	return nil
    69  }
    70  
    71  func removeIOURing(iour *IOURing) error {
    72  	poller.Lock()
    73  	delete(poller.iours, iour.eventfd)
    74  	poller.Unlock()
    75  
    76  	return os.NewSyscallError("epoll_ctl_del",
    77  		unix.EpollCtl(poller.fd, unix.EPOLL_CTL_DEL, iour.eventfd, nil))
    78  }
    79  
    80  func (poller *iourPoller) run() {
    81  	for {
    82  		n, err := unix.EpollWait(poller.fd, poller.events, -1)
    83  		if err != nil {
    84  			continue
    85  		}
    86  
    87  		for i := 0; i < n; i++ {
    88  			fd := int(poller.events[i].Fd)
    89  			poller.Lock()
    90  			iour, ok := poller.iours[fd]
    91  			poller.Unlock()
    92  			if !ok {
    93  				continue
    94  			}
    95  
    96  			select {
    97  			case iour.cqeSign <- struct{}{}:
    98  			default:
    99  			}
   100  		}
   101  
   102  		poller.adjust()
   103  	}
   104  }
   105  
   106  func (poller *iourPoller) adjust() {
   107  	poller.Lock()
   108  	l := len(poller.iours) - len(poller.events)
   109  	poller.Unlock()
   110  
   111  	if l <= 0 {
   112  		return
   113  	}
   114  
   115  	events := make([]unix.EpollEvent, l*2)
   116  	poller.events = append(poller.events, events...)
   117  }