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

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

commit 09e12a58d382f91c4368d04fa6feac79a5feec31
Author: gaohedong <[email protected]>
AuthorDate: Wed Apr 9 17:35:41 2025 +0800

    net/pkt: add poll function for pkt socket
    
    add poll function for pkt socket
    
    Signed-off-by: gaohedong <[email protected]>
---
 net/pkt/CMakeLists.txt |   1 +
 net/pkt/Kconfig        |   4 +
 net/pkt/Make.defs      |   1 +
 net/pkt/pkt.h          |  52 ++++++++
 net/pkt/pkt_netpoll.c  | 323 +++++++++++++++++++++++++++++++++++++++++++++++++
 net/pkt/pkt_sockif.c   |  43 ++++++-
 6 files changed, 422 insertions(+), 2 deletions(-)

diff --git a/net/pkt/CMakeLists.txt b/net/pkt/CMakeLists.txt
index a658238b83f..da3fac7dbe7 100644
--- a/net/pkt/CMakeLists.txt
+++ b/net/pkt/CMakeLists.txt
@@ -34,5 +34,6 @@ if(CONFIG_NET_PKT)
             pkt_input.c
             pkt_callback.c
             pkt_poll.c
+            pkt_netpoll.c
             pkt_finddev.c)
 endif()
diff --git a/net/pkt/Kconfig b/net/pkt/Kconfig
index b594e130a09..9e012c7bc12 100644
--- a/net/pkt/Kconfig
+++ b/net/pkt/Kconfig
@@ -61,5 +61,9 @@ config NET_PKT_MAX_CONNS
                This is useful in case the system is under very heavy load (or
                under attack), ensuring that the heap will not be exhausted.
 
+config NET_PKT_NPOLLWAITERS
+       int "Number of PKT poll waiters"
+       default 2
+
 endif # NET_PKT
 endmenu # Raw Socket Support
diff --git a/net/pkt/Make.defs b/net/pkt/Make.defs
index 628d5380798..6d846c2489b 100644
--- a/net/pkt/Make.defs
+++ b/net/pkt/Make.defs
@@ -36,6 +36,7 @@ NET_CSRCS += pkt_conn.c
 NET_CSRCS += pkt_input.c
 NET_CSRCS += pkt_callback.c
 NET_CSRCS += pkt_poll.c
+NET_CSRCS += pkt_netpoll.c
 NET_CSRCS += pkt_finddev.c
 
 # Include packet socket build support
diff --git a/net/pkt/pkt.h b/net/pkt/pkt.h
index 4b9e0d0deed..83ce4d287b8 100644
--- a/net/pkt/pkt.h
+++ b/net/pkt/pkt.h
@@ -53,6 +53,16 @@
 /* Representation of a packet socket connection */
 
 struct devif_callback_s; /* Forward reference */
