FreeBSD manual

download PDF document: dpcpu.9.pdf

DPCPU(9) FreeBSD Kernel Developer's Manual DPCPU(9)
NAME dpcpu - Kernel Dynamic Per-CPU Memory Allocator
SYNOPSIS #include <sys/pcpu.h>
Per-CPU Variable Definition and Declaration DPCPU_DEFINE(type, name);
DPCPU_DEFINE_STATIC(type, name);
DPCPU_DECLARE(type, name);
Current CPU Accessor Functions DPCPU_PTR(name);
DPCPU_GET(name);
DPCPU_SET(name, value);
Named CPU Accessor Functions DPCPU_ID_PTR(cpu, name);
DPCPU_ID_GET(cpu, name);
DPCPU_ID_SET(cpu, name, value);
DESCRIPTION dpcpu instantiates one instance of a global variable with each CPU in the system. Dynamically allocated per-CPU variables are defined using DPCPU_DEFINE(), which defines a variable of name name and type 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):
DPCPU_DEFINE(int, foo_int);
Values may also be initialized statically with the definition, causing each per-CPU instance to be initialized with the value:
DPCPU_DEFINE(int, foo_int) = 1;
Values that can be defined as static must use DPCPU_DEFINE_STATIC():
DPCPU_DEFINE_STATIC(int, foo_int);
DPCPU_DECLARE() produces a declaration of the per-CPU variable suitable for use in header files.
The current CPU's variable instance can be accessed via DPCPU_PTR (which returns a pointer to the per-CPU instance), DPCPU_GET (which retrieves the value of the per-CPU instance), and DPCPU_SET (which sets the value of the per-CPU instance).
Instances of variables associated with specific CPUs can be accessed via the DPCPU_ID_PTR, DPCPU_ID_GET, and DPGPU_ID_SET accessor functions, which accept an additional CPU ID argument, cpu. care when reasoning about and protecting per-CPU variables.
For example, it may be desirable to protect access using 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.
DPCPU_DEFINE_STATIC(int, foo_int); DPCPU_DEFINE_STATIC(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)); }
SEE ALSO atomic(9), critical_enter(9), mutex(9)
HISTORY dpcpu was first introduced by Jeff Roberson in FreeBSD 8.0. This manual page was written by Robert N. M. Watson.
FreeBSD 14.2-RELEASE July 5, 2018 FreeBSD 14.2-RELEASE