rte_seqlock.h(3)

πŸ’– rte_seqlock.h β€” bestie, gather round πŸ’–

okay so this page comes straight out of the Library Functions Manual (section 3, you know the vibe), and it's all about rte_seqlock.h β€” the header that gives you the RTE seqlock. no cap, this one's lowkey iconic. let's get into it πŸ¦‹


✨ NAME ✨

rte_seqlock.h β€” that's it. that's the name. short, sweet, main character energy. πŸ’…


🌸 SYNOPSIS 🌸

first things first, you gotta pull in the friends:

#include <stdbool.h>
#include <stdint.h>
#include <rte_atomic.h>
#include <rte_branch_prediction.h>
#include <rte_seqcount.h>
#include <rte_spinlock.h>

πŸŽ€ Data Structures

  • struct rte_seqlock_t

πŸŽ€ Macros

  • #define RTE_SEQLOCK_INITIALIZER

πŸŽ€ Functions

static void rte_seqlock_init (rte_seqlock_t *seqlock)
static uint32_t rte_seqlock_read_begin (const rte_seqlock_t *seqlock)
static bool rte_seqlock_read_retry (const rte_seqlock_t *seqlock,
    uint32_t begin_sn)
static void rte_seqlock_write_lock (rte_seqlock_t *seqlock)
static void rte_seqlock_write_unlock (rte_seqlock_t *seqlock)

πŸ’… Detailed Description πŸ’…

RTE Seqlock β€” say it with me. ✨

A sequence lock (seqlock) is a synchronization primitive that lets multiple, parallel readers efficiently and safely (as in, in a data-race free manner, okay? no cheating) access lock-protected data. and the RTE seqlock permits multiple writers as well, because it's generous like that 🫢. a spinlock is used for writer-writer synchronization.

A reader never blocks a writer. queen behavior. but heads up: very high frequency writes may prevent readers from making progress. 😭 so like, don't spam.

A seqlock is not preemption-safe on the writer side. if a writer gets preempted, it may block readers until the writer thread is allowed to continue. so keep heavy computations out of the writer-side critical section, bestie β€” that delays readers and we don't do that here. πŸ’€

Seqlocks are useful for data which are read by many cores, at a high frequency, and relatively infrequently written to. it's giving "everyone's reading, nobody's writing". πŸ“–

One way to think about seqlocks is that they provide means to perform atomic operations on objects larger than what the native machine instructions allow for. ✨

To avoid resource reclamation issues, the data protected by a seqlock should typically be kept self-contained β€” e.g., no pointers to mutable, dynamically allocated data. no strays, no loose pointers, keep it tidy. 🧚

Example usage:

#define MAX_Y_LEN 16
// Application-defined example data structure, protected by a seqlock.
struct config {
        rte_seqlock_t lock;
        int param_x;
        char param_y[MAX_Y_LEN];
};

// Accessor function for reading config fields.
void
config_read(const struct config *config, int *param_x, char *param_y)
{
        uint32_t sn;

        do {
                sn = rte_seqlock_read_begin(&config->lock);

                // Loads may be atomic or non-atomic, as in this example.
                *param_x = config->param_x;
                strcpy(param_y, config->param_y);
                // An alternative to an immediate retry is to abort and
                // try again at some later time, assuming progress is
                // possible without the data.
        } while (rte_seqlock_read_retry(&config->lock, sn));
}

// Accessor function for writing config fields.
void
config_update(struct config *config, int param_x, const char *param_y)
{
        rte_seqlock_write_lock(&config->lock);
        // Stores may be atomic or non-atomic, as in this example.
        config->param_x = param_x;
        strcpy(config->param_y, param_y);
        rte_seqlock_write_unlock(&config->lock);
}

see how cute that loop is? the do { ... } while (rte_seqlock_read_retry(...)) is literally the whole trick. πŸŒ€

In case there is only a single writer, or writer-writer serialization is provided by other means, the use of sequence lock (i.e., rte_seqlock_t) can be replaced with the use of the "raw" rte_seqcount_t type instead. downgrade to raw mode, slay. 🌈