+struct pollfd;           /* Forward reference */
+
+/* This is a container that holds the poll-related information */
+
+struct pkt_poll_s
+{
+  FAR struct pkt_conn_s       *conn; /* Needed to handle loss of connection */
+  FAR struct pollfd           *fds;  /* Needed to handle poll events */
+  FAR struct devif_callback_s *cb;   /* Needed to teardown the poll */
+};
 
 struct pkt_conn_s
 {
@@ -76,6 +86,12 @@ struct pkt_conn_s
   struct iob_queue_s readahead;   /* Read-ahead buffering */
 
   FAR struct iob_s  *pendiob;     /* The iob currently being sent */
+
+  /* The following is a list of poll structures of threads waiting for
+   * socket events.
+   */
+
+  struct pkt_poll_s  pollinfo[CONFIG_NET_PKT_NPOLLWAITERS];
 };
 
 /****************************************************************************
@@ -272,6 +288,42 @@ FAR struct net_driver_s *pkt_find_device(FAR struct 
pkt_conn_s *conn);
 
 void pkt_poll(FAR struct net_driver_s *dev, FAR struct pkt_conn_s *conn);
 
+/****************************************************************************
+ * Name: pkt_pollsetup
+ *
+ * Description:
+ *   Setup to monitor events on one PKT socket
+ *
+ * Input Parameters:
+ *   psock - The PKT socket of interest
+ *   fds   - The structure describing the events to be monitored, OR NULL if
+ *           this is a request to stop monitoring events.
+ *
+ * Returned Value:
+ *  0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+int pkt_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);
+
+/****************************************************************************
+ * Name: pkt_pollteardown
+ *
+ * Description:
+ *   Teardown monitoring of events on an PKT socket
+ *
+ * Input Parameters:
+ *   psock - The PKT socket of interest
+ *   fds   - The structure describing the events to be monitored, OR NULL if
+ *           this is a request to stop monitoring events.
+ *
+ * Returned Value:
+ *  0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+int pkt_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);
+
 /****************************************************************************
  * Name: pkt_sendmsg
  *
diff --git a/net/pkt/pkt_netpoll.c b/net/pkt/pkt_netpoll.c
new file mode 100644
index 00000000000..114a40184c1
--- /dev/null
+++ b/net/pkt/pkt_netpoll.c
@@ -0,0 +1,323 @@
+/****************************************************************************
+ * net/pkt/pkt_netpoll.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <assert.h>
+#include <poll.h>
+#include <debug.h>
+
+#include <nuttx/net/net.h>
+#include <nuttx/net/pkt.h>
+#include <nuttx/semaphore.h>
+
+#include "devif/devif.h"
+#include "netdev/netdev.h"
+#include "socket/socket.h"
+#include "pkt/pkt.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_pkt_cansend
+ *
+ * Description:
+ *   psock_pkt_cansend() returns a value indicating if a write to the socket
+ *   would block.  It is still possible that the write may block if another
+ *   write occurs first.
+ *
+ * Input Parameters:
+ *   conn     A reference to PKT connection structure.
+ *
+ * Returned Value:
+ *   OK (Always can send).
+ *
+ * Assumptions:
+ *   None
+ *
+ ****************************************************************************/
+
+static int psock_pkt_cansend(FAR struct pkt_conn_s *conn)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pkt_poll_eventhandler
+ *
+ * Description:
+ *   This function is called to perform the actual PKT receive operation via
+ *   the device interface layer.
+ *
+ * Input Parameters:
+ *   dev      The structure of the network driver that caused the event
+ *   pvpriv   An instance of struct pkt_poll_s cast to void*
+ *   flags    Set of events describing why the callback was invoked
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked
+ *
+ ****************************************************************************/
+
+static uint16_t pkt_poll_eventhandler(FAR struct net_driver_s *dev,
+                                      FAR void *pvpriv, uint16_t flags)
+{
+  FAR struct pkt_poll_s *info = pvpriv;
+
+  ninfo("flags: %04x\n", flags);
+
+  DEBUGASSERT(!info || (info->conn && info->fds));
+
+  /* 'priv' might be null in some race conditions (?) */
+
+  if (info)
+    {
+      pollevent_t eventset = 0;
+
+      /* Check for data availability events. */
+
+      if ((flags & PKT_NEWDATA) != 0)
+        {
+          eventset |= POLLIN;
+        }
+
+      /* Check for loss of connection events. */
+
+      if ((flags & NETDEV_DOWN) != 0)
+        {
+          eventset |= (POLLHUP | POLLERR);
+        }
+
+      /* A poll is a sign that we are free to send data. */
+
+      else if (psock_pkt_cansend(info->conn) >= 0)
+        {
+          eventset |= POLLOUT;
+        }
+
+      /* Awaken the caller of poll() is requested event occurred. */
+
+      poll_notify(&info->fds, 1, eventset);
+    }
+
+  return flags;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pkt_pollsetup
+ *
+ * Description:
+ *   Setup to monitor events on one PKT socket
+ *
+ * Input Parameters:
+ *   psock - The PKT socket of interest
+ *   fds   - The structure describing the events to be monitored, OR NULL if
+ *           this is a request to stop monitoring events.
+ *
+ * Returned Value:
+ *  0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+int pkt_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
+{
+  FAR struct pkt_conn_s *conn;
+  FAR struct pkt_poll_s *info;
+  FAR struct devif_callback_s *cb;
+  FAR struct net_driver_s *dev;
+  pollevent_t eventset = 0;
+  int ret = OK;
+
+  /* Some of the following must be atomic */
+
+  net_lock();
+
+  conn = psock->s_conn;
+
+  /* Sanity check */
+
+  if (conn == NULL || fds == NULL)
+    {
+      ret = -EINVAL;
+      goto errout_with_lock;
+    }
+
+  /* Find a container to hold the poll information */
+
+  info = conn->pollinfo;
+  while (info->conn != NULL)
+    {
+      if (++info >= &conn->pollinfo[CONFIG_NET_PKT_NPOLLWAITERS])
+        {
+          ret = -ENOMEM;
+          goto errout_with_lock;
+        }
+    }
+
+  /* Get the device that will provide the provide the NETDEV_DOWN event. */
+
+  dev = pkt_find_device(conn);
+
+  /* Allocate a PKT callback structure */
+
+  cb = pkt_callback_alloc(dev, conn);
+  if (cb == NULL)
+    {
+      ret = -EBUSY;
+      goto errout_with_lock;
+    }
+
+  /* Initialize the poll info container */
+
+  info->conn = conn;
+  info->fds  = fds;
+  info->cb   = cb;
+
+  /* Initialize the callback structure.  Save the reference to the info
+   * structure as callback private data so that it will be available during
+   * callback processing.
+   */
+
+  cb->flags = NETDEV_DOWN;
+  cb->priv  = info;
+  cb->event = pkt_poll_eventhandler;
+
+  if ((fds->events & POLLOUT) != 0)
+    {
+      cb->flags |= PKT_POLL;
+    }
+
+  if ((fds->events & POLLIN) != 0)
+    {
+      cb->flags |= PKT_NEWDATA;
+    }
+
+  /* Save the reference in the poll info structure as fds private as well
+   * for use during poll teardown as well.
+   */
+
+  fds->priv = info;
+
+  /* Check for read data availability now */
+
+  if (iob_peek_queue(&conn->readahead) != NULL)
+    {
+      /* Normal data may be read without blocking. */
+
+      eventset |= POLLRDNORM;
+    }
+
+  /* Check for write data availability now */
+
+  if (psock_pkt_cansend(conn) >= 0)
+    {
+      /* Normal data may be sent without blocking (at least one byte). */
+
+      eventset |= POLLWRNORM;
+    }
+
+  /* Check if any requested events are already in effect */
+
+  poll_notify(&fds, 1, eventset);
+
+errout_with_lock:
+  net_unlock();
+  return ret;
+}
+
+/****************************************************************************
+ * Name: pkt_pollteardown
+ *
+ * Description:
+ *   Teardown monitoring of events on an PKT socket
+ *
+ * Input Parameters:
+ *   psock - The PKT socket of interest
+ *   fds   - The structure describing the events to be monitored, OR NULL if
+ *           this is a request to stop monitoring events.
+ *
+ * Returned Value:
+ *  0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+int pkt_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
+{
+  FAR struct pkt_conn_s   *conn;
+  FAR struct pkt_poll_s   *info;
+  FAR struct net_driver_s *dev;
+
+  /* Some of the following must be atomic */
+
+  net_lock();
+
+  conn = psock->s_conn;
+
+  /* Sanity check */
+
+  if (!conn || !fds->priv)
+    {
+      net_unlock();
+      return -EINVAL;
+    }
+
+  /* Recover the socket descriptor poll state info from the poll structure */
+
+  info = (FAR struct pkt_poll_s *)fds->priv;
+  DEBUGASSERT(info->fds != NULL && info->cb != NULL);
+  if (info != NULL)
+    {
+      /* Get the device that will provide the NETDEV_DOWN event. */
+
+      dev = pkt_find_device(conn);
+
+      /* Release the callback */
+
+      pkt_callback_free(dev, conn, info->cb);
+
+      /* Release the poll/select data slot */
+
+      fds->priv = NULL;
+
+      /* Then free the poll info container */
+
+      info->conn = NULL;
+    }
+
+  net_unlock();
+
+  return OK;
+}
diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c
index a19f57f67d3..b8fe6b369eb 100644
--- a/net/pkt/pkt_sockif.c
+++ b/net/pkt/pkt_sockif.c
@@ -53,7 +53,10 @@ static int        pkt_setup(FAR struct socket *psock);
 static sockcaps_t pkt_sockcaps(FAR struct socket *psock);
 static void       pkt_addref(FAR struct socket *psock);
 static int        pkt_bind(FAR struct socket *psock,
-                    FAR const struct sockaddr *addr, socklen_t addrlen);
+                           FAR const struct sockaddr *addr,
+                           socklen_t addrlen);
+static int        pkt_netpoll(FAR struct socket *psock,
+                              FAR struct pollfd *fds, bool setup);
 static int        pkt_close(FAR struct socket *psock);
 
 /****************************************************************************
@@ -71,7 +74,7 @@ const struct sock_intf_s g_pkt_sockif =
   NULL,            /* si_listen */
   NULL,            /* si_connect */
   NULL,            /* si_accept */
