udp:Resolve UDP exit delay due to high CPU usage

Optimize the processing logic of UDP TXDrain, reduce thread switching,
and improve timeliness and CPU consumption.

Signed-off-by: wangchen <wangchen41@xiaomi.com>
This commit is contained in:
wangchen 2025-05-29 09:32:59 +08:00 committed by Xiang Xiao
parent 51743c55b2
commit f8ecbd781c
4 changed files with 13 additions and 195 deletions

View file

@ -162,6 +162,7 @@ struct udp_conn_s
#ifdef CONFIG_NET_TIMESTAMP
int timestamp; /* Nonzero when SO_TIMESTAMP is enabled */
#endif
FAR sem_t *txdrain_sem;
};
/* This structure supports UDP write buffering. It is simply a container
@ -837,38 +838,6 @@ int udp_readahead_notifier_setup(worker_t worker,
FAR void *arg);
#endif
/****************************************************************************
* Name: udp_writebuffer_notifier_setup
*
* Description:
* Set up to perform a callback to the worker function when an UDP write
* buffer is emptied. The worker function will execute on the high
* priority worker thread.
*
* Input Parameters:
* worker - The worker function to execute on the low priority work
* queue when data is available in the UDP read-ahead buffer.
* conn - The UDP connection where read-ahead data is needed.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The notification is in place. The returned value is a key that
* may be used later in a call to udp_notifier_teardown().
* == 0 - There is already buffered read-ahead data. No notification
* will be provided.
* < 0 - An unexpected error occurred and no notification will occur.
* The returned value is a negated errno value that indicates the
* nature of the failure.
*
****************************************************************************/
#ifdef CONFIG_NET_UDP_NOTIFIER
int udp_writebuffer_notifier_setup(worker_t worker,
FAR struct udp_conn_s *conn,
FAR void *arg);
#endif
/****************************************************************************
* Name: udp_notifier_teardown
*
@ -915,31 +884,6 @@ void udp_notifier_teardown(FAR void *key);
void udp_readahead_signal(FAR struct udp_conn_s *conn);
#endif
/****************************************************************************
* Name: udp_writebuffer_signal
*
* Description:
* All buffer Tx data has been sent. Signal all threads waiting for the
* write buffers to become empty.
*
* When write buffer becomes empty, *all* of the workers waiting
* for that event data will be executed. If there are multiple workers
* waiting for read-ahead data then only the first to execute will get the
* data. Others will need to call udp_writebuffer_notifier_setup() once
* again.
*
* Input Parameters:
* conn - The UDP connection where read-ahead data was just buffered.
*
* Returned Value:
* None.
*
****************************************************************************/
#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_NET_UDP_NOTIFIER)
void udp_writebuffer_signal(FAR struct udp_conn_s *conn);
#endif
/****************************************************************************
* Name: udp_txdrain
*

View file

@ -94,64 +94,6 @@ int udp_readahead_notifier_setup(worker_t worker,
return work_notifier_setup(&info);
}
/****************************************************************************
* Name: udp_writebuffer_notifier_setup
*
* Description:
* Set up to perform a callback to the worker function when an UDP write
* buffer is emptied. The worker function will execute on the high
* priority worker thread.
*
* Input Parameters:
* worker - The worker function to execute on the low priority work
* queue when data is available in the UDP read-ahead buffer.
* conn - The UDP connection where read-ahead data is needed.
* arg - A user-defined argument that will be available to the worker
* function when it runs.
*
* Returned Value:
* > 0 - The notification is in place. The returned value is a key that
* may be used later in a call to udp_notifier_teardown().
* == 0 - There is already buffered read-ahead data. No notification
* will be provided.
* < 0 - An unexpected error occurred and no notification will occur.
* The returned value is a negated errno value that indicates the
* nature of the failure.
*
****************************************************************************/
int udp_writebuffer_notifier_setup(worker_t worker,
FAR struct udp_conn_s *conn,
FAR void *arg)
{
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
struct work_notifier_s info;
DEBUGASSERT(worker != NULL);
/* If there is already buffered read-ahead data, then return zero without
* setting up the notification.
*/
if (sq_empty(&conn->write_q))
{
return 0;
}
/* Otherwise, this is just a simple wrapper around work_notifer_setup(). */
info.evtype = WORK_UDP_WRITEBUFFER;
info.qid = LPWORK;
info.qualifier = conn;
info.arg = arg;
info.worker = worker;
return work_notifier_setup(&info);
#else
return 0;
#endif
}
/****************************************************************************
* Name: udp_notifier_teardown
*
@ -205,34 +147,4 @@ void udp_readahead_signal(FAR struct udp_conn_s *conn)
work_notifier_signal(WORK_UDP_READAHEAD, conn);
}
/****************************************************************************
* Name: udp_writebuffer_signal
*
* Description:
* All buffer Tx data has been sent. Signal all threads waiting for the
* write buffers to become empty.
*
* When write buffer becomes empty, *all* of the workers waiting
* for that event data will be executed. If there are multiple workers
* waiting for read-ahead data then only the first to execute will get the
* data. Others will need to call tcp_writebuffer_notifier_setup() once
* again.
*
* Input Parameters:
* conn - The UDP connection where read-ahead data was just buffered.
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
void udp_writebuffer_signal(FAR struct udp_conn_s *conn)
{
/* This is just a simple wrapper around work_notifier_signal(). */
work_notifier_signal(WORK_UDP_WRITEBUFFER, conn);
}
#endif
#endif /* CONFIG_NET_UDP_NOTIFIER */

