Skip to content

Commit fc7e8c2

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 fc7e8c2

File tree

2 files changed

+19
-15
lines changed

2 files changed

+19
-15
lines changed

can/bus.py

+8-15
Original file line numberDiff line numberDiff line change
@@ -119,26 +119,19 @@ def recv(self, timeout: Optional[float] = None) -> Optional[Message]:
119119
while True:
120120
# try to get a message
121121
msg, already_filtered = self._recv_internal(timeout=time_left)
122+
time_left = timeout - (time() - start)
123+
124+
if msg is None:
125+
# if timeout is None or there is still time, try again
126+
if timeout is None or time_left > 0:
127+
continue
128+
return None
122129

123130
# return it, if it matches
124-
if msg and (already_filtered or self._matches_filters(msg)):
131+
if already_filtered or self._matches_filters(msg):
125132
LOG.log(self.RECV_LOGGING_LEVEL, "Received: %s", msg)
126133
return msg
127134

128-
# if not, and timeout is None, try indefinitely
129-
elif timeout is None:
130-
continue
131-
132-
# try next one only if there still is time, and with
133-
# reduced timeout
134-
else:
135-
time_left = timeout - (time() - start)
136-
137-
if time_left > 0:
138-
continue
139-
140-
return None
141-
142135
def _recv_internal(
143136
self, timeout: Optional[float]
144137
) -> Tuple[Optional[Message], bool]:

test/test_message_filtering.py

+11
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ 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(EXAMPLE_MSG.equals(actual,
56+
timestamp_delta=None,
57+
check_direction=False,
58+
check_channel=False))
59+
4960

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

0 commit comments

Comments
 (0)