Skip to content

Instantly share code, notes, and snippets.

@purpleidea
Forked from ast/epoll.go
Created May 7, 2018 18:50
Show Gist options
  • Save purpleidea/67a213043ace8c66592cc194698dfc84 to your computer and use it in GitHub Desktop.
Save purpleidea/67a213043ace8c66592cc194698dfc84 to your computer and use it in GitHub Desktop.
Minimal viable epoll package for go
package epoll
import (
"golang.org/x/sys/unix"
"os"
)
type Op uint32
const (
// Just a subset, check the complete x/sys/unix documentation
EpollIn Op = unix.EPOLLIN
EpollOut = unix.EPOLLOUT
EpollPri = unix.EPOLLPRI
EpollErr = unix.EPOLLERR
// It will probably not do what you have in mind without this flag.
// Without you will get multiple events while the fd is ready.
EpollEt = unix.EPOLLET
)
type Event struct {
File *os.File
Ops Op
}
type EpollWatcher struct {
Events chan Event
Errors chan error
epfd int
files map[int]*os.File
}
/* internal waiting function */
func (w *EpollWatcher) epollWait() {
events := make([]unix.EpollEvent, 10)
timeout_msec := -1
for {
n, err := unix.EpollWait(w.epfd, events, timeout_msec)
if err != nil {
w.Errors <- err
return
}
for _, e := range events[:n] {
w.Events <- Event{File: w.files[int(e.Fd)], Ops: Op(e.Events)}
}
}
}
func NewEpollWatcher() (*EpollWatcher, error) {
epfd, err := unix.EpollCreate(1) // argument ignored since Linux 2.6.8
if err != nil {
return nil, err
}
w := &EpollWatcher{Events: make(chan Event), Errors: make(chan error), epfd: epfd}
w.files = make(map[int]*os.File)
go w.epollWait() // enter waiting loop
return w, nil
}
func (w *EpollWatcher) Close() error {
return unix.Close(w.epfd)
}
func (w *EpollWatcher) Add(file *os.File, ops Op) error {
events := unix.EpollEvent{
Events: uint32(ops),
Fd: int32(file.Fd()),
}
err := unix.EpollCtl(w.epfd, unix.EPOLL_CTL_ADD, int(file.Fd()), &events)
if err != nil {
return err
}
// keep a map of fd to file so we can return the file object
w.files[int(file.Fd())] = file
return nil
}
func (w *EpollWatcher) Modify(file *os.File, ops Op) error {
events := unix.EpollEvent{
Events: uint32(ops),
Fd: int32(file.Fd()),
}
return unix.EpollCtl(w.epfd, unix.EPOLL_CTL_MOD, int(file.Fd()), &events)
}
func (w *EpollWatcher) Remove(file os.File) error {
err := unix.EpollCtl(w.epfd, unix.EPOLL_CTL_DEL, int(file.Fd()), nil)
if err != nil {
return err
}
delete(w.files, int(file.Fd()))
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment