Merge pull request #12560 from sepalani/bba-poll

BBA/HLE: Increase polling efficiency
This commit is contained in:
Admiral H. Curtiss 2024-05-04 17:43:24 +02:00 committed by GitHub
commit 1b19a75600
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 67 additions and 23 deletions

View File

@ -128,6 +128,13 @@ void CEXIETHERNET::BuiltInBBAInterface::WriteToQueue(const std::vector<u8>& data
const u8 next_write_index = (m_queue_write + 1) & 15; const u8 next_write_index = (m_queue_write + 1) & 15;
if (next_write_index != m_queue_read) if (next_write_index != m_queue_read)
m_queue_write = next_write_index; m_queue_write = next_write_index;
else
WARN_LOG_FMT(SP1, "BBA queue overrun, data might be lost");
}
bool CEXIETHERNET::BuiltInBBAInterface::WillQueueOverrun() const
{
return ((m_queue_write + 1) & 15) == m_queue_read;
} }
void CEXIETHERNET::BuiltInBBAInterface::PollData(std::size_t* datasize) void CEXIETHERNET::BuiltInBBAInterface::PollData(std::size_t* datasize)
@ -142,24 +149,39 @@ void CEXIETHERNET::BuiltInBBAInterface::PollData(std::size_t* datasize)
{ {
for (auto& tcp_buf : net_ref.tcp_buffers) for (auto& tcp_buf : net_ref.tcp_buffers)
{ {
if (WillQueueOverrun())
break;
if (!tcp_buf.used || (GetTickCountStd() - tcp_buf.tick) <= 1000) if (!tcp_buf.used || (GetTickCountStd() - tcp_buf.tick) <= 1000)
continue; continue;
tcp_buf.tick = GetTickCountStd();
// Timed out packet, resend // Timed out packet, resend
if (((m_queue_write + 1) & 15) != m_queue_read) tcp_buf.tick = GetTickCountStd();
WriteToQueue(tcp_buf.data); WriteToQueue(tcp_buf.data);
} }
} }
// Check for connection data // Check for connection data
if (*datasize != 0) if (*datasize == 0)
continue;
const auto socket_data = TryGetDataFromSocket(&net_ref);
if (socket_data.has_value())
{ {
*datasize = socket_data->size(); // Send it to the network buffer if empty
std::memcpy(m_eth_ref->mRecvBuffer.get(), socket_data->data(), *datasize); const auto socket_data = TryGetDataFromSocket(&net_ref);
if (socket_data.has_value())
{
*datasize = socket_data->size();
std::memcpy(m_eth_ref->mRecvBuffer.get(), socket_data->data(), *datasize);
}
}
else if (!WillQueueOverrun())
{
// Otherwise, enqueue it
const auto socket_data = TryGetDataFromSocket(&net_ref);
if (socket_data.has_value())
WriteToQueue(*socket_data);
}
else
{
WARN_LOG_FMT(SP1, "BBA queue might overrun, can't poll more data");
return;
} }
} }
} }
@ -226,7 +248,7 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleDHCP(const Common::UDPPacket& pack
std::optional<std::vector<u8>> std::optional<std::vector<u8>>
CEXIETHERNET::BuiltInBBAInterface::TryGetDataFromSocket(StackRef* ref) CEXIETHERNET::BuiltInBBAInterface::TryGetDataFromSocket(StackRef* ref)
{ {
size_t datasize = 0; // Set by socket.receive using a non-const reference std::size_t datasize = 0; // Set by socket.receive using a non-const reference
unsigned short remote_port; unsigned short remote_port;
switch (ref->type) switch (ref->type)
@ -249,8 +271,24 @@ CEXIETHERNET::BuiltInBBAInterface::TryGetDataFromSocket(StackRef* ref)
} }
case IPPROTO_TCP: case IPPROTO_TCP:
if (!ref->tcp_socket.Connected(ref)) switch (ref->tcp_socket.Connected(ref))
{
case BbaTcpSocket::ConnectingState::Error:
{
// Create the resulting RST ACK packet
const Common::TCPPacket result(ref->bba_mac, ref->my_mac, ref->from, ref->to, ref->seq_num,
ref->ack_num, TCP_FLAG_RST | TCP_FLAG_ACK);
WriteToQueue(result.Build());
ref->ip = 0;
ref->tcp_socket.disconnect();
[[fallthrough]];
}
case BbaTcpSocket::ConnectingState::None:
case BbaTcpSocket::ConnectingState::Connecting:
return std::nullopt; return std::nullopt;
case BbaTcpSocket::ConnectingState::Connected:
break;
}
sf::Socket::Status st = sf::Socket::Status::Done; sf::Socket::Status st = sf::Socket::Status::Done;
TcpBuffer* tcp_buffer = nullptr; TcpBuffer* tcp_buffer = nullptr;
@ -374,7 +412,7 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket&
{ {
// only if contain data // only if contain data
if (static_cast<int>(this_seq - ref->ack_num) >= 0 && if (static_cast<int>(this_seq - ref->ack_num) >= 0 &&
data.size() >= static_cast<size_t>(size)) data.size() >= static_cast<std::size_t>(size))
{ {
ref->tcp_socket.send(data.data(), size); ref->tcp_socket.send(data.data(), size);
ref->ack_num += size; ref->ack_num += size;
@ -658,14 +696,17 @@ bool CEXIETHERNET::BuiltInBBAInterface::SendFrame(const u8* frame, u32 size)
void CEXIETHERNET::BuiltInBBAInterface::ReadThreadHandler(CEXIETHERNET::BuiltInBBAInterface* self) void CEXIETHERNET::BuiltInBBAInterface::ReadThreadHandler(CEXIETHERNET::BuiltInBBAInterface* self)
{ {
std::size_t datasize = 0;
while (!self->m_read_thread_shutdown.IsSet()) while (!self->m_read_thread_shutdown.IsSet())
{ {
// make thread less cpu hungry if (datasize == 0)
std::this_thread::sleep_for(std::chrono::milliseconds(1)); {
// Make thread less CPU hungry
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
if (!self->m_read_enabled.IsSet()) if (!self->m_read_enabled.IsSet())
continue; continue;
size_t datasize = 0;
u8 wp = self->m_eth_ref->page_ptr(BBA_RWP); u8 wp = self->m_eth_ref->page_ptr(BBA_RWP);
const u8 rp = self->m_eth_ref->page_ptr(BBA_RRP); const u8 rp = self->m_eth_ref->page_ptr(BBA_RRP);
@ -691,6 +732,10 @@ void CEXIETHERNET::BuiltInBBAInterface::ReadThreadHandler(CEXIETHERNET::BuiltInB
self->m_queue_read++; self->m_queue_read++;
self->m_queue_read &= 15; self->m_queue_read &= 15;
} }
else
{
datasize = 0;
}
// Check network stack references // Check network stack references
self->PollData(&datasize); self->PollData(&datasize);
@ -777,14 +822,11 @@ sf::Socket::Status BbaTcpSocket::GetSockName(sockaddr_in* addr) const
return sf::Socket::Status::Done; return sf::Socket::Status::Done;
} }
bool BbaTcpSocket::Connected(StackRef* ref) BbaTcpSocket::ConnectingState BbaTcpSocket::Connected(StackRef* ref)
{ {
// Called by ReadThreadHandler's TryGetDataFromSocket // Called by ReadThreadHandler's TryGetDataFromSocket
// TODO: properly handle error state
switch (m_connecting_state) switch (m_connecting_state)
{ {
case ConnectingState::Connected:
return true;
case ConnectingState::Connecting: case ConnectingState::Connecting:
{ {
const int fd = getHandle(); const int fd = getHandle();
@ -814,6 +856,7 @@ bool BbaTcpSocket::Connected(StackRef* ref)
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) != 0) if (getsockopt(fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) != 0)
{ {
ERROR_LOG_FMT(SP1, "Failed to get BBA socket error state: {}", Common::StrNetworkError()); ERROR_LOG_FMT(SP1, "Failed to get BBA socket error state: {}", Common::StrNetworkError());
m_connecting_state = ConnectingState::Error;
break; break;
} }
@ -858,7 +901,7 @@ bool BbaTcpSocket::Connected(StackRef* ref)
default: default:
break; break;
} }
return false; return m_connecting_state;
} }
BbaUdpSocket::BbaUdpSocket() = default; BbaUdpSocket::BbaUdpSocket() = default;

View File

@ -48,9 +48,6 @@ public:
sf::Socket::Status GetPeerName(sockaddr_in* addr) const; sf::Socket::Status GetPeerName(sockaddr_in* addr) const;
sf::Socket::Status GetSockName(sockaddr_in* addr) const; sf::Socket::Status GetSockName(sockaddr_in* addr) const;
bool Connected(StackRef* ref);
private:
enum class ConnectingState enum class ConnectingState
{ {
None, None,
@ -59,6 +56,9 @@ private:
Error Error
}; };
ConnectingState Connected(StackRef* ref);
private:
ConnectingState m_connecting_state = ConnectingState::None; ConnectingState m_connecting_state = ConnectingState::None;
}; };

View File

@ -463,6 +463,7 @@ private:
static void ReadThreadHandler(BuiltInBBAInterface* self); static void ReadThreadHandler(BuiltInBBAInterface* self);
#endif #endif
void WriteToQueue(const std::vector<u8>& data); void WriteToQueue(const std::vector<u8>& data);
bool WillQueueOverrun() const;
void PollData(std::size_t* datasize); void PollData(std::size_t* datasize);
std::optional<std::vector<u8>> TryGetDataFromSocket(StackRef* ref); std::optional<std::vector<u8>> TryGetDataFromSocket(StackRef* ref);