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 23cec99002db4bb0ee3d80aa5844eba69a8ec34d
Author: yangsong8 <[email protected]>
AuthorDate: Sat Jun 21 15:48:52 2025 +0800

    drivers/usbhost: use small lock to protect usbhost cdcacm
    
    replace critical_section with spinlock
    
    Signed-off-by: yangsong8 <[email protected]>
---
 drivers/usbhost/usbhost_cdcacm.c | 57 ++++++++++++++++++++++------------------
 1 file changed, 31 insertions(+), 26 deletions(-)

diff --git a/drivers/usbhost/usbhost_cdcacm.c b/drivers/usbhost/usbhost_cdcacm.c
index 590659e1fa3..90c6ef539a3 100644
--- a/drivers/usbhost/usbhost_cdcacm.c
+++ b/drivers/usbhost/usbhost_cdcacm.c
@@ -25,6 +25,7 @@
  ****************************************************************************/
 
 #include <nuttx/config.h>
+#include <nuttx/spinlock.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -255,6 +256,7 @@ struct usbhost_cdcacm_s
   uint16_t       rxndx;          /* Index to the next byte in the RX packet 
buffer */
   int16_t        crefs;          /* Reference count on the driver instance */
   int16_t        nbytes;         /* The number of bytes actually transferred */
+  spinlock_t     spinlock;       /* Used to protect critical section */
   mutex_t        lock;           /* Used to maintain mutual exclusive access */
   struct work_s  ntwork;         /* For asynchronous notification work */
   struct work_s  rxwork;         /* For RX packet work */
@@ -474,6 +476,8 @@ static FAR struct usbhost_freestate_s *g_freelist;
 
 static uint32_t g_devinuse;
 
+static spinlock_t g_lock = SP_UNLOCKED;
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -507,14 +511,14 @@ static FAR struct usbhost_cdcacm_s 
*usbhost_allocclass(void)
    * our pre-allocated class instances from the free list.
    */
 
-  flags = enter_critical_section();
+  flags = spin_lock_irqsave(&g_lock);
   entry = g_freelist;
   if (entry)
     {
       g_freelist = entry->flink;
     }
 
-  leave_critical_section(flags);
+  spin_unlock_irqrestore(&g_lock, flags);
   uinfo("Allocated: %p\n", entry);
   return (FAR struct usbhost_cdcacm_s *)entry;
 }
@@ -562,10 +566,10 @@ static void usbhost_freeclass(FAR struct usbhost_cdcacm_s 
*usbclass)
 
   /* Just put the pre-allocated class structure back on the freelist */
 
-  flags = enter_critical_section();
+  flags = spin_lock_irqsave(&g_lock);
   entry->flink = g_freelist;
   g_freelist = entry;
-  leave_critical_section(flags);
+  spin_unlock_irqrestore(&g_lock, flags);
 }
 #else
 static void usbhost_freeclass(FAR struct usbhost_cdcacm_s *usbclass)
@@ -594,7 +598,7 @@ static int usbhost_devno_alloc(FAR struct usbhost_cdcacm_s 
*priv)
   irqstate_t flags;
   int devno;
 
-  flags = enter_critical_section();
+  flags = spin_lock_irqsave(&g_lock);
   for (devno = 0; devno < 32; devno++)
     {
       uint32_t bitno = 1 << devno;
@@ -602,12 +606,12 @@ static int usbhost_devno_alloc(FAR struct 
usbhost_cdcacm_s *priv)
         {
           g_devinuse |= bitno;
           priv->minor = devno;
-          leave_critical_section(flags);
+          spin_unlock_irqrestore(&g_lock, flags);
           return OK;
         }
     }
 
-  leave_critical_section(flags);
+  spin_unlock_irqrestore(&g_lock, flags);
   return -EMFILE;
 }
 
@@ -625,9 +629,9 @@ static void usbhost_devno_free(FAR struct usbhost_cdcacm_s 
*priv)
 
   if (devno >= 0 && devno < 32)
     {
-      irqstate_t flags = enter_critical_section();
+      irqstate_t flags = spin_lock_irqsave(&g_lock);
       g_devinuse &= ~(1 << devno);
-      leave_critical_section(flags);
+      spin_unlock_irqrestore(&g_lock, flags);
     }
 }
 
