|
NAMEdpcpu —
Kernel Dynamic Per-CPU Memory Allocator
SYNOPSIS#include <sys/pcpu.h>
Per-CPU Variable Definition and DeclarationDPCPU_DEFINE (type,
name);
Current CPU Accessor FunctionsDPCPU_PTR (name);
Named CPU Accessor FunctionsDPCPU_ID_PTR (cpu,
name);
DESCRIPTIONdpcpu 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 DPCPU_DEFINE_STATIC(int, foo_int);
The current CPU's variable instance can be accessed via
Instances of variables associated with specific CPUs can be
accessed via the SynchronizationIn addition to the ordinary synchronization concerns associated with global variables, which may imply the use of atomic(9), 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.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 ALSOatomic(9), critical_enter(9), mutex(9)HISTORYdpcpu was first introduced by Jeff
Roberson in FreeBSD 8.0. This manual page was
written by Robert N. M. Watson.
Visit the GSP FreeBSD Man Page Interface. |