mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 13:47:56 +00:00
nic_router: packet allocation w/o exceptions
In overload situations, i.e. when a sender fills up the entire buffer, we land in situations where the sender receives an ack_avail signal, releases one packet, allocates and sends a packet and fails to allocate a second packet. This is especially relevant if the receiver does not batch ack_avail signals (such as vfs_lwip). In those ping-pong scheduling scenarios, the overhead from catching the Packet_alloc_failed exception becomes significant. In case of the NIC router, we will land in an overload situation if the sender is faster than the receiver. The packet buffer will be filled up at some point and the NIC router starts to drop packets. For every dropped packet, we currently have to catch the Packet_alloc_failed exception. This commit adds a new method alloc_packet_attempt to Packet_stream_source that has almost the same signature as the older alloc_packet method but returns an Attempt<Packet_descriptor, Alloc_packet_error> object. As the method already used the allocator back end exception-less, changes on lower levels were not needed. Furthermore, the NIC router was modified to use the new exception-less alloc_packet_attempt instead of alloc_packet. Ref #4555
This commit is contained in:
parent
3f69457a94
commit
e32157e21b
@ -639,6 +639,10 @@ class Genode::Packet_stream_source : private Packet_stream_base
|
||||
class Saturated_submit_queue : Exception { };
|
||||
class Empty_ack_queue : Exception { };
|
||||
|
||||
enum class Alloc_packet_error { FAILED };
|
||||
|
||||
using Alloc_packet_result = Attempt<Packet_descriptor, Alloc_packet_error>;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -726,6 +730,29 @@ class Genode::Packet_stream_source : private Packet_stream_base
|
||||
throw Packet_alloc_failed(); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate packet without throwing exceptions
|
||||
*
|
||||
* \param size size of packet in bytes
|
||||
* \param align alignment of packet as log2 value, default is 1 byte
|
||||
* \return an Attempt object that either contains an error or a
|
||||
* packet descriptor with an assigned range within the
|
||||
* bulk buffer shared between source and sink
|
||||
*/
|
||||
Alloc_packet_result alloc_packet_attempt(Genode::size_t size, unsigned align = PACKET_ALIGNMENT)
|
||||
{
|
||||
if (size == 0)
|
||||
return Packet_descriptor(0, 0);
|
||||
|
||||
return _packet_alloc.alloc_aligned(size, align).convert<Alloc_packet_result>(
|
||||
|
||||
[&] (void *base) {
|
||||
return Packet_descriptor((Genode::off_t)base, size); },
|
||||
|
||||
[&] (Allocator::Alloc_error) {
|
||||
return Alloc_packet_error::FAILED; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pointer to the content of the specified packet
|
||||
*
|
||||
|
@ -1850,15 +1850,6 @@ void Interface::send(Ethernet_frame ð,
|
||||
}
|
||||
|
||||
|
||||
void Interface::_send_alloc_pkt(Packet_descriptor &pkt,
|
||||
void * &pkt_base,
|
||||
size_t pkt_size)
|
||||
{
|
||||
pkt = _source.alloc_packet(pkt_size);
|
||||
pkt_base = _source.packet_content(pkt);
|
||||
}
|
||||
|
||||
|
||||
void Interface::_send_submit_pkt(Packet_descriptor &pkt,
|
||||
void * &pkt_base,
|
||||
size_t pkt_size)
|
||||
|
@ -307,10 +307,6 @@ class Net::Interface : private Interface_list::Element
|
||||
|
||||
void _ack_packet(Packet_descriptor const &pkt);
|
||||
|
||||
void _send_alloc_pkt(Genode::Packet_descriptor &pkt,
|
||||
void * &pkt_base,
|
||||
Genode::size_t pkt_size);
|
||||
|
||||
void _send_submit_pkt(Genode::Packet_descriptor &pkt,
|
||||
void * &pkt_base,
|
||||
Genode::size_t pkt_size);
|
||||
@ -402,18 +398,19 @@ class Net::Interface : private Interface_list::Element
|
||||
_failed_to_send_packet_submit();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Packet_descriptor pkt;
|
||||
void *pkt_base;
|
||||
|
||||
_send_alloc_pkt(pkt, pkt_base, pkt_size);
|
||||
Size_guard size_guard(pkt_size);
|
||||
write_to_pkt(pkt_base, size_guard);
|
||||
_send_submit_pkt(pkt, pkt_base, pkt_size);
|
||||
}
|
||||
catch (Packet_stream_source::Packet_alloc_failed) {
|
||||
_failed_to_send_packet_alloc();
|
||||
}
|
||||
_source.alloc_packet_attempt(pkt_size).with_result(
|
||||
[&] (Packet_descriptor pkt)
|
||||
{
|
||||
void *pkt_base { _source.packet_content(pkt) };
|
||||
Size_guard size_guard(pkt_size);
|
||||
write_to_pkt(pkt_base, size_guard);
|
||||
_send_submit_pkt(pkt, pkt_base, pkt_size);
|
||||
},
|
||||
[&] (Packet_stream_source::Alloc_packet_error)
|
||||
{
|
||||
_failed_to_send_packet_alloc();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void send(Ethernet_frame ð,
|
||||
|
Loading…
Reference in New Issue
Block a user