You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/07/25 15:47:13 UTC

[incubator-nuttx] 02/09: SocketCAN: add non-blocking write

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/incubator-nuttx.git

commit 51a845ce54e38ca6ecc13c2fd7029802cb07076f
Author: Jari van Ewijk <ja...@nxp.com>
AuthorDate: Fri Jul 22 10:23:20 2022 +0200

    SocketCAN: add non-blocking write
    
    Co-authored-by: Peter van der Perk <pe...@nxp.com>
---
 net/can/can.h         | 26 ++++++++++++++++++++++++++
 net/can/can_input.c   | 52 ++++++++++++++++++++++++---------------------------
 net/can/can_sendmsg.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--
 net/can/can_sockif.c  | 10 +++-------
 4 files changed, 99 insertions(+), 37 deletions(-)

diff --git a/net/can/can.h b/net/can/can.h
index 48f9e1087d..d317fea6f7 100644
--- a/net/can/can.h
+++ b/net/can/can.h
@@ -267,6 +267,32 @@ ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
 
 void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn);
 
+/****************************************************************************
+ * Name: psock_can_cansend
+ *
+ * Description:
+ *   psock_can_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:
+ *   psock    An instance of the internal socket structure.
+ *
+ * Returned Value:
+ *   OK
+ *     At least one byte of data could be successfully written.
+ *   -EWOULDBLOCK
+ *     There is no room in the output buffer.
+ *   -EBADF
+ *     An invalid descriptor was specified.
+ *
+ * Assumptions:
+ *   None
+ *
+ ****************************************************************************/
+
+int psock_can_cansend(FAR struct socket *psock);
+
 /****************************************************************************
  * Name: can_sendmsg
  *
diff --git a/net/can/can_input.c b/net/can/can_input.c
index 024bb9aad5..7a073d566d 100644
--- a/net/can/can_input.c
+++ b/net/can/can_input.c
@@ -155,48 +155,44 @@ int can_input(struct net_driver_s *dev)
 {
   FAR struct can_conn_s *conn = NULL;
   int ret = OK;
+  uint16_t buflen = dev->d_len;
 
   do
     {
-      /* FIXME Support for multiple sockets??? */
-
       conn = can_nextconn(conn);
-    }
-  while (conn && conn->dev != 0 && dev != conn->dev);
-
-  if (conn)
-    {
-      uint16_t flags;
 
-      /* Setup for the application callback */
+      if (conn && (conn->dev == 0x0 || dev == conn->dev))
+        {
+          uint16_t flags;
 
-      dev->d_appdata = dev->d_buf;
-      dev->d_sndlen  = 0;
+          /* Setup for the application callback */
 
-      /* Perform the application callback */
+          dev->d_appdata = dev->d_buf;
+          dev->d_sndlen  = 0;
+          dev->d_len     = buflen;
 
-      flags = can_callback(dev, conn, CAN_NEWDATA);
+          /* Perform the application callback */
 
-      /* If the operation was successful, the CAN_NEWDATA flag is removed
-       * and thus the packet can be deleted (OK will be returned).
-       */
+          flags = can_callback(dev, conn, CAN_NEWDATA);
 
-      if ((flags & CAN_NEWDATA) != 0)
-        {
-          /* No.. the packet was not processed now.  Return -EAGAIN so
-           * that the driver may retry again later.  We still need to
-           * set d_len to zero so that the driver is aware that there
-           * is nothing to be sent.
+          /* If the operation was successful, the CAN_NEWDATA flag is removed
+           * and thus the packet can be deleted (OK will be returned).
            */
 
-           nwarn("WARNING: Packet not processed\n");
-           ret = -EAGAIN;
+          if ((flags & CAN_NEWDATA) != 0)
+            {
+              /* No.. the packet was not processed now.  Return -EAGAIN so
+               * that the driver may retry again later.  We still need to
+               * set d_len to zero so that the driver is aware that there
+               * is nothing to be sent.
+               */
+
+               nwarn("WARNING: Packet not processed\n");
+               ret = -EAGAIN;
+            }
         }
     }
-  else
-    {
-      ninfo("No CAN listener\n");
-    }
+  while (conn);
 
   return ret;
 }
diff --git a/net/can/can_sendmsg.c b/net/can/can_sendmsg.c
index a7912d99d1..3ccea61826 100644
--- a/net/can/can_sendmsg.c
+++ b/net/can/can_sendmsg.c
@@ -259,10 +259,17 @@ ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
       netdev_txnotify_dev(dev);
 
       /* Wait for the send to complete or an error to occur.
-       * net_lockedwait will also terminate if a signal is received.
+       * net_timedwait will also terminate if a signal is received.
        */
 
-      ret = net_lockedwait(&state.snd_sem);
+      if (_SS_ISNONBLOCK(conn->sconn.s_flags) || (flags & MSG_DONTWAIT) != 0)
+        {
+          ret = net_timedwait(&state.snd_sem, 0);
+        }
+      else
+        {
+          ret = net_timedwait(&state.snd_sem, UINT_MAX);
+        }
 
       /* Make sure that no further events are processed */
 
@@ -296,4 +303,41 @@ ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
   return state.snd_sent;
 }
 
+/****************************************************************************
+ * Name: psock_can_cansend
+ *
+ * Description:
+ *   psock_can_cansend() returns a value indicating if a write to the socket
+ *   would block.  No space in the buffer is actually reserved, so it is
+ *   possible that the write may still block if the buffer is filled by
+ *   another means.
+ *
+ * Input Parameters:
+ *   psock    An instance of the internal socket structure.
+ *
+ * Returned Value:
+ *   OK
+ *     At least one byte of data could be successfully written.
+ *   -EWOULDBLOCK
+ *     There is no room in the output buffer.
+ *   -EBADF
+ *     An invalid descriptor was specified.
+ *
+ ****************************************************************************/
+
+int psock_can_cansend(FAR struct socket *psock)
+{
+  /* Verify that we received a valid socket */
+
+  if (psock == NULL || psock->s_conn == NULL)
+    {
+      nerr("ERROR: Invalid socket\n");
+      return -EBADF;
+    }
+
+  /* TODO Query CAN driver mailboxes to see if there's mailbox available */
+
+  return OK;
+}
+
 #endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c
index 780641f972..bddc3ef9b8 100644
--- a/net/can/can_sockif.c
+++ b/net/can/can_sockif.c
@@ -139,15 +139,13 @@ static uint16_t can_poll_eventhandler(FAR struct net_driver_s *dev,
           eventset |= (POLLHUP | POLLERR);
         }
 
-#if 0
       /* A poll is a sign that we are free to send data. */
 
       else if ((flags & CAN_POLL) != 0 &&
-                 psock_udp_cansend(info->psock) >= 0)
+                 psock_can_cansend(info->psock) >= 0)
         {
           eventset |= (POLLOUT & info->fds->events);
         }
-#endif
 
       /* Awaken the caller of poll() is requested event occurred. */
 
@@ -608,14 +606,12 @@ static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds,
           fds->revents |= (POLLRDNORM & fds->events);
         }
 
-    #if 0
-      if (psock_udp_cansend(psock) >= 0)
+      if (psock_can_cansend(psock) >= 0)
         {
-          /* Normal data may be sent without blocking (at least one byte). */
+          /* A CAN frame may be sent without blocking. */
 
           fds->revents |= (POLLWRNORM & fds->events);
         }
-    #endif
 
       /* Check if any requested events are already in effect */