From fc35cf4737b2576224b3aeea148bf9739ff85478 Mon Sep 17 00:00:00 2001 From: zhanghongyu Date: Sat, 25 Jun 2022 19:53:50 +0800 Subject: [PATCH] udp: Use s_sndtimeo as the actual timeout time Signed-off-by: zhanghongyu --- net/udp/udp.h | 22 ++++++++++++ net/udp/udp_sendto_buffered.c | 26 ++++++++++++-- net/udp/udp_wrbuffer.c | 66 ++++++++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/net/udp/udp.h b/net/udp/udp.h index 966183f44f..b4bcdf52f4 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -472,6 +472,28 @@ struct udp_wrbuffer_s; FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void); #endif /* CONFIG_NET_UDP_WRITE_BUFFERS */ +/**************************************************************************** + * Name: udp_wrbuffer_timedalloc + * + * Description: + * Allocate a UDP write buffer by taking a pre-allocated buffer from + * the free list. This function is called from udp logic when a buffer + * of udp data is about to sent + * This function is wrapped version of udp_wrbuffer_alloc(), + * this wait will be terminated when the specified timeout expires. + * + * Input Parameters: + * timeout - The relative time to wait until a timeout is declared. + * + * Assumptions: + * Called from user logic with the network locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP_WRITE_BUFFERS +FAR struct udp_wrbuffer_s *udp_wrbuffer_timedalloc(unsigned int timeout); +#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */ + /**************************************************************************** * Name: udp_wrbuffer_tryalloc * diff --git a/net/udp/udp_sendto_buffered.c b/net/udp/udp_sendto_buffered.c index 470451ca55..4da96b9f0d 100644 --- a/net/udp/udp_sendto_buffered.c +++ b/net/udp/udp_sendto_buffered.c @@ -501,6 +501,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, { FAR struct udp_wrbuffer_s *wrb; FAR struct udp_conn_s *conn; + unsigned int timeout; bool nonblock; bool empty; int ret = OK; @@ -628,6 +629,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, nonblock = _SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0; + timeout = _SO_TIMEOUT(conn->sconn.s_sndtimeo); /* Dump the incoming buffer */ @@ -650,7 +652,16 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, goto errout_with_lock; } - net_lockedwait_uninterruptible(&conn->sndsem); + ret = net_timedwait_uninterruptible(&conn->sndsem, timeout); + if (ret < 0) + { + if (ret == -ETIMEDOUT) + { + ret = -EAGAIN; + } + + goto errout_with_lock; + } } #endif /* CONFIG_NET_SEND_BUFSIZE */ @@ -664,7 +675,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, } else { - wrb = udp_wrbuffer_alloc(); + wrb = udp_wrbuffer_timedalloc(timeout); } if (wrb == NULL) @@ -672,7 +683,16 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, /* A buffer allocation error occurred */ nerr("ERROR: Failed to allocate write buffer\n"); - ret = nonblock ? -EAGAIN : -ENOMEM; + + if (nonblock || timeout != UINT_MAX) + { + ret = -EAGAIN; + } + else + { + ret = -ENOMEM; + } + goto errout_with_lock; } diff --git a/net/udp/udp_wrbuffer.c b/net/udp/udp_wrbuffer.c index c8aa2f8e4a..d13bb4f181 100644 --- a/net/udp/udp_wrbuffer.c +++ b/net/udp/udp_wrbuffer.c @@ -155,11 +155,75 @@ FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void) return wrb; } +/**************************************************************************** + * Name: udp_wrbuffer_timedalloc + * + * Description: + * Allocate a UDP write buffer by taking a pre-allocated buffer from + * the free list. This function is called from udp logic when a buffer + * of udp data is about to sent + * This function is wrapped version of udp_wrbuffer_alloc(), + * this wait will be terminated when the specified timeout expires. + * + * Input Parameters: + * timeout - The relative time to wait until a timeout is declared. + * + * Assumptions: + * Called from user logic with the network locked. + * + ****************************************************************************/ + +FAR struct udp_wrbuffer_s *udp_wrbuffer_timedalloc(unsigned int timeout) +{ + FAR struct udp_wrbuffer_s *wrb; + int ret; + + /* We need to allocate two things: (1) A write buffer structure and (2) + * at least one I/O buffer to start the chain. + * + * Allocate the write buffer structure first then the IOB. In order to + * avoid deadlocks, we will need to free the IOB first, then the write + * buffer + */ + + ret = net_timedwait_uninterruptible(&g_wrbuffer.sem, timeout); + if (ret != OK) + { + return NULL; + } + + /* Now, we are guaranteed to have a write buffer structure reserved + * for us in the free list. + */ + + wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers); + DEBUGASSERT(wrb); + memset(wrb, 0, sizeof(struct udp_wrbuffer_s)); + + /* Now get the first I/O buffer for the write buffer structure */ + + wrb->wb_iob = net_iobtimedalloc(true, timeout, + IOBUSER_NET_UDP_WRITEBUFFER); + + /* Did we get an IOB? We should always get one except under some really + * weird error conditions. + */ + + if (wrb->wb_iob == NULL) + { + nerr("ERROR: Failed to allocate I/O buffer\n"); + udp_wrbuffer_release(wrb); + return NULL; + } + + return wrb; +} + /**************************************************************************** * Name: udp_wrbuffer_tryalloc * * Description: - * Try to allocate a TCP write buffer by taking a pre-allocated buffer from + * Try to allocate a UDP write buffer by taking a pre-allocated buffer from * the free list. This function is called from UDP logic when a buffer * of UDP data is about to be sent on a non-blocking socket. Returns * immediately if the allocation failed.