You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2019/12/31 15:52:46 UTC

[incubator-nuttx] branch master updated: psock_udp_sendto should call udp_wrbuffer_tryalloc for nonblock socket (#20)

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 5fb5a9d  psock_udp_sendto should call udp_wrbuffer_tryalloc for nonblock socket (#20)
5fb5a9d is described below

commit 5fb5a9dfddabe33966de961b03d5934f8a658084
Author: Xiang Xiao <xi...@xiaomi.com>
AuthorDate: Tue Dec 31 09:52:40 2019 -0600

    psock_udp_sendto should call udp_wrbuffer_tryalloc for nonblock socket (#20)
    
     net/udp/udp_wrbuffer.c:  Add new function udp_wrbuffer_tryalloc()
    net/udp/udp_psock_sendto_buffered.c:  If the socket was opened with O_NONBLOCK, then use udp_wrbuffer_tryalloc() so that the caller will not wait for a write buffer.  Return EGAIN if udp_wrbuffer_tryalloc() failes.
---
 net/udp/udp.h                       | 21 ++++++++++++++
 net/udp/udp_psock_sendto_buffered.c | 15 ++++++++--
 net/udp/udp_wrbuffer.c              | 56 +++++++++++++++++++++++++++++++++++++
 3 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/net/udp/udp.h b/net/udp/udp.h
index 2c95052..d63b1f7 100644
--- a/net/udp/udp.h
+++ b/net/udp/udp.h
@@ -461,6 +461,27 @@ FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void);
 #endif /* CONFIG_NET_UDP_WRITE_BUFFERS */
 
 /****************************************************************************
+ * Name: udp_wrbuffer_tryalloc
+ *
+ * Description:
+ *   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 if the socket is non-blocking. Returns
+ *   immediately if allocation fails.
+ *
+ * Input parameters:
+ *   None
+ *
+ * Assumptions:
+ *   Called from user logic with the network locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
+FAR struct udp_wrbuffer_s *udp_wrbuffer_tryalloc(void);
+#endif /* CONFIG_NET_UDP_WRITE_BUFFERS */
+
+/****************************************************************************
  * Name: udp_wrbuffer_release
  *
  * Description:
diff --git a/net/udp/udp_psock_sendto_buffered.c b/net/udp/udp_psock_sendto_buffered.c
index b465edb..d987886 100644
--- a/net/udp/udp_psock_sendto_buffered.c
+++ b/net/udp/udp_psock_sendto_buffered.c
@@ -697,18 +697,27 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
 
   if (len > 0)
     {
+      net_lock();
+
       /* Allocate a write buffer.  Careful, the network will be momentarily
        * unlocked here.
        */
 
-      net_lock();
-      wrb = udp_wrbuffer_alloc();
+      if (_SS_ISNONBLOCK(psock->s_flags))
+        {
+          wrb = udp_wrbuffer_tryalloc();
+        }
+      else
+        {
+          wrb = udp_wrbuffer_alloc();
+        }
+
       if (wrb == NULL)
         {
           /* A buffer allocation error occurred */
 
           nerr("ERROR: Failed to allocate write buffer\n");
-          ret = -ENOMEM;
+          ret = _SS_ISNONBLOCK(psock->s_flags) ? -EAGAIN : -ENOMEM;
           goto errout_with_lock;
         }
 
diff --git a/net/udp/udp_wrbuffer.c b/net/udp/udp_wrbuffer.c
index b380c59..9248c3a 100644
--- a/net/udp/udp_wrbuffer.c
+++ b/net/udp/udp_wrbuffer.c
@@ -171,6 +171,62 @@ FAR struct udp_wrbuffer_s *udp_wrbuffer_alloc(void)
 }
 
 /****************************************************************************
+ * Name: udp_wrbuffer_tryalloc
+ *
+ * Description:
+ *   Try to allocate a TCP 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.
+ *
+ * Input parameters:
+ *   None
+ *
+ * Assumptions:
+ *   Called from user logic with the network locked. Will return if no buffer
+ *   is available.
+ *
+ ****************************************************************************/
+
+FAR struct udp_wrbuffer_s *udp_wrbuffer_tryalloc(void)
+{
+  FAR struct udp_wrbuffer_s *wrb;
+
+  /* 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
+   */
+
+  if (nxsem_trywait(&g_wrbuffer.sem) != 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 = iob_tryalloc(false, IOBUSER_NET_UDP_WRITEBUFFER);
+  if (!wrb->wb_iob)
+    {
+      nerr("ERROR: Failed to allocate I/O buffer\n");
+      udp_wrbuffer_release(wrb);
+      return NULL;
+    }
+
+  return wrb;
+}
+
+/****************************************************************************
  * Name: udp_wrbuffer_release
  *
  * Description: