Add a man page for the kernel's dynamic per-CPU memory allocator.
MFC after: 3 days
This commit is contained in:
parent
385a67dc6a
commit
8509f6321a
@ -116,6 +116,7 @@ MAN= accept_filter.9 \
|
||||
disk.9 \
|
||||
dnv.9 \
|
||||
domain.9 \
|
||||
dpcpu.9 \
|
||||
drbr.9 \
|
||||
driver.9 \
|
||||
DRIVER_MODULE.9 \
|
||||
|
163
share/man/man9/dpcpu.9
Normal file
163
share/man/man9/dpcpu.9
Normal file
@ -0,0 +1,163 @@
|
||||
.\"-
|
||||
.\" Copyright (c) 2017 Robert N. M. Watson
|
||||
.\" 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 AUTHOR 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 AUTHOR 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.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 26, 2017
|
||||
.Dt DPCPU 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm dpcpu
|
||||
.Nd Kernel Dynamic Per-CPU Memory Allocator
|
||||
.Sh SYNOPSIS
|
||||
.In sys/pcpu.h
|
||||
.Ss Per-CPU Variable Definition and Declaration
|
||||
.Fn DPCPU_DEFINE "type" "name"
|
||||
.Fn DPCPU_DECLARE "type" "name"
|
||||
.Ss Current CPU Accessor Functions
|
||||
.Fn DPCPU_PTR "name"
|
||||
.Fn DPCPU_GET "name"
|
||||
.Fn DPCPU_SET "name" "value"
|
||||
.Ss Named CPU Accessor Functions
|
||||
.Fn DPCPU_ID_PTR "cpu" "name"
|
||||
.Fn DPCPU_ID_GET "cpu" "name"
|
||||
.Fn DPCPU_ID_SET "cpu" "name" "value"
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
instantiates one instance of a global variable with each CPU in the system.
|
||||
Dynamically allocated per-CPU variables are defined using
|
||||
.Fn DPCPU_DEFINE ,
|
||||
which defines a variable of name
|
||||
.Ar name
|
||||
and type
|
||||
.Ar type .
|
||||
Arbitrary C types may be used, including structures and arrays.
|
||||
If no initialization is provided, then each per-CPU instance of the variable
|
||||
will be zero-filled (i.e., as though allocated in BSS):
|
||||
.Bd -literal -offset 1234
|
||||
DPCPU_DEFINE(int, fooint);
|
||||
.Ed
|
||||
.Pp
|
||||
Values may also be initialized statically with the definition, causing each
|
||||
per-CPU instance to be initialized with the value:
|
||||
.Bd -literal -offset 1234
|
||||
DPCPU_DEFINE(int, fooint) = 1;
|
||||
.Ed
|
||||
.Pp
|
||||
Syntactically, the definition may be treated as a variable.
|
||||
For example, a dynamic per-CPU variable may be declared as
|
||||
.Dv static :
|
||||
.Bd -literal -offset 1234
|
||||
static DPCPU_DEFINE(int, fooint);
|
||||
.Ed
|
||||
.Pp
|
||||
.Fn DPCPU_DECLARE
|
||||
produces a declaration of the per-CPU variable suitable for use in header
|
||||
files.
|
||||
.Pp
|
||||
The current CPU's variable instance can be accessed via
|
||||
.Nm DPCPU_PTR
|
||||
(which returns a pointer to the per-CPU instance),
|
||||
.Nm DPCPU_GET
|
||||
(which retrieves the value of the per-CPU instance),
|
||||
and
|
||||
.Nm DPCPU_SET
|
||||
(which sets the value of the per-CPU instance).
|
||||
.Pp
|
||||
Instances of variables associated with specific CPUs can be accessed via the
|
||||
.Nm DPCPU_ID_PTR ,
|
||||
.Nm DPCPU_ID_GET ,
|
||||
and
|
||||
.Nm DPGPU_ID_SET
|
||||
accessor functions, which accept an additional CPU ID argument,
|
||||
.Ar cpu .
|
||||
.Ss Synchronization
|
||||
In addition to the ordinary synchronization concerns associated with global
|
||||
variables, which may imply the use of
|
||||
.Xr atomic 9 ,
|
||||
.Xr mutex 9 ,
|
||||
or other kernel synchronization primitives, it is further the case that
|
||||
thread migration could dynamically change the instance of a variable being
|
||||
accessed by a thread between operations.
|
||||
This requires additional care when reasoning about and protecting per-CPU
|
||||
variables.
|
||||
.Pp
|
||||
For example, it may be desirable to protect access using
|
||||
.Xr critical_section 9
|
||||
to prevent both preemption and migration during use.
|
||||
Alternatively, it may be desirable to cache the CPU ID at the start of a
|
||||
sequence of accesses, using suitable synchronization to make non-atomic
|
||||
sequences safe in the presence of migration.
|
||||
.Bd -literal -offset 1234
|
||||
static DPCPU_DEFINE(int, foo_int);
|
||||
static DPCPU_DEFINE(struct mutex, foo_lock);
|
||||
|
||||
void
|
||||
foo_int_increment(void)
|
||||
{
|
||||
int cpu, value;
|
||||
|
||||
/* Safe as atomic access. */
|
||||
atomic_add_int(DPCPU_PTR(foo_int), 1);
|
||||
|
||||
/*
|
||||
* Protect with a critical section, which prevents preemption
|
||||
* and migration. However, access to instances from remote CPUs
|
||||
* is not safe, as critical sections prevent concurrent access
|
||||
* only from the current CPU.
|
||||
*/
|
||||
critical_enter();
|
||||
value = DPCPU_GET(foo_int);
|
||||
value++;
|
||||
DPCPU_SET(foo_int, value);
|
||||
critical_exit();
|
||||
|
||||
/*
|
||||
* Protect with a per-CPU mutex, tolerating migration, but
|
||||
* potentially accessing the variable from multiple CPUs if
|
||||
* migration occurs after reading curcpu. Remote access to a
|
||||
* per-CPU variable is safe as long as the correct mutex is
|
||||
* acquired.
|
||||
*/
|
||||
cpu = curcpu;
|
||||
mtx_lock(DPCPU_ID_PTR(cpu, foo_lock));
|
||||
value = DPCPU_ID_GET(cpu, foo_int);
|
||||
value++;
|
||||
DPCPU_ID_SET(cpu, foo_int);
|
||||
mtx_unlock(DPCPU_ID_PTR(cpu, foo_lock));
|
||||
}
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr atomic 9 ,
|
||||
.Xr critical_enter 9 ,
|
||||
.Xr mutex 9
|
||||
.Sh HISTORY
|
||||
.Nm
|
||||
was first introduced by
|
||||
.An Jeff Roberson
|
||||
in
|
||||
.Fx 8.0 .
|
||||
This manual page was written by
|
||||
.An Robert N. M. Watson.
|
Loading…
Reference in New Issue
Block a user