Skip to content

Commit

Permalink
BusABC.recv: keep calling _recv_internal until it returns None
Browse files Browse the repository at this point in the history
Even if recv() is called with timeout=0, the caller's intention is
probably for recv() to check all of the messages that have already
arrived at the interface until one of them matches the filters.

This is already the way recv() behaves for interface drivers that take
advantage of hardware or OS-level filtering, but those that use BusABC's
default software-based filtering might return None even if a matching
message has already arrived.
  • Loading branch information
malsyned committed Oct 27, 2023
1 parent 38c4dc4 commit 5f174f5
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 11 deletions.
20 changes: 9 additions & 11 deletions can/bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,19 +120,17 @@ def recv(self, timeout: Optional[float] = None) -> Optional[Message]:
# try to get a message
msg, already_filtered = self._recv_internal(timeout=time_left)

# return it, if it matches
if msg and (already_filtered or self._matches_filters(msg)):
LOG.log(self.RECV_LOGGING_LEVEL, "Received: %s", msg)
return msg

# if not, and timeout is None, try indefinitely
elif timeout is None:
if msg:
# return it, if it matches
if already_filtered or self._matches_filters(msg):
LOG.log(self.RECV_LOGGING_LEVEL, "Received: %s", msg)
return msg
# if not, keep trying
continue

# try next one only if there still is time, and with
# reduced timeout
else:
time_left = timeout - (time() - start)
# try again only if there still is time, and with reduced timeout
if timeout is not None:
time_left = max(0, timeout - (time() - start))

if time_left > 0:
continue
Expand Down
12 changes: 12 additions & 0 deletions test/test_message_filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ def test_match_example_message(self):
self.assertFalse(self.bus._matches_filters(EXAMPLE_MSG))
self.assertTrue(self.bus._matches_filters(HIGHEST_MSG))

def test_empty_queue_up_to_match(self):
self.bus.set_filters(MATCH_EXAMPLE)
bus2 = Bus(interface="virtual", channel="testy")
bus2.send(HIGHEST_MSG)
bus2.send(EXAMPLE_MSG)
actual = self.bus.recv(timeout=0)
self.assertTrue(
EXAMPLE_MSG.equals(
actual, timestamp_delta=None, check_direction=False, check_channel=False
)
)


if __name__ == "__main__":
unittest.main()

0 comments on commit 5f174f5

Please sign in to comment.