vtsphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextEnglish}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget/core-api/local_opsmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/zh_TW/core-api/local_opsmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/it_IT/core-api/local_opsmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/ja_JP/core-api/local_opsmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/ko_KR/core-api/local_opsmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/sp_SP/core-api/local_opsmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageChinese (Simplified)uh1h hh _documenthsourceNlineNubhnote)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]h paragraph)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hh5Documentation/translations/zh_CN/disclaimer-zh_CN.rsthKhhubah}(h]h ]h"]h$]h&]uh1hhhhhhhhNubh field_list)}(hhh](hfield)}(hhh](h field_name)}(hOriginalh]hOriginal}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhS/var/lib/git/docbuild/linux/Documentation/translations/zh_CN/core-api/local_ops.rsthKubh field_body)}(h%Documentation/core-api/local_ops.rst h]h)}(h$Documentation/core-api/local_ops.rsth]h$Documentation/core-api/local_ops.rst}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(h翻译h]h翻译}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhKubh)}(h-司延腾 Yanteng Si h]h)}(h,司延腾 Yanteng Si h](h司延腾 Yanteng Si <}(hjhhhNhNubh reference)}(hsiyanteng@loongson.cnh]hsiyanteng@loongson.cn}(hjhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:siyanteng@loongson.cnuh1jhjubh>}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhhhKubhtarget)}(h.. _cn_local_ops:h]h}(h]h ]h"]h$]h&]refid cn-local-opsuh1jDhKhhhhhhubhsection)}(hhh](htitle)}(h$本地原子操作的语义和行为h]h$本地原子操作的语义和行为}(hjYhhhNhNubah}(h]h ]h"]h$]h&]uh1jWhjThhhhhK ubh)}(hhh]h)}(hhh](h)}(h作者h]h作者}(hjmhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjjhhhKubh)}(hMathieu Desnoyers h]h)}(hMathieu Desnoyersh]hMathieu Desnoyers}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj{ubah}(h]h ]h"]h$]h&]uh1hhjjubeh}(h]h ]h"]h$]h&]uh1hhhhKhjghhubah}(h]h ]h"]h$]h&]uh1hhjThhhhhKubh)}(hX 本文解释了本地原子操作的目的,如何为任何给定的架构实现这些操作,并说明了 如何正确使用这些操作。它还强调了在内存写入顺序很重要的情况下,跨CPU读取 这些本地变量时必须采取的预防措施。h]hX 本文解释了本地原子操作的目的,如何为任何给定的架构实现这些操作,并说明了 如何正确使用这些操作。它还强调了在内存写入顺序很重要的情况下,跨CPU读取 这些本地变量时必须采取的预防措施。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjThhubh)}(hXp注意,基于 ``local_t`` 的操作不建议用于一般内核操作。请使用 ``this_cpu`` 操作来代替使用,除非真的有特殊目的。大多数内核中使用的 ``local_t`` 已 经被 ``this_cpu`` 操作所取代。 ``this_cpu`` 操作在一条指令中结合了重 定位和类似 ``local_t`` 的语义,产生了更紧凑和更快的执行代码。h]h)}(hXp注意,基于 ``local_t`` 的操作不建议用于一般内核操作。请使用 ``this_cpu`` 操作来代替使用,除非真的有特殊目的。大多数内核中使用的 ``local_t`` 已 经被 ``this_cpu`` 操作所取代。 ``this_cpu`` 操作在一条指令中结合了重 定位和类似 ``local_t`` 的语义,产生了更紧凑和更快的执行代码。h](h注意,基于 }(hjhhhNhNubhliteral)}(h ``local_t``h]hlocal_t}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh8 的操作不建议用于一般内核操作。请使用 }(hjhhhNhNubj)}(h ``this_cpu``h]hthis_cpu}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhS 操作来代替使用,除非真的有特殊目的。大多数内核中使用的 }(hjhhhNhNubj)}(h ``local_t``h]hlocal_t}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 已 经被 }(hjhhhNhNubj)}(h ``this_cpu``h]hthis_cpu}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 操作所取代。 }(hjhhhNhNubj)}(h ``this_cpu``h]hthis_cpu}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh6 操作在一条指令中结合了重 定位和类似 }(hjhhhNhNubj)}(h ``local_t``h]hlocal_t}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh: 的语义,产生了更紧凑和更快的执行代码。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjThhhhhNubjS)}(hhh](jX)}(h本地原子操作的目的h]h本地原子操作的目的}(hj6hhhNhNubah}(h]h ]h"]h$]h&]uh1jWhj3hhhhhKubh)}(h本地原子操作的目的是提供快速和高度可重入的每CPU计数器。它们通过移除LOCK前 缀和通常需要在CPU间同步的内存屏障,将标准原子操作的性能成本降到最低。h]h本地原子操作的目的是提供快速和高度可重入的每CPU计数器。它们通过移除LOCK前 缀和通常需要在CPU间同步的内存屏障,将标准原子操作的性能成本降到最低。}(hjDhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK!hj3hhubh)}(hX在许多情况下,拥有快速的每CPU原子计数器是很有吸引力的:它不需要禁用中断来保护中 断处理程序,它允许在NMI(Non Maskable Interrupt)处理程序中使用连贯的计数器。 它对追踪目的和各种性能监测计数器特别有用。h]hX在许多情况下,拥有快速的每CPU原子计数器是很有吸引力的:它不需要禁用中断来保护中 断处理程序,它允许在NMI(Non Maskable Interrupt)处理程序中使用连贯的计数器。 它对追踪目的和各种性能监测计数器特别有用。}(hjRhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK$hj3hhubh)}(hX本地原子操作只保证在拥有数据的CPU上的变量修改的原子性。因此,必须注意确保只 有一个CPU写到 ``local_t`` 的数据。这是通过使用每CPU的数据来实现的,并确 保我们在一个抢占式安全上下文中修改它。然而,从任何一个CPU读取 ``local_t`` 数据都是允许的:这样它就会显得与所有者CPU的其他内存写入顺序不一致。h](h本地原子操作只保证在拥有数据的CPU上的变量修改的原子性。因此,必须注意确保只 有一个CPU写到 }(hj`hhhNhNubj)}(h ``local_t``h]hlocal_t}(hjhhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj`ubh 的数据。这是通过使用每CPU的数据来实现的,并确 保我们在一个抢占式安全上下文中修改它。然而,从任何一个CPU读取 }(hj`hhhNhNubj)}(h ``local_t``h]hlocal_t}(hjzhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj`ubhd 数据都是允许的:这样它就会显得与所有者CPU的其他内存写入顺序不一致。}(hj`hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK(hj3hhubeh}(h]id2ah ]h"]本地原子操作的目的ah$]h&]uh1jRhjThhhhhKubjS)}(hhh](jX)}(h针对特定架构的实现h]h针对特定架构的实现}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jWhjhhhhhK/ubh)}(hXB这可以通过稍微修改标准的原子操作来实现:只有它们的UP变体必须被保留。这通常 意味着删除LOCK前缀(在i386和x86_64上)和任何SMP同步屏障。如果架构在SMP和 UP之间没有不同的行为,在你的架构的 ``local.h`` 中包括 ``asm-generic/local.h`` 就足够了。h](hX这可以通过稍微修改标准的原子操作来实现:只有它们的UP变体必须被保留。这通常 意味着删除LOCK前缀(在i386和x86_64上)和任何SMP同步屏障。如果架构在SMP和 UP之间没有不同的行为,在你的架构的 }(hjhhhNhNubj)}(h ``local.h``h]hlocal.h}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 中包括 }(hjhhhNhNubj)}(h``asm-generic/local.h``h]hasm-generic/local.h}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 就足够了。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK1hjhhubh)}(h通过在一个结构体中嵌入一个 ``atomic_long_t`` , ``local_t`` 类型被定义为 一个不透明的 ``signed long`` 。这样做的目的是为了使从这个类型到 ``long`` 的转换失败。该定义看起来像::h](h(通过在一个结构体中嵌入一个 }(hjhhhNhNubj)}(h``atomic_long_t``h]h atomic_long_t}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh , }(hjhhhNhNubj)}(h ``local_t``h]hlocal_t}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh' 类型被定义为 一个不透明的 }(hjhhhNhNubj)}(h``signed long``h]h signed long}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh5 。这样做的目的是为了使从这个类型到 }(hjhhhNhNubj)}(h``long``h]hlong}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh) 的转换失败。该定义看起来像:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK6hjhhubh literal_block)}(h,typedef struct { atomic_long_t a; } local_t;h]h,typedef struct { atomic_long_t a; } local_t;}hj5sbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1j3hhhK:hjhhubeh}(h]id3ah ]h"]针对特定架构的实现ah$]h&]uh1jRhjThhhhhK/ubjS)}(hhh](jX)}(h-使用本地原子操作时应遵循的规则h]h-使用本地原子操作时应遵循的规则}(hjPhhhNhNubah}(h]h ]h"]h$]h&]uh1jWhjMhhhhhK>ubh bullet_list)}(hhh](h list_item)}(h:被本地操作触及的变量必须是每cpu的变量。 h]h)}(h9被本地操作触及的变量必须是每cpu的变量。h]h9被本地操作触及的变量必须是每cpu的变量。}(hjihhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK@hjeubah}(h]h ]h"]h$]h&]uh1jchj`hhhhhNubjd)}(hC*只有* 这些变量的CPU所有者才可以写入这些变量。 h]h)}(hB*只有* 这些变量的CPU所有者才可以写入这些变量。h](hemphasis)}(h*只有*h]h只有}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh: 这些变量的CPU所有者才可以写入这些变量。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKBhj}ubah}(h]h ]h"]h$]h&]uh1jchj`hhhhhNubjd)}(h这个CPU可以从任何上下文(进程、中断、软中断、nmi...)中使用本地操作来更新 它的local_t变量。 h]h)}(h这个CPU可以从任何上下文(进程、中断、软中断、nmi...)中使用本地操作来更新 它的local_t变量。h]h这个CPU可以从任何上下文(进程、中断、软中断、nmi...)中使用本地操作来更新 它的local_t变量。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKDhjubah}(h]h ]h"]h$]h&]uh1jchj`hhhhhNubjd)}(h当在进程上下文中使用本地操作时,必须禁用抢占(或中断),以确保进程在获得每 CPU变量和进行实际的本地操作之间不会被迁移到不同的CPU。 h]h)}(h当在进程上下文中使用本地操作时,必须禁用抢占(或中断),以确保进程在获得每 CPU变量和进行实际的本地操作之间不会被迁移到不同的CPU。h]h当在进程上下文中使用本地操作时,必须禁用抢占(或中断),以确保进程在获得每 CPU变量和进行实际的本地操作之间不会被迁移到不同的CPU。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKGhjubah}(h]h ]h"]h$]h&]uh1jchj`hhhhhNubjd)}(hX当在中断上下文中使用本地操作时,在主线内核上不需要特别注意,因为它们将在局 部CPU上运行,并且已经禁用了抢占。然而,我建议无论如何都要明确地禁用抢占, 以确保它在-rt内核上仍能正确工作。 h]h)}(hX 当在中断上下文中使用本地操作时,在主线内核上不需要特别注意,因为它们将在局 部CPU上运行,并且已经禁用了抢占。然而,我建议无论如何都要明确地禁用抢占, 以确保它在-rt内核上仍能正确工作。h]hX 当在中断上下文中使用本地操作时,在主线内核上不需要特别注意,因为它们将在局 部CPU上运行,并且已经禁用了抢占。然而,我建议无论如何都要明确地禁用抢占, 以确保它在-rt内核上仍能正确工作。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKJhjubah}(h]h ]h"]h$]h&]uh1jchj`hhhhhNubjd)}(h:读取本地cpu变量将提供该变量的当前拷贝。 h]h)}(h9读取本地cpu变量将提供该变量的当前拷贝。h]h9读取本地cpu变量将提供该变量的当前拷贝。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKNhjubah}(h]h ]h"]h$]h&]uh1jchj`hhhhhNubjd)}(hX对这些变量的读取可以从任何CPU进行,因为对 “ ``long`` ”,对齐的变量的更新 总是原子的。由于写入程序的CPU没有进行内存同步,所以在读取 *其他* cpu的变 量时,可以读取该变量的过期副本。 h]h)}(hX对这些变量的读取可以从任何CPU进行,因为对 “ ``long`` ”,对齐的变量的更新 总是原子的。由于写入程序的CPU没有进行内存同步,所以在读取 *其他* cpu的变 量时,可以读取该变量的过期副本。h](hA对这些变量的读取可以从任何CPU进行,因为对 “ }(hj hhhNhNubj)}(h``long``h]hlong}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubhu ”,对齐的变量的更新 总是原子的。由于写入程序的CPU没有进行内存同步,所以在读取 }(hj hhhNhNubj)}(h*其他*h]h其他}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh; cpu的变 量时,可以读取该变量的过期副本。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKPhjubah}(h]h ]h"]h$]h&]uh1jchj`hhhhhNubeh}(h]h ]h"]h$]h&]bullet*uh1j^hhhK@hjMhhubeh}(h]id4ah ]h"]-使用本地原子操作时应遵循的规则ah$]h&]uh1jRhjThhhhhK>ubjS)}(hhh](jX)}(h如何使用本地原子操作h]h如何使用本地原子操作}(hjThhhNhNubah}(h]h ]h"]h$]h&]uh1jWhjQhhhhhKVubj4)}(hk#include #include static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);h]hk#include #include static DEFINE_PER_CPU(local_t, counters) = LOCAL_INIT(0);}hjbsbah}(h]h ]h"]h$]h&]jCjDuh1j3hhhKZhjQhhubeh}(h]id5ah ]h"]如何使用本地原子操作ah$]h&]uh1jRhjThhhhhKVubjS)}(hhh](jX)}(h 计数器h]h 计数器}(hj{hhhNhNubah}(h]h ]h"]h$]h&]uh1jWhjxhhhhhKaubh)}(h8计数是在一个signed long的所有位上进行的。h]h8计数是在一个signed long的所有位上进行的。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKchjxhhubh)}(h在可抢占的上下文中,围绕本地原子操作使用 ``get_cpu_var()`` 和 ``put_cpu_var()`` :它确保在对每个cpu变量进行写访问时,抢占被禁用。比如 说::h](h=在可抢占的上下文中,围绕本地原子操作使用 }(hjhhhNhNubj)}(h``get_cpu_var()``h]h get_cpu_var()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 和 }(hjhhhNhNubj)}(h``put_cpu_var()``h]h put_cpu_var()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhT :它确保在对每个cpu变量进行写访问时,抢占被禁用。比如 说:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKehjxhhubj4)}(h9local_inc(&get_cpu_var(counters)); put_cpu_var(counters);h]h9local_inc(&get_cpu_var(counters)); put_cpu_var(counters);}hjsbah}(h]h ]h"]h$]h&]jCjDuh1j3hhhKihjxhhubh)}(h^如果你已经在一个抢占安全上下文中,你可以使用 ``this_cpu_ptr()`` 代替::h](hC如果你已经在一个抢占安全上下文中,你可以使用 }(hjhhhNhNubj)}(h``this_cpu_ptr()``h]hthis_cpu_ptr()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 代替:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKlhjxhhubj4)}(h#local_inc(this_cpu_ptr(&counters));h]h#local_inc(this_cpu_ptr(&counters));}hjsbah}(h]h ]h"]h$]h&]jCjDuh1j3hhhKnhjxhhubeh}(h]id6ah ]h"] 计数器ah$]h&]uh1jRhjThhhhhKaubjS)}(hhh](jX)}(h读取计数器h]h读取计数器}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jWhj hhhhhKsubh)}(h那些本地计数器可以从外部的CPU中读取,以求得计数的总和。请注意,local_read 所看到的跨CPU的数据必须被认为是相对于拥有该数据的CPU上发生的其他内存写入来 说不符合顺序的::h]h那些本地计数器可以从外部的CPU中读取,以求得计数的总和。请注意,local_read 所看到的跨CPU的数据必须被认为是相对于拥有该数据的CPU上发生的其他内存写入来 说不符合顺序的:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKuhj hhubj4)}(hZlong sum = 0; for_each_online_cpu(cpu) sum += local_read(&per_cpu(counters, cpu));h]hZlong sum = 0; for_each_online_cpu(cpu) sum += local_read(&per_cpu(counters, cpu));}hj,sbah}(h]h ]h"]h$]h&]jCjDuh1j3hhhKyhj hhubh)}(hX如果你想使用远程local_read来同步CPU之间对资源的访问,必须在写入者和读取者 的CPU上分别使用显式的 ``smp_wmb()`` 和 ``smp_rmb()`` 内存屏障。如果你使 用 ``local_t`` 变量作为写在缓冲区中的字节的计数器,就会出现这种情况:在缓 冲区写和计数器增量之间应该有一个 ``smp_wmb()`` ,在计数器读和缓冲区读之间 也应有一个 ``smp_rmb()`` 。h](h如果你想使用远程local_read来同步CPU之间对资源的访问,必须在写入者和读取者 的CPU上分别使用显式的 }(hj:hhhNhNubj)}(h ``smp_wmb()``h]h smp_wmb()}(hjBhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj:ubh 和 }(hj:hhhNhNubj)}(h ``smp_rmb()``h]h smp_rmb()}(hjThhhNhNubah}(h]h ]h"]h$]h&]uh1jhj:ubh! 内存屏障。如果你使 用 }(hj:hhhNhNubj)}(h ``local_t``h]hlocal_t}(hjfhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj:ubh 变量作为写在缓冲区中的字节的计数器,就会出现这种情况:在缓 冲区写和计数器增量之间应该有一个 }(hj:hhhNhNubj)}(h ``smp_wmb()``h]h smp_wmb()}(hjxhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj:ubh9 ,在计数器读和缓冲区读之间 也应有一个 }(hj:hhhNhNubj)}(h ``smp_rmb()``h]h smp_rmb()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj:ubh 。}(hj:hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK}hj hhubh)}(hQ下面是一个使用 ``local.h`` 实现每个cpu基本计数器的示例模块::h](h下面是一个使用 }(hjhhhNhNubj)}(h ``local.h``h]hlocal.h}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh/ 实现每个cpu基本计数器的示例模块:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj hhubj4)}(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");}hjsbah}(h]h ]h"]h$]h&]jCjDuh1j3hhhKhj hhubeh}(h]id7ah ]h"]读取计数器ah$]h&]uh1jRhjThhhhhKsubeh}(h](jQid1eh ]h"]($本地原子操作的语义和行为 cn_local_opseh$]h&]uh1jRhhhhhhhK expect_referenced_by_name}jjFsexpect_referenced_by_id}jQjFsubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(jWN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerjerror_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh، _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}jQ]jFasnameids}(jjQjjjjjJjGjNjKjujrj jjju nametypes}(jjjjJjNjuj juh}(jQjTjjTjj3jGjjKjMjrjQjjxjj u footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}jKsRparse_messages]transform_messages]hsystem_message)}(hhh]h)}(hhh]h2Hyperlink target "cn-local-ops" is not referenced.}hjrsbah}(h]h ]h"]h$]h&]uh1hhjoubah}(h]h ]h"]h$]h&]levelKtypeINFOsourceh،lineKuh1jmuba transformerN include_log]7Documentation/translations/zh_CN/core-api/local_ops.rst(NNNNta decorationNhhub.