最近我在看 Go 的网络轮询器相关文章时,从源码看到 netpollinit 是通过 nonblockingPipe() 创建读写管道 来中断 epollwait ,为什么同样是 Linux 下不使用 eventfd 唤醒事件?有什么原因吗?
https://github.com/golang/go/blob/master/src/runtime/netpoll.go
func netpollinit() {
epfd = epollcreate1(_EPOLL_CLOEXEC)
if epfd < 0 {
epfd = epollcreate(1024)
if epfd < 0 {
println("runtime: epollcreate failed with", -epfd)
throw("runtime: netpollinit failed")
}
closeonexec(epfd)
}
r, w, errno := nonblockingPipe()
if errno != 0 {
println("runtime: pipe failed with", -errno)
throw("runtime: pipe failed")
}
ev := epollevent{
events: _EPOLLIN,
}
*(**uintptr)(unsafe.Pointer(&ev.data)) = &netpollBreakRd
errno = epollctl(epfd, _EPOLL_CTL_ADD, r, &ev)
if errno != 0 {
println("runtime: epollctl failed with", -errno)
throw("runtime: epollctl failed")
}
netpollBreakRd = uintptr(r)
netpollBreakWr = uintptr(w)
}
// netpollBreak interrupts an epollwait.
func netpollBreak() {
if atomic.Cas(&netpollWakeSig, 0, 1) {
for {
var b byte
n := write(netpollBreakWr, unsafe.Pointer(&b), 1)
if n == 1 {
break
}
if n == -_EINTR {
continue
}
if n == -_EAGAIN {
return
}
println("runtime: netpollBreak write failed with", -n)
throw("runtime: netpollBreak write failed")
}
}
}
1
lesismal 2022-04-03 23:01:58 +08:00
我不敢说这就是原因,只作为猜测:
1. pipe 和 event 都可以实现功能 2. pipe 每次只需要 write 1 字节,而 eventfd 每次必须写入大于等于 8 字节、相比之下浪费 |
2
nuk 2022-04-04 01:21:48 +08:00
内核版本要求吧,不然 eventfd 应该是更好的选择
|
3
mengzhuo 2022-04-05 09:54:52 +08:00
|