Skip to content

Commit 05294ba

Browse files
committed
Eliminate busy loop when receiving messages from non-blocking socket
For a non-blocking socket, it should wait for events first before receiving messages from the socket, otherwise it would receive empty message and run into a busy loop. Signed-off-by: Quan Tian <[email protected]>
1 parent 856e190 commit 05294ba

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

nl/nl_linux.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,9 @@ func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
629629
}
630630

631631
type NetlinkSocket struct {
632-
fd int32
632+
fd int32
633+
// pfd is non nil when the socket is in non-blocking mode, and is used to wait for events on the socket.
634+
pfd *unix.PollFd
633635
lsa unix.SockaddrNetlink
634636
sync.Mutex
635637
}
@@ -728,17 +730,20 @@ func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
728730
return nil, err
729731
}
730732

733+
var pfd *unix.PollFd
731734
// Sometimes (socket_linux.go:SocketGet), Subscribe is used to create a socket
732-
// that subscirbed to no groups. So we don't need to set nonblock there.
735+
// that subscribes to no groups. So we don't need to set nonblock there.
733736
if len(groups) > 0 {
734737
if err := unix.SetNonblock(fd, true); err != nil {
735738
unix.Close(fd)
736739
return nil, err
737740
}
741+
pfd = &unix.PollFd{Fd: int32(fd), Events: unix.POLLIN}
738742
}
739743

740744
s := &NetlinkSocket{
741-
fd: int32(fd),
745+
fd: int32(fd),
746+
pfd: pfd,
742747
}
743748
s.lsa.Family = unix.AF_NETLINK
744749

@@ -791,6 +796,13 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, *unix.SockaddrNetli
791796
if fd < 0 {
792797
return nil, nil, fmt.Errorf("Receive called on a closed socket")
793798
}
799+
// The socket is in non-blocking mode.
800+
if s.pfd != nil {
801+
if _, err := unix.Poll([]unix.PollFd{*s.pfd}, -1); err != nil {
802+
return nil, nil, fmt.Errorf("Error polling the socket: %w", err)
803+
}
804+
}
805+
794806
var fromAddr *unix.SockaddrNetlink
795807
var rb [RECEIVE_BUFFER_SIZE]byte
796808
nr, from, err := unix.Recvfrom(fd, rb[:], 0)

0 commit comments

Comments
 (0)