@@ -1905,6 +1909,7 @@ usbhost_create(FAR struct usbhost_hubport_s *hport,
            */
 
           nxmutex_init(&priv->lock);
+          spin_lock_init(&priv->spinlock);
 
           /* Set up the serial lower-half interface */
 
@@ -2123,6 +2128,7 @@ static int usbhost_disconnected(FAR struct 
usbhost_class_s *usbclass)
     (FAR struct usbhost_cdcacm_s *)usbclass;
   FAR struct usbhost_hubport_s *hport;
   irqstate_t flags;
+  int16_t crefs;
   int ret;
 
   DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
@@ -2132,8 +2138,10 @@ static int usbhost_disconnected(FAR struct 
usbhost_class_s *usbclass)
    * is no longer available.
    */
 
-  flags              = enter_critical_section();
+  flags              = spin_lock_irqsave(&priv->spinlock);
   priv->disconnected = true;
+  crefs              = priv->crefs;
+  spin_unlock_irqrestore(&priv->spinlock, flags);
 
   /* Let the upper half driver know that serial device is no longer
    * connected.
@@ -2174,8 +2182,8 @@ static int usbhost_disconnected(FAR struct 
usbhost_class_s *usbclass)
    * serial driver.
    */
 
-  uinfo("crefs: %d\n", priv->crefs);
-  if (priv->crefs == 1)
+  uinfo("crefs: %d\n", crefs);
+  if (crefs == 1)
     {
       /* Destroy the class instance.  If we are executing from an interrupt
        * handler, then defer the destruction to the worker thread.
@@ -2200,7 +2208,6 @@ static int usbhost_disconnected(FAR struct 
usbhost_class_s *usbclass)
         }
     }
 
-  leave_critical_section(flags);
   return OK;
 }
 
@@ -2241,7 +2248,7 @@ static int usbhost_setup(FAR struct uart_dev_s *uartdev)
    * isconnect events.
    */
 
-  flags = enter_critical_section();
+  flags = spin_lock_irqsave(&priv->spinlock);
   if (priv->disconnected)
     {
       /* No... the block driver is no longer bound to the class.  That means
@@ -2259,7 +2266,7 @@ static int usbhost_setup(FAR struct uart_dev_s *uartdev)
       ret = OK;
     }
 
-  leave_critical_section(flags);
+  spin_unlock_irqrestore(&priv->spinlock, flags);
   nxmutex_unlock(&priv->lock);
   return ret;
 }
@@ -2286,20 +2293,13 @@ static void usbhost_shutdown(FAR struct uart_dev_s 
*uartdev)
 
   DEBUGASSERT(priv->crefs > 1);
   nxmutex_lock(&priv->lock);
-  priv->crefs--;
-
-  /* Release the semaphore.  The following operations when crefs == 1 are
-   * safe because we know that there is no outstanding open references to
-   * the block driver.
-   */
-
-  nxmutex_unlock(&priv->lock);
 
   /* We need to disable interrupts momentarily to assure that there are
    * no asynchronous disconnect events.
    */
 
-  flags = enter_critical_section();
+  flags = spin_lock_irqsave(&priv->spinlock);
+  priv->crefs--;
 
   /* Check if the USB CDC/ACM device is still connected.  If the
    * CDC/ACM device is not connected and the reference count just
@@ -2312,10 +2312,15 @@ static void usbhost_shutdown(FAR struct uart_dev_s 
*uartdev)
       /* Destroy the class instance */
 
       DEBUGASSERT(priv->crefs == 1);
+      spin_unlock_irqrestore(&priv->spinlock, flags);
+      nxmutex_unlock(&priv->lock);
       usbhost_destroy(priv);
     }
-
-  leave_critical_section(flags);
+  else
+    {
+      spin_unlock_irqrestore(&priv->spinlock, flags);
+      nxmutex_unlock(&priv->lock);
+    }
 }
 
 /****************************************************************************

Reply via email to