seqlock: Better implementation of the seqlock.

This commit provided a better implementation of the seqlock, which
ensure the functional correctness and provide better performance.

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
ouyangxiangzhen
2025-09-19 10:58:59 +08:00
committed by Alan C. Assis
parent 46ad770b60
commit ef1fb35462
+39 -26
View File
@@ -27,13 +27,14 @@
* Included Files * Included Files
****************************************************************************/ ****************************************************************************/
#include <nuttx/spinlock.h> #include <nuttx/atomic.h>
#include <nuttx/irq.h>
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
#define SEQLOCK_INITIALIZER {0, SP_UNLOCKED} #define SEQLOCK_INITIALIZER {0}
/**************************************************************************** /****************************************************************************
* Public Data Types * Public Data Types
@@ -45,8 +46,7 @@
typedef struct seqclock typedef struct seqclock
{ {
volatile unsigned int sequence; atomic_t sequence;
spinlock_t lock;
} seqcount_t; } seqcount_t;
#undef EXTERN #undef EXTERN
@@ -59,7 +59,7 @@ extern "C"
#endif #endif
/**************************************************************************** /****************************************************************************
* Public Function Prototypes * Inline Functions
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
@@ -78,8 +78,7 @@ extern "C"
static inline_function void seqlock_init(FAR seqcount_t *s) static inline_function void seqlock_init(FAR seqcount_t *s)
{ {
s->sequence = 0; atomic_init(&s->sequence, 0u);
spin_lock_init(&s->lock);
} }
/**************************************************************************** /****************************************************************************
@@ -98,15 +97,17 @@ static inline_function void seqlock_init(FAR seqcount_t *s)
****************************************************************************/ ****************************************************************************/
static inline_function static inline_function
unsigned int read_seqbegin(FAR const seqcount_t *s) uint32_t read_seqbegin(FAR const seqcount_t *s)
{ {
unsigned int seq; uint32_t seq;
while (predict_false((seq = s->sequence) & 1)); do
{
/* Ensure no load operation is re-ordered before the acquire load. */
#ifdef CONFIG_SMP seq = atomic_read_acquire(&s->sequence);
SMP_RMB(); }
#endif while (seq & 1);
return seq; return seq;
} }
@@ -128,16 +129,13 @@ unsigned int read_seqbegin(FAR const seqcount_t *s)
****************************************************************************/ ****************************************************************************/
static inline_function static inline_function
unsigned int read_seqretry(FAR const seqcount_t *s, unsigned int start) uint32_t read_seqretry(FAR const seqcount_t *s, uint32_t start)
{ {
unsigned int seq; /* Ensure all load operations before are completed. */
#ifdef CONFIG_SMP SMP_RMB();
UP_DMB();
#endif
seq = s->sequence; return predict_false(atomic_read(&s->sequence) != start);
return predict_false(seq != start);
} }
/**************************************************************************** /****************************************************************************
@@ -158,10 +156,26 @@ unsigned int read_seqretry(FAR const seqcount_t *s, unsigned int start)
static inline_function static inline_function
irqstate_t write_seqlock_irqsave(FAR seqcount_t *s) irqstate_t write_seqlock_irqsave(FAR seqcount_t *s)
{ {
irqstate_t flags = spin_lock_irqsave(&s->lock); uint32_t sequence;
irqstate_t flags = up_irq_save();
for (; ; )
{
sequence = atomic_read(&s->sequence);
if (predict_true(!(sequence & 1)))
{
/* Try to acquire the lock ownership. */
if (atomic_cmpxchg_acquire(&s->sequence, &sequence, sequence + 1))
{
break;
}
}
/* CPU Relax and retry. */
}
s->sequence++;
SMP_WMB();
return flags; return flags;
} }
@@ -184,9 +198,8 @@ irqstate_t write_seqlock_irqsave(FAR seqcount_t *s)
static inline_function static inline_function
void write_sequnlock_irqrestore(seqcount_t *s, irqstate_t flags) void write_sequnlock_irqrestore(seqcount_t *s, irqstate_t flags)
{ {
SMP_WMB(); atomic_set_release(&s->sequence, s->sequence + 1);
s->sequence++; up_irq_restore(flags);
spin_unlock_irqrestore(&s->lock, flags);
} }
#undef EXTERN #undef EXTERN