PSERIALIZE(9)

πŸ“¦ version 11.0, in nixpkgs unstable

πŸ’… pserialize(9): passive serialization, but make it cute πŸ’…

okay so welcome to the pserialize(9) page from the Kernel Developer's Manual, bestie. This one is all about passive serialization, and it's lowkey iconic: lock-less reads, writer-side patience, the whole vibe. ✨

πŸ“› NAME πŸ“›

pserialize β€” passive serialization mechanism

🌸 SYNOPSIS 🌸

#include <sys/pserialize.h>

pserialize_t
pserialize_create(void);

void
pserialize_destroy(pserialize_t psz);

int
pserialize_read_enter(void);

void
pserialize_read_exit(int s);

void
pserialize_perform(pserialize_t psz);

πŸ¦‹ DESCRIPTION πŸ¦‹

Passive serialization is a reader / writer synchronisation mechanism designed for lock-less read operations. The read operations may happen from software interrupt at IPL_SOFTCLOCK.

✨ FUNCTIONS ✨

  • pserialize_create() β€” Allocate a new synchronisation object. Fresh object, new vibes. πŸŽ€
  • pserialize_destroy() β€” Destroy the synchronisation object. No synchronisation activity should happen at this point.
  • pserialize_read_enter() β€” Enter the critical path of the reader side. Returns an IPL value, which must be passed to pserialize_read_exit(9). Protected code path is not allowed to block. Not allowed, bestie.
  • pserialize_read_exit() β€” Exit the critical path of the reader side. Takes the IPL value returned by pserialize_read_enter(9).
  • pserialize_perform() β€” Perform the passive serialization on the writer side. Passing of this function ensures that no readers are in action. Writers are typically additionally serialized with a separate mechanism, e.g. mutex(9), to remove objects used by readers from a published list. Operation blocks and it may only be performed from thread context.

πŸŽ€ EXAMPLES πŸŽ€

Okay, imagine we've got a global database of frotz records:

struct frotz {
        ...
        struct frotz    *f_next;
};

static struct {
        kmutex_t        lock;
        pserialize_t    psz;
        struct frotz    *first;
} frobbotzim __cacheline_aligned;

Create a frotz and publish it, as a writer:

struct frotz *f = pool_get(&frotz_pool, PR_WAITOK);

/* Initialize f.  */
...

mutex_enter(&frobbotzim.lock);
f->f_next = frobbotzim.first;
/*
 * Publish the contents of f->f_next before we publish the
 * pointer to f in frobbotzim.first.
 */
membar_producer();
frobbotzim.first = f;
mutex_exit(&frobbotzim.lock);

Find a frotz, as a reader:

struct frotz *f;
int error = ENOENT;
int s;

s = pserialize_read_enter();
for (f = frobbotzim.first; f != NULL; f = f->f_next) {
        /* Fetch f before we fetch anything f points to.  */
        membar_datadep_consumer();
        if (f->f_... == key) {
                /*
                 * Grab whatever part of the frotz we need.
                 * Note that we can't use the frotz after
                 * pserialize_read_exit, without a stronger
                 * kind of reference, say a reference count
                 * managed by atomic_ops(3).
                 */
                *resultp = f->f_...;
                error = 0;
                break;
        }
}
pserialize_read_exit(s);

return error;

Remove a frotz, as a writer, and free it once there are no more readers:

struct frotz **fp, *f;

mutex_enter(&frobbotzim.lock);
for (fp = &frobbotzim.first; (f = *fp) != NULL; fp = &f->f_next) {
        if (f->f_... == key) {
                /*
                 * Unhook it from the list.  Readers may still
                 * be traversing the list at this point, so
                 * the next pointer must remain valid and
                 * memory must remain allocated.
                 */
                *fp = f->f_next;
                break;
        }
}
mutex_exit(&frobbotzim.lock);

/*
 * Wait for all existing readers to complete.  New readers will
 * not see f because the list no longer points to it.
 */
pserialize_perform(frobbotzim.psz);

/* Now nobody else can be touching f, so it is safe to free.  */
if (f != NULL)
        pool_put(&frotz_pool, f);

πŸ”₯ CODE REFERENCES πŸ”₯

The pserialize is implemented within the file sys/kern/subr_pserialize.c.

🌈 SEE ALSO 🌈

Hennessy, et al., Passive serialization in a multitasking environment, US Patent and Trademark Office, US Patent 4809168, February 28, 1989.

πŸ‘‘ HISTORY πŸ‘‘

Passive serialization mechanism first appeared in NetBSD 6.0.


xoxo πŸ’‹ β€” source/version: Debian; date: January 26, 2016 🌸

πŸ“¦ where this page comes from