18509f632SRobert Watson.\"- 28509f632SRobert Watson.\" Copyright (c) 2017 Robert N. M. Watson 38509f632SRobert Watson.\" All rights reserved. 48509f632SRobert Watson.\" 58509f632SRobert Watson.\" Redistribution and use in source and binary forms, with or without 68509f632SRobert Watson.\" modification, are permitted provided that the following conditions 78509f632SRobert Watson.\" are met: 88509f632SRobert Watson.\" 1. Redistributions of source code must retain the above copyright 98509f632SRobert Watson.\" notice, this list of conditions and the following disclaimer. 108509f632SRobert Watson.\" 2. Redistributions in binary form must reproduce the above copyright 118509f632SRobert Watson.\" notice, this list of conditions and the following disclaimer in the 128509f632SRobert Watson.\" documentation and/or other materials provided with the distribution. 138509f632SRobert Watson.\" 148509f632SRobert Watson.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158509f632SRobert Watson.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168509f632SRobert Watson.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178509f632SRobert Watson.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188509f632SRobert Watson.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198509f632SRobert Watson.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208509f632SRobert Watson.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218509f632SRobert Watson.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228509f632SRobert Watson.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238509f632SRobert Watson.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248509f632SRobert Watson.\" SUCH DAMAGE. 258509f632SRobert Watson.\" 26*2bf95012SAndrew Turner.Dd July 5, 2018 278509f632SRobert Watson.Dt DPCPU 9 288509f632SRobert Watson.Os 298509f632SRobert Watson.Sh NAME 308509f632SRobert Watson.Nm dpcpu 318509f632SRobert Watson.Nd Kernel Dynamic Per-CPU Memory Allocator 328509f632SRobert Watson.Sh SYNOPSIS 338509f632SRobert Watson.In sys/pcpu.h 348509f632SRobert Watson.Ss Per-CPU Variable Definition and Declaration 358509f632SRobert Watson.Fn DPCPU_DEFINE "type" "name" 36*2bf95012SAndrew Turner.Fn DPCPU_DEFINE_STATIC "type" "name" 378509f632SRobert Watson.Fn DPCPU_DECLARE "type" "name" 388509f632SRobert Watson.Ss Current CPU Accessor Functions 398509f632SRobert Watson.Fn DPCPU_PTR "name" 408509f632SRobert Watson.Fn DPCPU_GET "name" 418509f632SRobert Watson.Fn DPCPU_SET "name" "value" 428509f632SRobert Watson.Ss Named CPU Accessor Functions 438509f632SRobert Watson.Fn DPCPU_ID_PTR "cpu" "name" 448509f632SRobert Watson.Fn DPCPU_ID_GET "cpu" "name" 458509f632SRobert Watson.Fn DPCPU_ID_SET "cpu" "name" "value" 468509f632SRobert Watson.Sh DESCRIPTION 478509f632SRobert Watson.Nm 488509f632SRobert Watsoninstantiates one instance of a global variable with each CPU in the system. 498509f632SRobert WatsonDynamically allocated per-CPU variables are defined using 508509f632SRobert Watson.Fn DPCPU_DEFINE , 518509f632SRobert Watsonwhich defines a variable of name 528509f632SRobert Watson.Ar name 538509f632SRobert Watsonand type 548509f632SRobert Watson.Ar type . 558509f632SRobert WatsonArbitrary C types may be used, including structures and arrays. 568509f632SRobert WatsonIf no initialization is provided, then each per-CPU instance of the variable 578509f632SRobert Watsonwill be zero-filled (i.e., as though allocated in BSS): 588509f632SRobert Watson.Bd -literal -offset 1234 592cb46844SRobert WatsonDPCPU_DEFINE(int, foo_int); 608509f632SRobert Watson.Ed 618509f632SRobert Watson.Pp 628509f632SRobert WatsonValues may also be initialized statically with the definition, causing each 638509f632SRobert Watsonper-CPU instance to be initialized with the value: 648509f632SRobert Watson.Bd -literal -offset 1234 652cb46844SRobert WatsonDPCPU_DEFINE(int, foo_int) = 1; 668509f632SRobert Watson.Ed 678509f632SRobert Watson.Pp 68*2bf95012SAndrew TurnerValues that can be defined as 69*2bf95012SAndrew Turner.Dv static 70*2bf95012SAndrew Turnermust use 71*2bf95012SAndrew Turner.Fn DPCPU_DEFINE_STATIC : 728509f632SRobert Watson.Bd -literal -offset 1234 73*2bf95012SAndrew TurnerDPCPU_DEFINE_STATIC(int, foo_int); 748509f632SRobert Watson.Ed 758509f632SRobert Watson.Pp 768509f632SRobert Watson.Fn DPCPU_DECLARE 778509f632SRobert Watsonproduces a declaration of the per-CPU variable suitable for use in header 788509f632SRobert Watsonfiles. 798509f632SRobert Watson.Pp 808509f632SRobert WatsonThe current CPU's variable instance can be accessed via 818509f632SRobert Watson.Nm DPCPU_PTR 828509f632SRobert Watson(which returns a pointer to the per-CPU instance), 838509f632SRobert Watson.Nm DPCPU_GET 848509f632SRobert Watson(which retrieves the value of the per-CPU instance), 858509f632SRobert Watsonand 868509f632SRobert Watson.Nm DPCPU_SET 878509f632SRobert Watson(which sets the value of the per-CPU instance). 888509f632SRobert Watson.Pp 898509f632SRobert WatsonInstances of variables associated with specific CPUs can be accessed via the 908509f632SRobert Watson.Nm DPCPU_ID_PTR , 918509f632SRobert Watson.Nm DPCPU_ID_GET , 928509f632SRobert Watsonand 938509f632SRobert Watson.Nm DPGPU_ID_SET 948509f632SRobert Watsonaccessor functions, which accept an additional CPU ID argument, 958509f632SRobert Watson.Ar cpu . 968509f632SRobert Watson.Ss Synchronization 978509f632SRobert WatsonIn addition to the ordinary synchronization concerns associated with global 988509f632SRobert Watsonvariables, which may imply the use of 998509f632SRobert Watson.Xr atomic 9 , 1008509f632SRobert Watson.Xr mutex 9 , 1018509f632SRobert Watsonor other kernel synchronization primitives, it is further the case that 1028509f632SRobert Watsonthread migration could dynamically change the instance of a variable being 1038509f632SRobert Watsonaccessed by a thread between operations. 1048509f632SRobert WatsonThis requires additional care when reasoning about and protecting per-CPU 1058509f632SRobert Watsonvariables. 1068509f632SRobert Watson.Pp 1078509f632SRobert WatsonFor example, it may be desirable to protect access using 1088509f632SRobert Watson.Xr critical_section 9 1098509f632SRobert Watsonto prevent both preemption and migration during use. 1108509f632SRobert WatsonAlternatively, it may be desirable to cache the CPU ID at the start of a 1118509f632SRobert Watsonsequence of accesses, using suitable synchronization to make non-atomic 1128509f632SRobert Watsonsequences safe in the presence of migration. 1138509f632SRobert Watson.Bd -literal -offset 1234 114*2bf95012SAndrew TurnerDPCPU_DEFINE_STATIC(int, foo_int); 115*2bf95012SAndrew TurnerDPCPU_DEFINE_STATIC(struct mutex, foo_lock); 1168509f632SRobert Watson 1178509f632SRobert Watsonvoid 1188509f632SRobert Watsonfoo_int_increment(void) 1198509f632SRobert Watson{ 1208509f632SRobert Watson int cpu, value; 1218509f632SRobert Watson 1228509f632SRobert Watson /* Safe as atomic access. */ 1238509f632SRobert Watson atomic_add_int(DPCPU_PTR(foo_int), 1); 1248509f632SRobert Watson 1258509f632SRobert Watson /* 1268509f632SRobert Watson * Protect with a critical section, which prevents preemption 1278509f632SRobert Watson * and migration. However, access to instances from remote CPUs 1288509f632SRobert Watson * is not safe, as critical sections prevent concurrent access 1298509f632SRobert Watson * only from the current CPU. 1308509f632SRobert Watson */ 1318509f632SRobert Watson critical_enter(); 1328509f632SRobert Watson value = DPCPU_GET(foo_int); 1338509f632SRobert Watson value++; 1348509f632SRobert Watson DPCPU_SET(foo_int, value); 1358509f632SRobert Watson critical_exit(); 1368509f632SRobert Watson 1378509f632SRobert Watson /* 1388509f632SRobert Watson * Protect with a per-CPU mutex, tolerating migration, but 1398509f632SRobert Watson * potentially accessing the variable from multiple CPUs if 1408509f632SRobert Watson * migration occurs after reading curcpu. Remote access to a 1418509f632SRobert Watson * per-CPU variable is safe as long as the correct mutex is 1428509f632SRobert Watson * acquired. 1438509f632SRobert Watson */ 1448509f632SRobert Watson cpu = curcpu; 1458509f632SRobert Watson mtx_lock(DPCPU_ID_PTR(cpu, foo_lock)); 1468509f632SRobert Watson value = DPCPU_ID_GET(cpu, foo_int); 1478509f632SRobert Watson value++; 1488509f632SRobert Watson DPCPU_ID_SET(cpu, foo_int); 1498509f632SRobert Watson mtx_unlock(DPCPU_ID_PTR(cpu, foo_lock)); 1508509f632SRobert Watson} 1518509f632SRobert Watson.Ed 1528509f632SRobert Watson.Sh SEE ALSO 1538509f632SRobert Watson.Xr atomic 9 , 1548509f632SRobert Watson.Xr critical_enter 9 , 1558509f632SRobert Watson.Xr mutex 9 1568509f632SRobert Watson.Sh HISTORY 1578509f632SRobert Watson.Nm 1588509f632SRobert Watsonwas first introduced by 1598509f632SRobert Watson.An Jeff Roberson 1608509f632SRobert Watsonin 1618509f632SRobert Watson.Fx 8.0 . 1628509f632SRobert WatsonThis manual page was written by 1638509f632SRobert Watson.An Robert N. M. Watson . 164