Skip to content

fix(socketcan): support socket file descriptors over 1023#2057

Open
SAY-5 wants to merge 4 commits into
hardbyte:mainfrom
SAY-5:fix/socketcan-high-fd
Open

fix(socketcan): support socket file descriptors over 1023#2057
SAY-5 wants to merge 4 commits into
hardbyte:mainfrom
SAY-5:fix/socketcan-high-fd

Conversation

@SAY-5

@SAY-5 SAY-5 commented May 12, 2026

Copy link
Copy Markdown
Contributor

Summary of Changes

  • Switch SocketcanBus._recv_internal() and send() from select.select() to select.poll().
  • Add regression test test/test_socketcan_high_fd.py (Linux-only) covering send/recv with a mocked socket whose fd is 2048.
  • Add towncrier news fragment.

Related Issues / Pull Requests

Type of Change

  • Bug fix

Checklist

  • I have followed the contribution guide.
  • I have added or updated tests as appropriate.
  • I have added or updated documentation as appropriate.
  • I have added a news fragment for towncrier.
  • All checks and tests pass (tox).

Additional Notes

select.select() is limited by glibc's FD_SETSIZE (1024) and raises ValueError: filedescriptor out of range in select() for higher fds even when the OS limit allows them. select.poll() has no such limit and returns equivalent readiness data. The change is internal to SocketcanBus; the public send/recv signatures and exception semantics are unchanged.

SAY-5 added 3 commits May 11, 2026 21:01
select.select() is limited by glibc's FD_SETSIZE (1024) and raises
ValueError for higher fds even when the OS limit allows them. Switch
SocketcanBus._recv_internal() and send() to select.poll(), which has
no such limit. Fixes hardbyte#2053.

Signed-off-by: SAY-5 <say.apm35@gmail.com>
Signed-off-by: SAY-5 <say.apm35@gmail.com>
@SAY-5 SAY-5 force-pushed the fix/socketcan-high-fd branch from 5d2dca1 to 43dc1a5 Compare May 13, 2026 00:29
Comment thread can/interfaces/socketcan/socketcan.py Outdated
while time_left >= 0:
# Wait for write availability
ready = select.select([], [self.socket], [], time_left)[1]
ready = poller.poll(max(0, int(time_left * 1000)))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the max call for? time_left is alwas positive here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped in 977fad4, the loop condition already guarantees time_left >= 0.

Comment thread can/interfaces/socketcan/socketcan.py Outdated
# being self.socket or an empty list if self.socket is not ready)
ready_receive_sockets, _, _ = select.select([self.socket], [], [], timeout)
# poll() avoids select.select()'s ValueError for fds >= FD_SETSIZE
poller = select.poll()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You create new poll objects on every read and write. That can't be good for performance.

Create one poll object inside __init__() and register both POLLIN and POLLOUT. Then here you call (fd, event) = self._poller.poll() and check whether the event contains POLLIN.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 977fad4. I went with one poller per direction, both created in init: with a single object registered for POLLIN|POLLOUT, recv would wake immediately whenever the socket is writable (which is almost always) and turn a blocking recv into a spin. Two pollers keep the blocking semantics and also avoid send/recv threads mutating shared registration state.

Comment thread test/test_socketcan_high_fd.py Outdated
@@ -0,0 +1,91 @@
#!/usr/bin/env python

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to create a new file to test this. Add a test to the existing socketcan tests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved into test_socketcan.py as SocketCANHighFdTest in 977fad4 and deleted the extra file.

@@ -0,0 +1 @@
``SocketcanBus`` now uses ``select.poll()`` instead of ``select.select()`` so that socket file descriptors above ``FD_SETSIZE`` (1024 on glibc) no longer raise ``ValueError: filedescriptor out of range in select()``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

…st into test_socketcan

Signed-off-by: Sai Asish Y <say.apm35@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SocketcanBus does not support socket file descriptors over 1023

2 participants