PSERIALIZE(9) Kernel Developer's Manual PSERIALIZE(9)

NAME

pserializepassive 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.
 
 
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.
 
 
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 must be additionally serialized with a separate mechanism, e.g. mutex(9). Operation blocks and it may only be performed from thread context.

EXAMPLES

Given 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; 
		} 
	} 
	/* 
	 * 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.  */ 
	mutex_exit(&frobbotzim.lock); 
 
	if (f != NULL) 
		pool_put(&frotz_pool, f);

CODE REFERENCES

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

SEE ALSO

membar_ops(3), condvar(9), mutex(9), rwlock(9)
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.
January 26, 2016 NetBSD 8.2