xref: /OK3568_Linux_fs/kernel/Documentation/core-api/local_ops.rst (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun
2*4882a593Smuzhiyun.. _local_ops:
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun=================================================
5*4882a593SmuzhiyunSemantics and Behavior of Local Atomic Operations
6*4882a593Smuzhiyun=================================================
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun:Author: Mathieu Desnoyers
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun
11*4882a593SmuzhiyunThis document explains the purpose of the local atomic operations, how
12*4882a593Smuzhiyunto implement them for any given architecture and shows how they can be used
13*4882a593Smuzhiyunproperly. It also stresses on the precautions that must be taken when reading
14*4882a593Smuzhiyunthose local variables across CPUs when the order of memory writes matters.
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun.. note::
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun    Note that ``local_t`` based operations are not recommended for general
19*4882a593Smuzhiyun    kernel use. Please use the ``this_cpu`` operations instead unless there is
20*4882a593Smuzhiyun    really a special purpose. Most uses of ``local_t`` in the kernel have been
21*4882a593Smuzhiyun    replaced by ``this_cpu`` operations. ``this_cpu`` operations combine the
22*4882a593Smuzhiyun    relocation with the ``local_t`` like semantics in a single instruction and
23*4882a593Smuzhiyun    yield more compact and faster executing code.
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun
26*4882a593SmuzhiyunPurpose of local atomic operations
27*4882a593Smuzhiyun==================================
28*4882a593Smuzhiyun
29*4882a593SmuzhiyunLocal atomic operations are meant to provide fast and highly reentrant per CPU
30*4882a593Smuzhiyuncounters. They minimize the performance cost of standard atomic operations by
31*4882a593Smuzhiyunremoving the LOCK prefix and memory barriers normally required to synchronize
32*4882a593Smuzhiyunacross CPUs.
33*4882a593Smuzhiyun
34*4882a593SmuzhiyunHaving fast per CPU atomic counters is interesting in many cases: it does not
35*4882a593Smuzhiyunrequire disabling interrupts to protect from interrupt handlers and it permits
36*4882a593Smuzhiyuncoherent counters in NMI handlers. It is especially useful for tracing purposes
37*4882a593Smuzhiyunand for various performance monitoring counters.
38*4882a593Smuzhiyun
39*4882a593SmuzhiyunLocal atomic operations only guarantee variable modification atomicity wrt the
40*4882a593SmuzhiyunCPU which owns the data. Therefore, care must taken to make sure that only one
41*4882a593SmuzhiyunCPU writes to the ``local_t`` data. This is done by using per cpu data and
42*4882a593Smuzhiyunmaking sure that we modify it from within a preemption safe context. It is
43*4882a593Smuzhiyunhowever permitted to read ``local_t`` data from any CPU: it will then appear to
44*4882a593Smuzhiyunbe written out of order wrt other memory writes by the owner CPU.
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun
47*4882a593SmuzhiyunImplementation for a given architecture
48*4882a593Smuzhiyun=======================================
49*4882a593Smuzhiyun
50*4882a593SmuzhiyunIt can be done by slightly modifying the standard atomic operations: only
51*4882a593Smuzhiyuntheir UP variant must be kept. It typically means removing LOCK prefix (on
52*4882a593Smuzhiyuni386 and x86_64) and any SMP synchronization barrier. If the architecture does
53*4882a593Smuzhiyunnot have a different behavior between SMP and UP, including
54*4882a593Smuzhiyun``asm-generic/local.h`` in your architecture's ``local.h`` is sufficient.
55*4882a593Smuzhiyun
56*4882a593SmuzhiyunThe ``local_t`` type is defined as an opaque ``signed long`` by embedding an
57*4882a593Smuzhiyun``atomic_long_t`` inside a structure. This is made so a cast from this type to
58*4882a593Smuzhiyuna ``long`` fails. The definition looks like::
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun    typedef struct { atomic_long_t a; } local_t;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun
63*4882a593SmuzhiyunRules to follow when using local atomic operations
64*4882a593Smuzhiyun==================================================
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun* Variables touched by local ops must be per cpu variables.
67*4882a593Smuzhiyun* *Only* the CPU owner of these variables must write to them.
68*4882a593Smuzhiyun* This CPU can use local ops from any context (process, irq, softirq, nmi, ...)
69*4882a593Smuzhiyun  to update its ``local_t`` variables.
70*4882a593Smuzhiyun* Preemption (or interrupts) must be disabled when using local ops in
71*4882a593Smuzhiyun  process context to make sure the process won't be migrated to a
72*4882a593Smuzhiyun  different CPU between getting the per-cpu variable and doing the
73*4882a593Smuzhiyun  actual local op.
74*4882a593Smuzhiyun* When using local ops in interrupt context, no special care must be
75*4882a593Smuzhiyun  taken on a mainline kernel, since they will run on the local CPU with
76*4882a593Smuzhiyun  preemption already disabled. I suggest, however, to explicitly
77*4882a593Smuzhiyun  disable preemption anyway to make sure it will still work correctly on
78*4882a593Smuzhiyun  -rt kernels.
79*4882a593Smuzhiyun* Reading the local cpu variable will provide the current copy of the
80*4882a593Smuzhiyun  variable.
81*4882a593Smuzhiyun* Reads of these variables can be done from any CPU, because updates to
82*4882a593Smuzhiyun  "``long``", aligned, variables are always atomic. Since no memory
83*4882a593Smuzhiyun  synchronization is done by the writer CPU, an outdated copy of the
84*4882a593Smuzhiyun  variable can be read when reading some *other* cpu's variables.
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun
87*4882a593SmuzhiyunHow to use local atomic operations
88*4882a593Smuzhiyun==================================
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun::
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun    #include <linux/percpu.h>
93*4882a593Smuzhiyun    #include <asm/local.h>
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun    static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun
98*4882a593SmuzhiyunCounting
99*4882a593Smuzhiyun========
100*4882a593Smuzhiyun
101*4882a593SmuzhiyunCounting is done on all the bits of a signed long.
102*4882a593Smuzhiyun
103*4882a593SmuzhiyunIn preemptible context, use ``get_cpu_var()`` and ``put_cpu_var()`` around
104*4882a593Smuzhiyunlocal atomic operations: it makes sure that preemption is disabled around write
105*4882a593Smuzhiyunaccess to the per cpu variable. For instance::
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun    local_inc(&get_cpu_var(counters));
108*4882a593Smuzhiyun    put_cpu_var(counters);
109*4882a593Smuzhiyun
110*4882a593SmuzhiyunIf you are already in a preemption-safe context, you can use
111*4882a593Smuzhiyun``this_cpu_ptr()`` instead::
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun    local_inc(this_cpu_ptr(&counters));
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun
117*4882a593SmuzhiyunReading the counters
118*4882a593Smuzhiyun====================
119*4882a593Smuzhiyun
120*4882a593SmuzhiyunThose local counters can be read from foreign CPUs to sum the count. Note that
121*4882a593Smuzhiyunthe data seen by local_read across CPUs must be considered to be out of order
122*4882a593Smuzhiyunrelatively to other memory writes happening on the CPU that owns the data::
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun    long sum = 0;
125*4882a593Smuzhiyun    for_each_online_cpu(cpu)
126*4882a593Smuzhiyun            sum += local_read(&per_cpu(counters, cpu));
127*4882a593Smuzhiyun
128*4882a593SmuzhiyunIf you want to use a remote local_read to synchronize access to a resource
129*4882a593Smuzhiyunbetween CPUs, explicit ``smp_wmb()`` and ``smp_rmb()`` memory barriers must be used
130*4882a593Smuzhiyunrespectively on the writer and the reader CPUs. It would be the case if you use
131*4882a593Smuzhiyunthe ``local_t`` variable as a counter of bytes written in a buffer: there should
132*4882a593Smuzhiyunbe a ``smp_wmb()`` between the buffer write and the counter increment and also a
133*4882a593Smuzhiyun``smp_rmb()`` between the counter read and the buffer read.
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun
136*4882a593SmuzhiyunHere is a sample module which implements a basic per cpu counter using
137*4882a593Smuzhiyun``local.h``::
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun    /* test-local.c
140*4882a593Smuzhiyun     *
141*4882a593Smuzhiyun     * Sample module for local.h usage.
142*4882a593Smuzhiyun     */
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun    #include <asm/local.h>
146*4882a593Smuzhiyun    #include <linux/module.h>
147*4882a593Smuzhiyun    #include <linux/timer.h>
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun    static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun    static struct timer_list test_timer;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun    /* IPI called on each CPU. */
154*4882a593Smuzhiyun    static void test_each(void *info)
155*4882a593Smuzhiyun    {
156*4882a593Smuzhiyun            /* Increment the counter from a non preemptible context */
157*4882a593Smuzhiyun            printk("Increment on cpu %d\n", smp_processor_id());
158*4882a593Smuzhiyun            local_inc(this_cpu_ptr(&counters));
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun            /* This is what incrementing the variable would look like within a
161*4882a593Smuzhiyun             * preemptible context (it disables preemption) :
162*4882a593Smuzhiyun             *
163*4882a593Smuzhiyun             * local_inc(&get_cpu_var(counters));
164*4882a593Smuzhiyun             * put_cpu_var(counters);
165*4882a593Smuzhiyun             */
166*4882a593Smuzhiyun    }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun    static void do_test_timer(unsigned long data)
169*4882a593Smuzhiyun    {
170*4882a593Smuzhiyun            int cpu;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun            /* Increment the counters */
173*4882a593Smuzhiyun            on_each_cpu(test_each, NULL, 1);
174*4882a593Smuzhiyun            /* Read all the counters */
175*4882a593Smuzhiyun            printk("Counters read from CPU %d\n", smp_processor_id());
176*4882a593Smuzhiyun            for_each_online_cpu(cpu) {
177*4882a593Smuzhiyun                    printk("Read : CPU %d, count %ld\n", cpu,
178*4882a593Smuzhiyun                            local_read(&per_cpu(counters, cpu)));
179*4882a593Smuzhiyun            }
180*4882a593Smuzhiyun            mod_timer(&test_timer, jiffies + 1000);
181*4882a593Smuzhiyun    }
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun    static int __init test_init(void)
184*4882a593Smuzhiyun    {
185*4882a593Smuzhiyun            /* initialize the timer that will increment the counter */
186*4882a593Smuzhiyun            timer_setup(&test_timer, do_test_timer, 0);
187*4882a593Smuzhiyun            mod_timer(&test_timer, jiffies + 1);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun            return 0;
190*4882a593Smuzhiyun    }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun    static void __exit test_exit(void)
193*4882a593Smuzhiyun    {
194*4882a593Smuzhiyun            del_timer_sync(&test_timer);
195*4882a593Smuzhiyun    }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun    module_init(test_init);
198*4882a593Smuzhiyun    module_exit(test_exit);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun    MODULE_LICENSE("GPL");
201*4882a593Smuzhiyun    MODULE_AUTHOR("Mathieu Desnoyers");
202*4882a593Smuzhiyun    MODULE_DESCRIPTION("Local Atomic Ops");
203