Skip to content

Commit 5f174f5

Browse files
committed
BusABC.recv: keep calling _recv_internal until it returns None
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.
1 parent 38c4dc4 commit 5f174f5

File tree

2 files changed

+21
-11
lines changed

2 files changed

+21
-11
lines changed

can/bus.py

+9-11
Original file line numberDiff line numberDiff line change
@@ -120,19 +120,17 @@ def recv(self, timeout: Optional[float] = None) -> Optional[Message]:
120120
# try to get a message
121121
msg, already_filtered = self._recv_internal(timeout=time_left)
122122

123-
# return it, if it matches
124-
if msg and (already_filtered or self._matches_filters(msg)):
125-
LOG.log(self.RECV_LOGGING_LEVEL, "Received: %s", msg)
126-
return msg
127-
128-
# if not, and timeout is None, try indefinitely
129-
elif timeout is None:
123+
if msg:
124+
# return it, if it matches
125+
if already_filtered or self._matches_filters(msg):
126+
LOG.log(self.RECV_LOGGING_LEVEL, "Received: %s", msg)
127+
return msg
128+
# if not, keep trying
130129
continue
131130

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

137135
if time_left > 0:
138136
continue

test/test_message_filtering.py

+12
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ def test_match_example_message(self):
4646
self.assertFalse(self.bus._matches_filters(EXAMPLE_MSG))
4747
self.assertTrue(self.bus._matches_filters(HIGHEST_MSG))
4848

49+
def test_empty_queue_up_to_match(self):
50+
self.bus.set_filters(MATCH_EXAMPLE)
51+
bus2 = Bus(interface="virtual", channel="testy")
52+
bus2.send(HIGHEST_MSG)
53+
bus2.send(EXAMPLE_MSG)
54+
actual = self.bus.recv(timeout=0)
55+
self.assertTrue(
56+
EXAMPLE_MSG.equals(
57+
actual, timestamp_delta=None, check_direction=False, check_channel=False
58+
)
59+
)
60+
4961

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

0 commit comments

Comments
 (0)