> From: Ola Liljedahl [mailto:ola.liljed...@arm.com]
> Sent: Thursday, 31 March 2022 11.05
> 
> On 3/31/22 09:46, Mattias Rönnblom wrote:
> > On 2022-03-30 16:26, Mattias Rönnblom wrote:
> >> A sequence lock (seqlock) is synchronization primitive which allows
> >> for data-race free, low-overhead, high-frequency reads, especially
> for
> >> data structures shared across many cores and which are updated with
> >> relatively infrequently.
> >>
> >>
> >
> > <snip>
> >
> > Some questions I have:
> >
> > Is a variant of the seqlock without the spinlock required? The reason
> I
> > left such out was that I thought that in most cases where only a
> single
> > writer is used (or serialization is external to the seqlock), the
> > spinlock overhead is negligible, since updates are relatively
> infrequent.

Mattias, when you suggested adding the seqlock, I considered this too, and came 
to the same conclusion as you.

> You can combine the spinlock and the sequence number. Odd sequence
> number means the seqlock is busy. That would replace a non-atomic RMW
> of
> the sequence number with an atomic RMW CAS and avoid the spin lock
> atomic RMW operation. Not sure how much it helps.
> 
> >
> > Should the rte_seqlock_read_retry() be called rte_seqlock_read_end(),
> or
> > some third alternative? I wanted to make clear it's not just a
> "release
> > the lock" function. You could use
> > the|||__attribute__((warn_unused_result)) annotation to make clear
> the
> > return value cannot be ignored, although I'm not sure DPDK ever use
> that
> > attribute.

I strongly support adding __attribute__((warn_unused_result)) to the function. 
There's a first time for everything, and this attribute is very relevant here!

> We have to decide how to use the seqlock API from the application
> perspective.
> Your current proposal:
> do {
>      sn = rte_seqlock_read_begin(&seqlock)
>      //read protected data
> } while (rte_seqlock_read_retry(&seqlock, sn));
> 
> or perhaps
> sn = rte_seqlock_read_lock(&seqlock);
> do {
>      //read protected data
> } while (!rte_seqlock_read_tryunlock(&seqlock, &sn));
> 
> Tryunlock should signal to the user that the unlock operation might not
> succeed and something needs to be repeated.

Perhaps rename rte_seqlock_read_retry() to rte_seqlock_read_tryend()? As Ola 
mentions, this also inverses the boolean result value. If you consider this, 
please check that the resulting assembly output remains efficient.

I think lock()/unlock() should be avoided in the read operation names, because 
no lock is taken during read. I like the critical region begin()/end() names.

Regarding naming, you should also consider renaming 
rte_seqlock_write_begin/end() to rte_seqlock_write_lock/unlock(), following the 
naming convention of the other locks. This could prepare for future extensions, 
such as rte_seqlock_write_trylock(). Just a thought; I don't feel strongly 
about this.

Ola, the rte_seqlock_read_lock(&seqlock) must remain inside the loop, because 
retries can be triggered by a write operation happening between the 
read_begin() and read_tryend(), and then the new sn must be used by the read 
operation.

Reply via email to