€•@nŒsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ&/translations/zh_CN/core-api/local_ops”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ&/translations/zh_TW/core-api/local_ops”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ&/translations/it_IT/core-api/local_ops”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ&/translations/ja_JP/core-api/local_ops”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ&/translations/ko_KR/core-api/local_ops”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒPortuguese (Brazilian)”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ&/translations/pt_BR/core-api/local_ops”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ&/translations/sp_SP/core-api/local_ops”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒtarget”“”)”}”(hŒ.. _local_ops:”h]”h}”(h]”h ]”h"]”h$]”h&]”Œrefid”Œ local-ops”uh1hµh´Khhh²hh³Œ@/var/lib/git/docbuild/linux/Documentation/core-api/local_ops.rst”ubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒ1Semantics and Behavior of Local Atomic Operations”h]”hŒ1Semantics and Behavior of Local Atomic Operations”…””}”(hhËh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhhÆh²hh³hÃh´KubhŒ field_list”“”)”}”(hhh]”hŒfield”“”)”}”(hhh]”(hŒ field_name”“”)”}”(hŒAuthor”h]”hŒAuthor”…””}”(hhåh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hãhhàh³hÃh´KubhŒ field_body”“”)”}”(hŒMathieu Desnoyers ”h]”hŒ paragraph”“”)”}”(hŒMathieu Desnoyers”h]”hŒMathieu Desnoyers”…””}”(hhûh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´Khhõubah}”(h]”h ]”h"]”h$]”h&]”uh1hóhhàubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÞh³hÃh´KhhÛh²hubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙhhÆh²hh³hÃh´Kubhú)”}”(hX+This document explains the purpose of the local atomic operations, how to implement them for any given architecture and shows how they can be used properly. It also stresses on the precautions that must be taken when reading those local variables across CPUs when the order of memory writes matters.”h]”hX+This document explains the purpose of the local atomic operations, how to implement them for any given architecture and shows how they can be used properly. It also stresses on the precautions that must be taken when reading those local variables across CPUs when the order of memory writes matters.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´K hhÆh²hubhŒnote”“”)”}”(hXžNote that ``local_t`` based operations are not recommended for general kernel use. Please use the ``this_cpu`` operations instead unless there is really a special purpose. Most uses of ``local_t`` in the kernel have been replaced by ``this_cpu`` operations. ``this_cpu`` operations combine the relocation with the ``local_t`` like semantics in a single instruction and yield more compact and faster executing code.”h]”hú)”}”(hXžNote that ``local_t`` based operations are not recommended for general kernel use. Please use the ``this_cpu`` operations instead unless there is really a special purpose. Most uses of ``local_t`` in the kernel have been replaced by ``this_cpu`` operations. ``this_cpu`` operations combine the relocation with the ``local_t`` like semantics in a single instruction and yield more compact and faster executing code.”h]”(hŒ Note that ”…””}”(hj/h²hh³Nh´NubhŒliteral”“”)”}”(hŒ ``local_t``”h]”hŒlocal_t”…””}”(hj9h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj/ubhŒM based operations are not recommended for general kernel use. Please use the ”…””}”(hj/h²hh³Nh´Nubj8)”}”(hŒ ``this_cpu``”h]”hŒthis_cpu”…””}”(hjKh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj/ubhŒK operations instead unless there is really a special purpose. Most uses of ”…””}”(hj/h²hh³Nh´Nubj8)”}”(hŒ ``local_t``”h]”hŒlocal_t”…””}”(hj]h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj/ubhŒ% in the kernel have been replaced by ”…””}”(hj/h²hh³Nh´Nubj8)”}”(hŒ ``this_cpu``”h]”hŒthis_cpu”…””}”(hjoh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj/ubhŒ operations. ”…””}”(hj/h²hh³Nh´Nubj8)”}”(hŒ ``this_cpu``”h]”hŒthis_cpu”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj/ubhŒ, operations combine the relocation with the ”…””}”(hj/h²hh³Nh´Nubj8)”}”(hŒ ``local_t``”h]”hŒlocal_t”…””}”(hj“h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj/ubhŒY like semantics in a single instruction and yield more compact and faster executing code.”…””}”(hj/h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´Khj+ubah}”(h]”h ]”h"]”h$]”h&]”uh1j)hhÆh²hh³hÃh´NubhÅ)”}”(hhh]”(hÊ)”}”(hŒ"Purpose of local atomic operations”h]”hŒ"Purpose of local atomic operations”…””}”(hj´h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhj±h²hh³hÃh´Kubhú)”}”(hŒ÷Local atomic operations are meant to provide fast and highly reentrant per CPU counters. They minimize the performance cost of standard atomic operations by removing the LOCK prefix and memory barriers normally required to synchronize across CPUs.”h]”hŒ÷Local atomic operations are meant to provide fast and highly reentrant per CPU counters. They minimize the performance cost of standard atomic operations by removing the LOCK prefix and memory barriers normally required to synchronize across CPUs.”…””}”(hjÂh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´Khj±h²hubhú)”}”(hXHaving fast per CPU atomic counters is interesting in many cases: it does not require disabling interrupts to protect from interrupt handlers and it permits coherent counters in NMI handlers. It is especially useful for tracing purposes and for various performance monitoring counters.”h]”hXHaving fast per CPU atomic counters is interesting in many cases: it does not require disabling interrupts to protect from interrupt handlers and it permits coherent counters in NMI handlers. It is especially useful for tracing purposes and for various performance monitoring counters.”…””}”(hjÐh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´K"hj±h²hubhú)”}”(hXÅLocal atomic operations only guarantee variable modification atomicity wrt the CPU which owns the data. Therefore, care must taken to make sure that only one CPU writes to the ``local_t`` data. This is done by using per cpu data and making sure that we modify it from within a preemption safe context. It is however permitted to read ``local_t`` data from any CPU: it will then appear to be written out of order wrt other memory writes by the owner CPU.”h]”(hŒ°Local atomic operations only guarantee variable modification atomicity wrt the CPU which owns the data. Therefore, care must taken to make sure that only one CPU writes to the ”…””}”(hjÞh²hh³Nh´Nubj8)”}”(hŒ ``local_t``”h]”hŒlocal_t”…””}”(hjæh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÞubhŒ“ data. This is done by using per cpu data and making sure that we modify it from within a preemption safe context. It is however permitted to read ”…””}”(hjÞh²hh³Nh´Nubj8)”}”(hŒ ``local_t``”h]”hŒlocal_t”…””}”(hjøh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÞubhŒl data from any CPU: it will then appear to be written out of order wrt other memory writes by the owner CPU.”…””}”(hjÞh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´K'hj±h²hubeh}”(h]”Œ"purpose-of-local-atomic-operations”ah ]”h"]”Œ"purpose of local atomic operations”ah$]”h&]”uh1hÄhhÆh²hh³hÃh´KubhÅ)”}”(hhh]”(hÊ)”}”(hŒ'Implementation for a given architecture”h]”hŒ'Implementation for a given architecture”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhjh²hh³hÃh´K0ubhú)”}”(hXiIt can be done by slightly modifying the standard atomic operations: only their UP variant must be kept. It typically means removing LOCK prefix (on i386 and x86_64) and any SMP synchronization barrier. If the architecture does not have a different behavior between SMP and UP, including ``asm-generic/local.h`` in your architecture's ``local.h`` is sufficient.”h]”(hX It can be done by slightly modifying the standard atomic operations: only their UP variant must be kept. It typically means removing LOCK prefix (on i386 and x86_64) and any SMP synchronization barrier. If the architecture does not have a different behavior between SMP and UP, including ”…””}”(hj)h²hh³Nh´Nubj8)”}”(hŒ``asm-generic/local.h``”h]”hŒasm-generic/local.h”…””}”(hj1h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj)ubhŒ in your architecture’s ”…””}”(hj)h²hh³Nh´Nubj8)”}”(hŒ ``local.h``”h]”hŒlocal.h”…””}”(hjCh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj)ubhŒ is sufficient.”…””}”(hj)h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´K2hjh²hubhú)”}”(hŒÉThe ``local_t`` type is defined as an opaque ``signed long`` by embedding an ``atomic_long_t`` inside a structure. This is made so a cast from this type to a ``long`` fails. The definition looks like::”h]”(hŒThe ”…””}”(hj[h²hh³Nh´Nubj8)”}”(hŒ ``local_t``”h]”hŒlocal_t”…””}”(hjch²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj[ubhŒ type is defined as an opaque ”…””}”(hj[h²hh³Nh´Nubj8)”}”(hŒ``signed long``”h]”hŒ signed long”…””}”(hjuh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj[ubhŒ by embedding an ”…””}”(hj[h²hh³Nh´Nubj8)”}”(hŒ``atomic_long_t``”h]”hŒ atomic_long_t”…””}”(hj‡h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj[ubhŒ@ inside a structure. This is made so a cast from this type to a ”…””}”(hj[h²hh³Nh´Nubj8)”}”(hŒ``long``”h]”hŒlong”…””}”(hj™h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj[ubhŒ" fails. The definition looks like:”…””}”(hj[h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´K8hjh²hubhŒ literal_block”“”)”}”(hŒ,typedef struct { atomic_long_t a; } local_t;”h]”hŒ,typedef struct { atomic_long_t a; } local_t;”…””}”hj³sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1j±h³hÃh´K #include static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);”h]”hŒk#include #include static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);”…””}”hjðsbah}”(h]”h ]”h"]”h$]”h&]”jÁjÂuh1j±h³hÃh´K\hjßh²hubeh}”(h]”Œ"how-to-use-local-atomic-operations”ah ]”h"]”Œ"how to use local atomic operations”ah$]”h&]”uh1hÄhhÆh²hh³hÃh´KXubhÅ)”}”(hhh]”(hÊ)”}”(hŒCounting”h]”hŒCounting”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhjh²hh³hÃh´Kcubhú)”}”(hŒ2Counting is done on all the bits of a signed long.”h]”hŒ2Counting is done on all the bits of a signed long.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´Kehjh²hubhú)”}”(hŒÉIn preemptible context, use ``get_cpu_var()`` and ``put_cpu_var()`` around local atomic operations: it makes sure that preemption is disabled around write access to the per cpu variable. For instance::”h]”(hŒIn preemptible context, use ”…””}”(hj%h²hh³Nh´Nubj8)”}”(hŒ``get_cpu_var()``”h]”hŒ get_cpu_var()”…””}”(hj-h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj%ubhŒ and ”…””}”(hj%h²hh³Nh´Nubj8)”}”(hŒ``put_cpu_var()``”h]”hŒ put_cpu_var()”…””}”(hj?h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj%ubhŒ… around local atomic operations: it makes sure that preemption is disabled around write access to the per cpu variable. For instance:”…””}”(hj%h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´Kghjh²hubj²)”}”(hŒ9local_inc(&get_cpu_var(counters)); put_cpu_var(counters);”h]”hŒ9local_inc(&get_cpu_var(counters)); put_cpu_var(counters);”…””}”hjWsbah}”(h]”h ]”h"]”h$]”h&]”jÁjÂuh1j±h³hÃh´Kkhjh²hubhú)”}”(hŒYIf you are already in a preemption-safe context, you can use ``this_cpu_ptr()`` instead::”h]”(hŒ=If you are already in a preemption-safe context, you can use ”…””}”(hjeh²hh³Nh´Nubj8)”}”(hŒ``this_cpu_ptr()``”h]”hŒthis_cpu_ptr()”…””}”(hjmh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjeubhŒ instead:”…””}”(hjeh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´Knhjh²hubj²)”}”(hŒ#local_inc(this_cpu_ptr(&counters));”h]”hŒ#local_inc(this_cpu_ptr(&counters));”…””}”hj…sbah}”(h]”h ]”h"]”h$]”h&]”jÁjÂuh1j±h³hÃh´Kqhjh²hubeh}”(h]”Œcounting”ah ]”h"]”Œcounting”ah$]”h&]”uh1hÄhhÆh²hh³hÃh´KcubhÅ)”}”(hhh]”(hÊ)”}”(hŒReading the counters”h]”hŒReading the counters”…””}”(hjžh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhj›h²hh³hÃh´Kvubhú)”}”(hŒèThose local counters can be read from foreign CPUs to sum the count. Note that the data seen by local_read across CPUs must be considered to be out of order relatively to other memory writes happening on the CPU that owns the data::”h]”hŒçThose local counters can be read from foreign CPUs to sum the count. Note that the data seen by local_read across CPUs must be considered to be out of order relatively to other memory writes happening on the CPU that owns the data:”…””}”(hj¬h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´Kxhj›h²hubj²)”}”(hŒZlong sum = 0; for_each_online_cpu(cpu) sum += local_read(&per_cpu(counters, cpu));”h]”hŒZlong sum = 0; for_each_online_cpu(cpu) sum += local_read(&per_cpu(counters, cpu));”…””}”hjºsbah}”(h]”h ]”h"]”h$]”h&]”jÁjÂuh1j±h³hÃh´K|hj›h²hubhú)”}”(hXÌIf you want to use a remote local_read to synchronize access to a resource between CPUs, explicit ``smp_wmb()`` and ``smp_rmb()`` memory barriers must be used respectively on the writer and the reader CPUs. It would be the case if you use the ``local_t`` variable as a counter of bytes written in a buffer: there should be a ``smp_wmb()`` between the buffer write and the counter increment and also a ``smp_rmb()`` between the counter read and the buffer read.”h]”(hŒbIf you want to use a remote local_read to synchronize access to a resource between CPUs, explicit ”…””}”(hjÈh²hh³Nh´Nubj8)”}”(hŒ ``smp_wmb()``”h]”hŒ smp_wmb()”…””}”(hjÐh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÈubhŒ and ”…””}”(hjÈh²hh³Nh´Nubj8)”}”(hŒ ``smp_rmb()``”h]”hŒ smp_rmb()”…””}”(hjâh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÈubhŒr memory barriers must be used respectively on the writer and the reader CPUs. It would be the case if you use the ”…””}”(hjÈh²hh³Nh´Nubj8)”}”(hŒ ``local_t``”h]”hŒlocal_t”…””}”(hjôh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÈubhŒG variable as a counter of bytes written in a buffer: there should be a ”…””}”(hjÈh²hh³Nh´Nubj8)”}”(hŒ ``smp_wmb()``”h]”hŒ smp_wmb()”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÈubhŒ? between the buffer write and the counter increment and also a ”…””}”(hjÈh²hh³Nh´Nubj8)”}”(hŒ ``smp_rmb()``”h]”hŒ smp_rmb()”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hjÈubhŒ. between the counter read and the buffer read.”…””}”(hjÈh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´K€hj›h²hubhú)”}”(hŒTHere is a sample module which implements a basic per cpu counter using ``local.h``::”h]”(hŒGHere is a sample module which implements a basic per cpu counter using ”…””}”(hj0h²hh³Nh´Nubj8)”}”(hŒ ``local.h``”h]”hŒlocal.h”…””}”(hj8h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j7hj0ubhŒ:”…””}”(hj0h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hùh³hÃh´Kˆhj›h²hubj²)”}”(hXY/* test-local.c * * Sample module for local.h usage. */ #include #include #include static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0); static struct timer_list test_timer; /* IPI called on each CPU. */ static void test_each(void *info) { /* Increment the counter from a non preemptible context */ printk("Increment on cpu %d\n", smp_processor_id()); local_inc(this_cpu_ptr(&counters)); /* This is what incrementing the variable would look like within a * preemptible context (it disables preemption) : * * local_inc(&get_cpu_var(counters)); * put_cpu_var(counters); */ } static void do_test_timer(unsigned long data) { int cpu; /* Increment the counters */ on_each_cpu(test_each, NULL, 1); /* Read all the counters */ printk("Counters read from CPU %d\n", smp_processor_id()); for_each_online_cpu(cpu) { printk("Read : CPU %d, count %ld\n", cpu, local_read(&per_cpu(counters, cpu))); } mod_timer(&test_timer, jiffies + 1000); } static int __init test_init(void) { /* initialize the timer that will increment the counter */ timer_setup(&test_timer, do_test_timer, 0); mod_timer(&test_timer, jiffies + 1); return 0; } static void __exit test_exit(void) { timer_shutdown_sync(&test_timer); } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mathieu Desnoyers"); MODULE_DESCRIPTION("Local Atomic Ops");”h]”hXY/* test-local.c * * Sample module for local.h usage. */ #include #include #include static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0); static struct timer_list test_timer; /* IPI called on each CPU. */ static void test_each(void *info) { /* Increment the counter from a non preemptible context */ printk("Increment on cpu %d\n", smp_processor_id()); local_inc(this_cpu_ptr(&counters)); /* This is what incrementing the variable would look like within a * preemptible context (it disables preemption) : * * local_inc(&get_cpu_var(counters)); * put_cpu_var(counters); */ } static void do_test_timer(unsigned long data) { int cpu; /* Increment the counters */ on_each_cpu(test_each, NULL, 1); /* Read all the counters */ printk("Counters read from CPU %d\n", smp_processor_id()); for_each_online_cpu(cpu) { printk("Read : CPU %d, count %ld\n", cpu, local_read(&per_cpu(counters, cpu))); } mod_timer(&test_timer, jiffies + 1000); } static int __init test_init(void) { /* initialize the timer that will increment the counter */ timer_setup(&test_timer, do_test_timer, 0); mod_timer(&test_timer, jiffies + 1); return 0; } static void __exit test_exit(void) { timer_shutdown_sync(&test_timer); } module_init(test_init); module_exit(test_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mathieu Desnoyers"); MODULE_DESCRIPTION("Local Atomic Ops");”…””}”hjPsbah}”(h]”h ]”h"]”h$]”h&]”jÁjÂuh1j±h³hÃh´K‹hj›h²hubeh}”(h]”Œreading-the-counters”ah ]”h"]”Œreading the counters”ah$]”h&]”uh1hÄhhÆh²hh³hÃh´Kvubeh}”(h]”(Œ1semantics-and-behavior-of-local-atomic-operations”hÂeh ]”h"]”(Œ1semantics and behavior of local atomic operations”Œ local_ops”eh$]”h&]”uh1hÄhhh²hh³hÃh´KŒexpect_referenced_by_name”}”jlh·sŒexpect_referenced_by_id”}”hÂh·subeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÃuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(hÉNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”j–Œerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÃŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”hÂ]”h·asŒnameids”}”(jlhÂjkjhjjjÈjÅjÜjÙjjj˜j•jcj`uŒ nametypes”}”(jlˆjk‰j‰jȉj܉j‰j˜‰jc‰uh}”(hÂhÆjhhÆjj±jÅjjÙjËjjßj•jj`j›uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”hŒsystem_message”“”)”}”(hhh]”hú)”}”(hhh]”hŒ/Hyperlink target "local-ops" is not referenced.”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”uh1hùhjýubah}”(h]”h ]”h"]”h$]”h&]”Œlevel”KŒtype”ŒINFO”Œsource”hÃŒline”Kuh1jûubaŒ transformer”NŒ include_log”]”Œ decoration”Nh²hub.