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 \
|
disk.9 \
|
||||||
dnv.9 \
|
dnv.9 \
|
||||||
domain.9 \
|
domain.9 \
|
||||||
|
dpcpu.9 \
|
||||||
drbr.9 \
|
drbr.9 \
|
||||||
driver.9 \
|
driver.9 \
|
||||||
DRIVER_MODULE.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