internal/pipewire: EPOLL_CTL_ADD instead of EPOLL_CTL_MOD
All checks were successful
Test / Create distribution (push) Successful in 37s
Test / Sandbox (push) Successful in 2m29s
Test / Hakurei (push) Successful in 3m24s
Test / Hpkg (push) Successful in 4m15s
Test / Sandbox (race detector) (push) Successful in 4m30s
Test / Hakurei (race detector) (push) Successful in 5m26s
Test / Flake checks (push) Successful in 1m45s

Implementation is no longer tied down by the limitations of SyscallConn.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-12-19 00:43:15 +09:00
parent 5a50bf80ee
commit ec49c63c5f

View File

@@ -188,63 +188,57 @@ func (conn *unixConn) wantsEpoll() error {
if !conn.epoll { if !conn.epoll {
conn.epoll = true conn.epoll = true
conn.epollFd, conn.epollErr = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC) conn.epollFd, conn.epollErr = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC)
if conn.epollErr == nil {
if conn.epollErr = syscall.EpollCtl(conn.epollFd, syscall.EPOLL_CTL_ADD, conn.fd, &syscall.EpollEvent{
Events: syscall.EPOLLERR | syscall.EPOLLHUP,
Fd: int32(conn.fd),
}); conn.epollErr != nil {
_ = syscall.Close(conn.epollFd)
}
}
} }
return conn.epollErr return conn.epollErr
} }
// wait waits for a specific I/O event on fd and returns a function // wait waits for a specific I/O event on fd. Caller must arrange for wantsEpoll
// that must be deferred by the caller regardless of error. // to be called somewhere before wait is called.
func (conn *unixConn) wait(event uint32, errP *error) (cleanupFunc func()) { func (conn *unixConn) wait(event uint32) (err error) {
if conn.timeout == 0 { if conn.timeout == 0 {
return func() {} return nil
} }
deadline := time.Now().Add(conn.timeout) deadline := time.Now().Add(conn.timeout)
conn.timeout = 0 conn.timeout = 0
if *errP = syscall.EpollCtl(conn.epollFd, syscall.EPOLL_CTL_ADD, conn.fd, &syscall.EpollEvent{ if err = syscall.EpollCtl(conn.epollFd, syscall.EPOLL_CTL_MOD, conn.fd, &syscall.EpollEvent{
Events: event | syscall.EPOLLERR | syscall.EPOLLHUP, Events: event | syscall.EPOLLERR | syscall.EPOLLHUP,
Fd: int32(conn.fd), Fd: int32(conn.fd),
}); *errP != nil { }); err != nil {
return func() {} return
} else {
cleanupFunc = func() {
// fd is guaranteed to remain valid while f executes but not after f returns
if epDelErr := syscall.EpollCtl(conn.epollFd, syscall.EPOLL_CTL_DEL, conn.fd, nil); epDelErr != nil && *errP == nil {
*errP = epDelErr
return
}
}
} }
for timeout := deadline.Sub(time.Now()); timeout > 0; timeout = deadline.Sub(time.Now()) { for timeout := deadline.Sub(time.Now()); timeout > 0; timeout = deadline.Sub(time.Now()) {
if n, err := syscall.EpollWait(conn.epollFd, conn.epollBuf[:], int(timeout/time.Millisecond)); err != nil { var n int
*errP = err if n, err = syscall.EpollWait(conn.epollFd, conn.epollBuf[:], int(timeout/time.Millisecond)); err != nil {
return return
} else { }
switch n {
case 1: // only the socket fd is ever added
if conn.epollBuf[0].Fd != int32(conn.fd) { // unreachable
err = syscall.ENOTRECOVERABLE
break
}
if conn.epollBuf[0].Events&event == event ||
conn.epollBuf[0].Events&syscall.EPOLLERR|syscall.EPOLLHUP != 0 {
break
}
*errP = syscall.ETIME
continue
case 0: // timeout switch n {
err = syscall.ETIMEDOUT case 1: // only the socket fd is ever added
break if conn.epollBuf[0].Fd != int32(conn.fd) { // unreachable
return syscall.ENOTRECOVERABLE
default: // unreachable
err = syscall.ENOTRECOVERABLE
break
} }
if conn.epollBuf[0].Events&event == event ||
conn.epollBuf[0].Events&syscall.EPOLLERR|syscall.EPOLLHUP != 0 {
return nil
}
err = syscall.ETIME
continue
*errP = err case 0: // timeout
break return syscall.ETIMEDOUT
default: // unreachable
return syscall.ENOTRECOVERABLE
} }
} }
return return
@@ -254,9 +248,7 @@ func (conn *unixConn) wait(event uint32, errP *error) (cleanupFunc func()) {
func (conn *unixConn) Recvmsg(p, oob []byte, flags int) (n, oobn, recvflags int, err error) { func (conn *unixConn) Recvmsg(p, oob []byte, flags int) (n, oobn, recvflags int, err error) {
if err = conn.wantsEpoll(); err != nil { if err = conn.wantsEpoll(); err != nil {
return return
} } else if err = conn.wait(syscall.EPOLLIN); err != nil {
defer conn.wait(syscall.EPOLLIN, &err)()
if err != nil {
return return
} }
@@ -268,9 +260,7 @@ func (conn *unixConn) Recvmsg(p, oob []byte, flags int) (n, oobn, recvflags int,
func (conn *unixConn) Sendmsg(p, oob []byte, flags int) (n int, err error) { func (conn *unixConn) Sendmsg(p, oob []byte, flags int) (n int, err error) {
if err = conn.wantsEpoll(); err != nil { if err = conn.wantsEpoll(); err != nil {
return return
} } else if err = conn.wait(syscall.EPOLLOUT); err != nil {
defer conn.wait(syscall.EPOLLOUT, &err)()
if err != nil {
return return
} }