See also

https://en.wikipedia.org/wiki/Seqlock.

Definition in file rte_seqlock.h.


⭐ Macro Definition Documentation ⭐

πŸŽ€ #define RTE_SEQLOCK_INITIALIZER

Value:

{                           \
    .count = RTE_SEQCOUNT_INITIALIZER,      \
    .lock = RTE_SPINLOCK_INITIALIZER        \
}

A static seqlock initializer. one macro, zero drama, everything pre-locked and ready. 🫢

Definition at line 109 of file rte_seqlock.h.


πŸ‘‘ Function Documentation πŸ‘‘

πŸŽ€ void rte_seqlock_init (rte_seqlock_t * seqlock) [inline], [static]

Initialize the seqlock.

This function initializes the seqlock, and leaves the writer-side spinlock unlocked. (yes, unlocked. it's ready, not taken. πŸ’…)

Parameters

  • seqlock β€” A pointer to the seqlock.

Definition at line 125 of file rte_seqlock.h.

πŸŽ€ uint32_t rte_seqlock_read_begin (const rte_seqlock_t * seqlock) [inline], [static]

Begin a read-side critical section.

See rte_seqcount_read_retry() for details.

Parameters

  • seqlock β€” A pointer to the seqlock.

Returns

  • The seqlock sequence number for this critical section, to later be passed to rte_seqlock_read_retry().

See also

  • rte_seqlock_read_retry()
  • rte_seqcount_read_retry()

Definition at line 146 of file rte_seqlock.h.

πŸŽ€ bool rte_seqlock_read_retry (const rte_seqlock_t * seqlock, uint32_t begin_sn) [inline], [static]

End a read-side critical section.

See rte_seqcount_read_retry() for details.

Parameters

  • seqlock β€” A pointer to the seqlock.
  • begin_sn β€” The seqlock sequence number returned by rte_seqlock_read_begin().

Returns

  • true or false, if the just-read seqlock-protected data was inconsistent or consistent, respectively, at the time it was read. so true = bestie the data was moving, run it back. false = you're good, it's consistent. πŸ”₯

See also

  • rte_seqlock_read_begin()

Definition at line 168 of file rte_seqlock.h.

πŸŽ€ void rte_seqlock_write_lock (rte_seqlock_t * seqlock) [inline], [static]

Begin a write-side critical section.

A call to this function acquires the write lock associated seqlock, and marks the beginning of a write-side critical section.

After having called this function, the caller may go on to modify (both read and write) the protected data, in an atomic or non-atomic manner. do your thing. ✨

After the necessary updates have been performed, the application calls rte_seqlock_write_unlock().

This function is not preemption-safe in the sense that preemption of the calling thread may block reader progress until the writer thread is rescheduled. 😭

Unlike rte_seqlock_read_begin(), each call made to rte_seqlock_write_lock() must be matched with an unlock call. no ghost locks. every lock gets its unlock, periodt. πŸ’…

Parameters

  • seqlock β€” A pointer to the seqlock.

See also

  • rte_seqlock_write_unlock()

Definition at line 199 of file rte_seqlock.h.

πŸŽ€ void rte_seqlock_write_unlock (rte_seqlock_t * seqlock) [inline], [static]

End a write-side critical section.

A call to this function marks the end of the write-side critical section, for seqlock. After this call has been made, the protected data may no longer be modified. hands off the data, bestie. 🚫

Parameters

  • seqlock β€” A pointer to the seqlock.

See also

  • rte_seqlock_write_lock()

Definition at line 221 of file rte_seqlock.h.


🌈 Author 🌈

Generated automatically by Doxygen for DPDK from the source code. (not me writing this by hand at 2am, no ma'am, the robots did it πŸ€–βœ¨)


and that's the whole page, bestie!! you ate πŸ“ no notes, fr fr. this was DPDK, Version 25.11.3, and we were all up in rte_seqlock.h(3) β€” go forth and seqlock responsibly. mwah. πŸ’–πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from