Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/core/dev/ring_slave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
// AF_INET address 0.0.0.0:0, used for 3T flow spec keys.
static const sock_addr s_sock_addrany;

static thread_local lock_dummy t_lock_dummy_ring;
static padded_lock_dummy g_lock_dummy_ring;

static lock_base *get_new_lock(const char *name, bool real_lock)
{
return (real_lock
? static_cast<lock_base *>(multilock::create_new_lock(MULTILOCK_RECURSIVE, name))
: static_cast<lock_base *>(&t_lock_dummy_ring));
: static_cast<lock_base *>(&g_lock_dummy_ring.lock));
}

ring_slave::ring_slave(int if_index, ring *parent, ring_type_t type, bool use_locks)
Expand Down
5 changes: 3 additions & 2 deletions src/core/sock/sockinfo_tcp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ extern global_stats_t g_global_stat_static;
tcp_timers_collection *g_tcp_timers_collection = nullptr;
thread_local thread_local_tcp_timers g_thread_local_tcp_timers;
bind_no_port *g_bind_no_port = nullptr;
static thread_local lock_dummy t_lock_dummy_socket;

static padded_lock_dummy g_lock_dummy_socket;

/*
* The following socket options are inherited by a connected TCP socket from the listening socket:
Expand Down Expand Up @@ -137,7 +138,7 @@ static lock_base *get_new_tcp_lock()
return (
safe_mce_sys().tcp_ctl_thread != option_tcp_ctl_thread::CTL_THREAD_DELEGATE_TCP_TIMERS
? static_cast<lock_base *>(multilock::create_new_lock(MULTILOCK_RECURSIVE, "tcp_con"))
: static_cast<lock_base *>(&t_lock_dummy_socket));
: static_cast<lock_base *>(&g_lock_dummy_socket.lock));
}

inline void sockinfo_tcp::lwip_pbuf_init_custom(mem_buf_desc_t *p_desc)
Expand Down
8 changes: 8 additions & 0 deletions src/utils/lock_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,14 @@ class lock_dummy : public lock_base {
int is_locked_by_me() override { return 1; }
};

// Users of lock_dummy may wish to alignas(64) to place this lock in in a different cache-line and
// prevent false sharing
struct alignas(64) padded_lock_dummy {
lock_dummy lock;
// Padding to fill a full cache line
char padding[64 - sizeof(lock_dummy)];
};

static inline void lock_deleter_func(lock_base *lock)
{
lock->delete_obj();
Expand Down
27 changes: 26 additions & 1 deletion tests/gtest/tcp/tcp_socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "common/sys.h"
#include "common/base.h"
#include "tcp_base.h"

#include <thread>
class tcp_socket : public tcp_base {};

/**
Expand Down Expand Up @@ -125,3 +125,28 @@ TEST_F(tcp_socket, ti_2_ipv6only_listen_all)
test_lambda(true);
test_lambda(false);
}

/**
* @test tcp_socket.ti_3_socket_closed_different_thread_works
* @brief
* Test that a socket can be closed after its creator thread terminates
* @details
* Creates a socket in a separate thread, then closes it from the main thread
* after the creator thread has terminated. This verifies that socket cleanup
* works correctly across thread boundaries.
*/
TEST_F(tcp_socket, ti_3_socket_closed_different_thread_works)
{
int fd = -1;

std::thread t([&fd]() {
fd = socket(m_family, SOCK_STREAM, IPPROTO_IP);
EXPECT_LE(0, fd);
EXPECT_EQ(errno, EOK);
});

t.join();

EXPECT_LE(0, fd);
close(fd);
}