-  NULL,            /* si_poll */
+  pkt_netpoll,     /* si_poll */
   pkt_sendmsg,     /* si_sendmsg */
   pkt_recvmsg,     /* si_recvmsg */
   pkt_close        /* si_close */
@@ -264,6 +267,42 @@ static int pkt_bind(FAR struct socket *psock,
     }
 }
 
+/****************************************************************************
+ * Name: pkt_netpoll
+ *
+ * Description:
+ *   The standard poll() operation redirects operations on pkt socket
+ *
+ * Input Parameters:
+ *   psock - An instance of the internal socket structure.
+ *   fds   - The structure describing the events to be monitored, OR NULL if
+ *           this is a request to stop monitoring events.
+ *   setup - true: Setup up the poll; false: Teardown the poll
+ *
+ * Returned Value:
+ *  0: Success; Negated errno on failure
+ *
+ ****************************************************************************/
+
+static int pkt_netpoll(FAR struct socket *psock, FAR struct pollfd *fds,
+                       bool setup)
+{
+  /* Check if we are setting up or tearing down the poll */
+
+  if (setup)
+    {
+      /* Perform the PKT poll() setup */
+
+      return pkt_pollsetup(psock, fds);
+    }
+  else
+    {
+      /* Perform the PKT poll() teardown */
+
+      return pkt_pollteardown(psock, fds);
+    }
+}
+
 /****************************************************************************
  * Name: pkt_close
  *

Reply via email to