View file

@ -138,11 +138,14 @@ static void sendto_writebuffer_release(FAR struct udp_conn_s *conn)
conn->sndcb->event = NULL;
wrb = NULL;
#ifdef CONFIG_NET_UDP_NOTIFIER
/* Notify any waiters that the write buffers have been drained. */
if (conn->txdrain_sem != NULL)
{
/* Notify the txdrain semaphore that the write buffer queue
* has been drained.
*/
udp_writebuffer_signal(conn);
#endif
nxsem_post(conn->txdrain_sem);
}
}
else
{

View file

@ -41,35 +41,6 @@
#if defined(CONFIG_NET_UDP_WRITE_BUFFERS) && defined(CONFIG_NET_UDP_NOTIFIER)
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: txdrain_worker
*
* Description:
* Called with the write buffers have all been sent.
*
* Input Parameters:
* arg - The notifier entry.
*
* Returned Value:
* None.
*
****************************************************************************/
static void txdrain_worker(FAR void *arg)
{
FAR sem_t *waitsem = (FAR sem_t *)arg;
DEBUGASSERT(waitsem != NULL);
/* Then just post the semaphore, waking up tcp_txdrain() */
nxsem_post(waitsem);
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -94,7 +65,7 @@ int udp_txdrain(FAR struct socket *psock, unsigned int timeout)
{
FAR struct udp_conn_s *conn;
sem_t waitsem;
int ret;
int ret = OK;
DEBUGASSERT(psock->s_type == SOCK_DGRAM);
@ -111,24 +82,12 @@ int udp_txdrain(FAR struct socket *psock, unsigned int timeout)
/* The following needs to be done with the network stable */
net_lock();
ret = udp_writebuffer_notifier_setup(txdrain_worker, conn, &waitsem);
if (ret > 0)
if (!sq_empty(&conn->write_q))
{
int key = ret;
/* There is pending write data.. wait for it to drain. */
tls_cleanup_push(tls_get_info(), udp_notifier_teardown, &key);
conn->txdrain_sem = &waitsem;
ret = net_sem_timedwait_uninterruptible(&waitsem, timeout);
/* Tear down the notifier (in case we timed out or were canceled) */
if (ret < 0)
{
udp_notifier_teardown(&key);
}
tls_cleanup_pop(tls_get_info(), 0);
conn->txdrain_sem = NULL;
}
net_unlock();