evio/internal/internal_linux.go

133 lines
2.6 KiB
Go

// Copyright 2017 Joshua J Baker. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package internal
import (
"syscall"
"unsafe"
)
// Poll ...
type Poll struct {
fd int // epoll fd
wfd int // wake fd
notes noteQueue
}
// OpenPoll ...
func OpenPoll() *Poll {
l := new(Poll)
p, err := syscall.EpollCreate1(0)
if err != nil {
panic(err)
}
l.fd = p
r0, _, e0 := syscall.Syscall(syscall.SYS_EVENTFD2, 0, 0, 0)
if e0 != 0 {
syscall.Close(p)
panic(err)
}
l.wfd = int(r0)
l.AddRead(l.wfd)
return l
}
// Close ...
func (p *Poll) Close() error {
if err := syscall.Close(p.wfd); err != nil {
return err
}
return syscall.Close(p.fd)
}
// Trigger ...
func (p *Poll) Trigger(note interface{}) error {
p.notes.Add(note)
var x uint64 = 1
_, err := syscall.Write(p.wfd, (*(*[8]byte)(unsafe.Pointer(&x)))[:])
return err
}
// Wait ...
func (p *Poll) Wait(iter func(fd int, note interface{}) error) error {
events := make([]syscall.EpollEvent, 64)
for {
n, err := syscall.EpollWait(p.fd, events, 100)
if err != nil && err != syscall.EINTR {
return err
}
if err := p.notes.ForEach(func(note interface{}) error {
return iter(0, note)
}); err != nil {
return err
}
for i := 0; i < n; i++ {
if fd := int(events[i].Fd); fd != p.wfd {
if err := iter(fd, nil); err != nil {
return err
}
} else if fd == p.wfd {
var data [8]byte
syscall.Read(p.wfd, data[:])
}
}
}
}
// AddReadWrite ...
func (p *Poll) AddReadWrite(fd int) {
if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_ADD, fd,
&syscall.EpollEvent{Fd: int32(fd),
Events: syscall.EPOLLIN | syscall.EPOLLOUT,
},
); err != nil {
panic(err)
}
}
// AddRead ...
func (p *Poll) AddRead(fd int) {
if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_ADD, fd,
&syscall.EpollEvent{Fd: int32(fd),
Events: syscall.EPOLLIN,
},
); err != nil {
panic(err)
}
}
// ModRead ...
func (p *Poll) ModRead(fd int) {
if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_MOD, fd,
&syscall.EpollEvent{Fd: int32(fd),
Events: syscall.EPOLLIN,
},
); err != nil {
panic(err)
}
}
// ModReadWrite ...
func (p *Poll) ModReadWrite(fd int) {
if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_MOD, fd,
&syscall.EpollEvent{Fd: int32(fd),
Events: syscall.EPOLLIN | syscall.EPOLLOUT,
},
); err != nil {
panic(err)
}
}
// ModDetach ...
func (p *Poll) ModDetach(fd int) {
if err := syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_DEL, fd,
&syscall.EpollEvent{Fd: int32(fd),
Events: syscall.EPOLLIN | syscall.EPOLLOUT,
},
); err != nil {
panic(err)
}
}