.\"
.\" Copyright 2013 Samy Al Bahra.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in the
.\"    documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\"
.Dd July 26, 2013.
.Dt ck_sequence 3
.Sh NAME
.Nm ck_sequence_init ,
.Nm ck_sequence_read_begin ,
.Nm ck_sequence_read_retry ,
.Nm ck_sequence_write_begin ,
.Nm ck_sequence_write_end
.Nd sequence locks
.Sh LIBRARY
Concurrency Kit (libck, \-lck)
.Sh SYNOPSIS
.In ck_sequence.h
.Pp
.Dv ck_sequence_t seqlock = CK_SEQUENCE_INITIALIZER;
.Pp
.Ft void
.Fn ck_sequence_init "ck_sequence_t *sq"
.Ft unsigned int
.Fn ck_sequence_read_begin "const ck_sequence_t *sq"
.Ft bool
.Fn ck_sequence_read_retry "const ck_sequence_t *sq" "unsigned int version"
.Ft void
.Fn ck_sequence_write_begin "ck_sequence_t *sq"
.Ft void
.Fn ck_sequence_write_end "ck_sequence_t *sq"
.Sh DESCRIPTION
It is recommended to use ck_sequence when a small amount of data that cannot be
accessed atomically has to be synchronized with readers in a fashion that does
not block any writer. Readers are able to execute their read-side critical
sections without any atomic operations. A ck_sequence_t must be initialized
before use. It may be initialized using either a static initializer
(CK_SEQUENCE_INITIALIZER) or using
.Fn ck_sequence_init .
Before readers attempt to
read data that may be concurrently modified they must first save the return
value of
.Fn ck_sequence_read_begin .
While or after a reader has completed copying
the data associated with a ck_sequence_t it must pass the earlier return value
of
.Fn ck_sequence_read_begin
to
.Fn "ck_sequence_read_retry". If
.Fn ck_sequence_read_retry
returns true then the copy of data may be inconsistent and the read process
must be retried. Writers must rely on their own synchronization primitives.
Once a writer has entered its respective critical section, it must call
.Fn ck_sequence_write_begin
to signal intent to update the data protected
by the ck_sequence_t. Before the writer leaves its critical section it must
execute
.Fn ck_sequence_write_end
to indicate that the updates have left respective objects in a consistent state.
.Sh EXAMPLE
.Bd -literal -offset indent
#include <ck_sequence.h>
#include <stdlib.h>

static struct example {
	int a;
	int b;
	int c;
} global;

static ck_sequence_t seqlock = CK_SEQUENCE_INITIALIZER;

void
reader(void)
{
	struct example copy;
	unsigned int version;

	/*
	 * Attempt a read of the data structure. If the structure
	 * has been modified between ck_sequence_read_begin and
	 * ck_sequence_read_retry then attempt another read since
	 * the data may be in an inconsistent state.
	 */
	do {
		version = ck_sequence_read_begin(&seqlock);
		copy = global;
	} while (ck_sequence_read_retry(&seqlock, version));

	/*
	 * The previous may also be expressed using CK_SEQUENCE_READ.
	 * Generally recommend to only use ck_sequence_read_retry
	 * if you would like to detect a conflicting write at some
	 * higher granularity.
	 */
	CK_SEQUENCE_READ(&seqlock, &version) {
		copy = global;
	}

	return;
}

void
writer(void)
{

	for (;;) {
		ck_sequence_write_begin(&seqlock);
		global.a = rand();
		global.b = global.a + global.b;
		global.c = global.b + global.c;
		ck_sequence_write_end(&seqlock);
	}

	return;
}
.Ed
.Sh SEE ALSO
.Xr ck_brlock 3 ,
.Xr ck_bytelock 3 ,
.Xr ck_rwlock 3
.Pp
Additional information available at http://concurrencykit.org/
