drivers/video: use spinlock to replace critical section for goldfish_fb and vnc

Critical sections only disable interrupts on the local CPU, which
is insufficient for SMP. Replace with per-device spinlocks to
ensure proper mutual exclusion across all cores.

Signed-off-by: jianglianfang <jianglianfang@xiaomi.com>
This commit is contained in:
jianglianfang 2025-04-17 15:06:16 +08:00 committed by Xiang Xiao
parent c858f3cc44
commit a8de4c998c
3 changed files with 19 additions and 15 deletions

View file

@ -29,6 +29,7 @@
#include <nuttx/video/fb.h>
#include <nuttx/irq.h>
#include <nuttx/kmalloc.h>
#include <nuttx/spinlock.h>
/****************************************************************************
* Pre-processor definitions
@ -82,6 +83,7 @@ struct goldfish_fb_s
struct fb_videoinfo_s videoinfo;
FAR void *base;
int irq;
spinlock_t lock; /* Lock for this framebuffer */
};
/****************************************************************************
@ -166,7 +168,7 @@ static int goldfish_fb_interrupt(int irq, FAR void *dev_id, FAR void *arg)
irqstate_t flags;
uint32_t status;
flags = enter_critical_section();
flags = spin_lock_irqsave(&fb->lock);
status = getreg32(fb->base + GOLDFISH_FB_INT_STATUS);
if (status & GOLDFISH_FB_INT_VSYNC)
{
@ -178,7 +180,7 @@ static int goldfish_fb_interrupt(int irq, FAR void *dev_id, FAR void *arg)
goldfish_fb_framedone_irq(fb);
}
leave_critical_section(flags);
spin_unlock_irqrestore(&fb->lock, flags);
return OK;
}

View file

@ -41,6 +41,7 @@
#include <nuttx/input/keyboard.h>
#include <nuttx/net/net.h>
#include <nuttx/semaphore.h>
#include <nuttx/spinlock.h>
/****************************************************************************
* Pre-processor Definitions
@ -211,6 +212,8 @@ struct vnc_session_s
volatile bool rre; /* True: Remote supports RRE encoding */
FAR uint8_t *fb; /* Allocated local frame buffer */
spinlock_t lock; /* Lock for vnc updating */
/* VNC client input support */
vnc_kbdout_t kbdout; /* Callout when keyboard input is received */

View file

@ -192,15 +192,16 @@ vnc_alloc_update(FAR struct vnc_session_s *session)
*/
vnc_sem_debug(session, "Before alloc", 0);
flags = enter_critical_section();
nxsem_wait_uninterruptible(&session->freesem);
flags = spin_lock_irqsave(&session->lock);
/* It is reserved.. go get it */
update = (FAR struct vnc_fbupdate_s *)sq_remfirst(&session->updfree);
leave_critical_section(flags);
spin_unlock_irqrestore(&session->lock, flags);
vnc_sem_debug(session, "After alloc", 1);
DEBUGASSERT(update != NULL);
@ -232,7 +233,7 @@ static void vnc_free_update(FAR struct vnc_session_s *session,
*/
vnc_sem_debug(session, "Before free", 1);
flags = enter_critical_section();
flags = spin_lock_irqsave_nopreempt(&session->lock);
/* Put the entry into the free list */
@ -242,7 +243,7 @@ static void vnc_free_update(FAR struct vnc_session_s *session,
nxsem_post(&session->freesem);
leave_critical_section(flags);
spin_unlock_irqrestore_nopreempt(&session->lock, flags);
vnc_sem_debug(session, "After free", 0);
DEBUGASSERT(nxsem_get_value(&session->freesem, &sval) == 0 &&
@ -278,10 +279,11 @@ vnc_remove_queue(FAR struct vnc_session_s *session)
*/
vnc_sem_debug(session, "Before remove", 0);
flags = enter_critical_section();
nxsem_wait_uninterruptible(&session->queuesem);
flags = spin_lock_irqsave(&session->lock);
/* It is reserved.. go get it */
rect = (FAR struct vnc_fbupdate_s *)sq_remfirst(&session->updqueue);
@ -302,7 +304,7 @@ vnc_remove_queue(FAR struct vnc_session_s *session)
}
errout:
leave_critical_section(flags);
spin_unlock_irqrestore(&session->lock, flags);
return rect;
}
@ -332,7 +334,7 @@ static void vnc_add_queue(FAR struct vnc_session_s *session,
*/
vnc_sem_debug(session, "Before add", 1);
flags = enter_critical_section();
flags = spin_lock_irqsave_nopreempt(&session->lock);
/* Put the entry into the list of queued rectangles. */
@ -344,7 +346,7 @@ static void vnc_add_queue(FAR struct vnc_session_s *session,
nxsem_post(&session->queuesem);
leave_critical_section(flags);
spin_unlock_irqrestore_nopreempt(&session->lock, flags);
vnc_sem_debug(session, "After add", 0);
DEBUGASSERT(nxsem_get_value(&session->queuesem, &sval) == 0 &&
@ -611,12 +613,10 @@ int vnc_update_rectangle(FAR struct vnc_session_s *session,
* the framebuffer since the last whole screen update.
*/
flags = enter_critical_section();
if (!change && !session->change)
{
/* No.. ignore the client update. We have nothing new to report. */
leave_critical_section(flags);
return OK;
}
@ -636,9 +636,10 @@ int vnc_update_rectangle(FAR struct vnc_session_s *session,
FAR struct vnc_fbupdate_s *next;
updinfo("New whole screen update...\n");
flags = spin_lock_irqsave(&session->lock);
curr = (FAR struct vnc_fbupdate_s *)session->updqueue.head;
sq_init(&session->updqueue);
spin_unlock_irqrestore(&session->lock, flags);
nxsem_reset(&session->queuesem, 0);
for (; curr != NULL; curr = next)
@ -681,8 +682,6 @@ int vnc_update_rectangle(FAR struct vnc_session_s *session,
intersection.x, intersection.y,
intersection.w, intersection.h);
}
leave_critical_section(flags);
}
/* Since we ignore bad rectangles and wait for update structures, there is