usb c_api: prevent exception on full ack queue

Count more accurately how much packets are in flied, and whether
new packets can be handled. Moreover, catch potential exceptions
whenever acknowledging a packet, and warn about the lost acknowledgement.

Fix genodelabs/genode#4678
This commit is contained in:
Stefan Kalkowski 2022-11-22 12:03:02 +01:00 committed by Christian Helmuth
parent 8ddd93ec27
commit 5cff81fc29

View File

@ -84,7 +84,8 @@ class genode_usb_session : public Usb::Session_rpc_object
Session_label const _label;
List_element<genode_usb_session> _le { this };
void _ack(int err, Usb::Packet_descriptor p);
unsigned _packets_in_fly();
void _ack(int err, Usb::Packet_descriptor p);
/*
* Non_copyable
@ -411,13 +412,26 @@ void genode_usb_session::release_interface(unsigned iface)
}
unsigned genode_usb_session::_packets_in_fly()
{
unsigned ret = 0;
for (unsigned idx = 0; idx < MAX_PACKETS_IN_FLY; idx++)
if (packets[idx].constructed()) ret++;
return ret;
}
void genode_usb_session::_ack(int err, Usb::Packet_descriptor p)
{
if (err == NO_ERROR)
p.succeded = true;
else
p.error = (Usb::Packet_descriptor::Error)err;
sink()->acknowledge_packet(p);
try {
sink()->acknowledge_packet(p);
} catch(...) {
warning("USB client's ack queue run full, looses packet ack!");
}
}
@ -439,15 +453,15 @@ bool genode_usb_session::request(genode_usb_request_callbacks & req, void * data
/* get next packet from request stream */
while (true) {
if (!sink()->packet_avail() || !sink()->ack_slots_free())
if (!sink()->packet_avail() ||
(sink()->ack_slots_free() <= _packets_in_fly()))
return false;
p = sink()->get_packet();
if (sink()->packet_valid(p))
break;
p.error = Packet_descriptor::PACKET_INVALID_ERROR;
sink()->acknowledge_packet(p);
_ack(Packet_descriptor::PACKET_INVALID_ERROR, p);
}
addr_t offset = (addr_t)sink()->packet_content(p) -