Skip to content

Commit aa7e0dd

Browse files
committed
TCPIP: fix stale accept futex notifications
A TCP child socket can become visible and accept-ready to `FreeRTOS_accept()` before `on_tcp_connect()` increments the accept futex. If a waiter accepts the child while the counter is zero, the old futex consume helper does not decrement it to -1, because -1 represents an invalid futex. The delayed `on_tcp_connect` callback then increments the counter to one, though no connection is pending. This leaves pending multi-waiters with a misleading futex. They will repeatedly treat the socket as ready, call `accept()`, and never block, defeating the purpose of multi-waiter waiting. Use a signed counter and always decrement after a successful accept. An early accept records a temporary negative debt that the callback later repays. Reserve INT32_MIN for an invalid futex so that normal negative debt cannot conflict with the sentinel value.
1 parent ba80e0a commit aa7e0dd

3 files changed

Lines changed: 5 additions & 5 deletions

File tree

include/NetAPI.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ enum SocketEventType : uint8_t
5151
static constexpr size_t NumFutexTypes = SocketEventType::SocketAcceptEvent + 1;
5252
/// Sentinel value stored in a socket event futex after the socket has been
5353
/// torn down.
54-
static constexpr uint32_t SocketNotAvailable = -1;
54+
static constexpr int32_t SocketNotAvailable = INT32_MIN;
5555

5656
/**
5757
* Enumeration defining the connection type.

lib/tcpip/network_wrapper.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ int SealedSocket::signal_event_futex(SocketEventType type)
405405
{
406406
return -EINVAL;
407407
}
408-
uint32_t current = futex.load();
408+
int32_t current = futex.load();
409409
while (current != SocketNotAvailable)
410410
{
411411
/*
@@ -427,8 +427,8 @@ int SealedSocket::signal_event_futex(SocketEventType type)
427427
int SealedSocket::consume_event_futex(SocketEventType type)
428428
{
429429
auto &futex = eventFutexState[type];
430-
uint32_t current = futex.load();
431-
while (current != SocketNotAvailable && current != 0)
430+
int32_t current = futex.load();
431+
while (current != SocketNotAvailable)
432432
{
433433
if (futex.compare_exchange_strong(current, current - 1))
434434
{

lib/tcpip/tcpip-internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ struct SealedSocket
4949
* feature. Different events increment different futexes in the array and
5050
* wake the corresponding waiting threads.
5151
*/
52-
std::atomic<uint32_t> eventFutexState[NumFutexTypes];
52+
std::atomic<int32_t> eventFutexState[NumFutexTypes];
5353
/**
5454
* Increments the futex and notifies all waiters if the futex is still
5555
* valid.

0 commit comments

Comments
 (0)