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 {
conn.epoll = true
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
}
// wait waits for a specific I/O event on fd and returns a function
// that must be deferred by the caller regardless of error.
func (conn *unixConn) wait(event uint32, errP *error) (cleanupFunc func()) {
// wait waits for a specific I/O event on fd. Caller must arrange for wantsEpoll
// to be called somewhere before wait is called.
func (conn *unixConn) wait(event uint32) (err error) {
if conn.timeout == 0 {
return func() {}
return nil
}
deadline := time.Now().Add(conn.timeout)
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,
Fd: int32(conn.fd),
}); *errP != nil {
return func() {}
} 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
}
}
}); err != nil {
return
}
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 {
*errP = err
var n int
if n, err = syscall.EpollWait(conn.epollFd, conn.epollBuf[:], int(timeout/time.Millisecond)); err != nil {
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
err = syscall.ETIMEDOUT
break
default: // unreachable
err = syscall.ENOTRECOVERABLE
break
switch n {
case 1: // only the socket fd is ever added
if conn.epollBuf[0].Fd != int32(conn.fd) { // unreachable
return syscall.ENOTRECOVERABLE
}
if conn.epollBuf[0].Events&event == event ||
conn.epollBuf[0].Events&syscall.EPOLLERR|syscall.EPOLLHUP != 0 {
return nil
}
err = syscall.ETIME
continue
*errP = err
break
case 0: // timeout
return syscall.ETIMEDOUT
default: // unreachable
return syscall.ENOTRECOVERABLE
}
}
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) {
if err = conn.wantsEpoll(); err != nil {
return
}
defer conn.wait(syscall.EPOLLIN, &err)()
if err != nil {
} else if err = conn.wait(syscall.EPOLLIN); err != nil {
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) {
if err = conn.wantsEpoll(); err != nil {
return
}
defer conn.wait(syscall.EPOLLOUT, &err)()
if err != nil {
} else if err = conn.wait(syscall.EPOLLOUT); err != nil {
return
}