linux_nic_drv: stop receiver thread on congested queue

Otherwise, the thread spins on and drops packets.
This commit is contained in:
Christian Helmuth 2020-05-25 18:22:54 +02:00 committed by Norman Feske
parent c6b17be744
commit 420ed91480

View File

@ -36,6 +36,7 @@
#include <base/heap.h> #include <base/heap.h>
#include <base/thread.h> #include <base/thread.h>
#include <base/log.h> #include <base/log.h>
#include <base/blockade.h>
#include <nic/root.h> #include <nic/root.h>
/* Linux */ /* Linux */
@ -61,6 +62,7 @@ class Linux_session_component : public Nic::Session_component
{ {
int fd; int fd;
Genode::Signal_context_capability sigh; Genode::Signal_context_capability sigh;
Genode::Blockade blockade { };
Rx_signal_thread(Genode::Env &env, int fd, Genode::Signal_context_capability sigh) Rx_signal_thread(Genode::Env &env, int fd, Genode::Signal_context_capability sigh)
: Genode::Thread(env, "rx_signal", 0x1000), fd(fd), sigh(sigh) { } : Genode::Thread(env, "rx_signal", 0x1000), fd(fd), sigh(sigh) { }
@ -78,6 +80,8 @@ class Linux_session_component : public Nic::Session_component
/* signal incoming packet */ /* signal incoming packet */
Genode::Signal_transmitter(sigh).submit(); Genode::Signal_transmitter(sigh).submit();
blockade.block();
} }
} }
}; };
@ -169,40 +173,60 @@ class Linux_session_component : public Nic::Session_component
return true; return true;
} }
bool _receive() enum class Receive_result {
NO_PACKET, READ_ERROR, SUBMITTED, ALLOC_FAILED, SUBMIT_QUEUE_FULL };
Receive_result _receive()
{ {
unsigned const max_size = Nic::Packet_allocator::DEFAULT_PACKET_SIZE; unsigned const max_size = Nic::Packet_allocator::DEFAULT_PACKET_SIZE;
if (!_rx.source()->ready_to_submit()) if (!_rx.source()->ready_to_submit())
return false; return Receive_result::SUBMIT_QUEUE_FULL;
Nic::Packet_descriptor p; Nic::Packet_descriptor p;
try { try {
p = _rx.source()->alloc_packet(max_size); p = _rx.source()->alloc_packet(max_size);
} catch (Session::Rx::Source::Packet_alloc_failed) { return false; } } catch (Session::Rx::Source::Packet_alloc_failed) { return Receive_result::ALLOC_FAILED; }
int size = read(_tap_fd, _rx.source()->packet_content(p), max_size); int size = read(_tap_fd, _rx.source()->packet_content(p), max_size);
if (size <= 0) { if (size <= 0) {
_rx.source()->release_packet(p); _rx.source()->release_packet(p);
return false; return errno == EAGAIN ? Receive_result::NO_PACKET
: Receive_result::READ_ERROR;
} }
/* adjust packet size */ /* adjust packet size */
Nic::Packet_descriptor p_adjust(p.offset(), size); Nic::Packet_descriptor p_adjust(p.offset(), size);
_rx.source()->submit_packet(p_adjust); _rx.source()->submit_packet(p_adjust);
return true; return Receive_result::SUBMITTED;
} }
protected: protected:
bool _handle_incoming_packets()
{
while (true) {
switch (_receive()) {
case Receive_result::NO_PACKET: return true;
case Receive_result::READ_ERROR: return true;
case Receive_result::SUBMITTED: continue;
case Receive_result::ALLOC_FAILED: return false;
case Receive_result::SUBMIT_QUEUE_FULL: return false;
}
}
}
void _handle_packet_stream() override void _handle_packet_stream() override
{ {
while (_rx.source()->ack_avail()) while (_rx.source()->ack_avail()) {
_rx.source()->release_packet(_rx.source()->get_acked_packet()); _rx.source()->release_packet(_rx.source()->get_acked_packet());
}
while (_send()) ; while (_send()) ;
while (_receive()) ;
if (_handle_incoming_packets())
_rx_thread.blockade.wakeup();
} }
public: public: