Service: Sockets: Fix busy-waiting CPU starvation and Close/Socket race conditions

This commit is contained in:
collecting
2026-01-16 17:42:54 -05:00
parent 31d0bca2da
commit 0b5701624a
3 changed files with 81 additions and 45 deletions

View File

@@ -531,6 +531,9 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type");
type = static_cast<Type>(static_cast<u32>(type) & ~0x20000000);
// Lock the table before searching for or creating a descriptor
std::lock_guard table_lock(fd_table_mutex);
const s32 fd = FindFreeFileDescriptorHandle();
if (fd < 0) {
LOG_ERROR(Service, "No more file descriptors available");
@@ -539,7 +542,6 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
file_descriptors[fd] = FileDescriptor{};
FileDescriptor& descriptor = *file_descriptors[fd];
// ENONMEM might be thrown here
auto room_member = room_network.GetRoomMember().lock();
const bool using_proxy = room_member && room_member->IsConnected();
@@ -547,23 +549,21 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
LOG_INFO(Service, "New socket fd={} domain={} type={} protocol={} proxy={}",
fd, domain, type, protocol, using_proxy);
// Store socket type information for pooling
descriptor.domain = Translate(domain);
descriptor.type = Translate(type);
descriptor.protocol = Translate(protocol);
descriptor.is_connection_based = IsConnectionBased(type);
// Try to reuse a socket from the pool if using proxy
if (using_proxy) {
SocketPoolKey key{descriptor.domain, descriptor.type, descriptor.protocol};
std::lock_guard lock(socket_pool_mutex);
std::lock_guard pool_lock(socket_pool_mutex);
auto it = socket_pool.find(key);
if (it != socket_pool.end() && !it->second.empty()) {
descriptor.socket = it->second.back();
it->second.pop_back();
// call Initialize here so socket_proxy.cpp functions work
// Reset the socket state so 'closed' is false and the queue is empty
descriptor.socket->Initialize(descriptor.domain, descriptor.type, descriptor.protocol);
LOG_DEBUG(Service, "Reused socket from pool for fd={}", fd);