sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextEnglish}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget/core-api/xarraymodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget#/translations/zh_TW/core-api/xarraymodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget#/translations/it_IT/core-api/xarraymodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget#/translations/ja_JP/core-api/xarraymodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget#/translations/ko_KR/core-api/xarraymodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget#/translations/sp_SP/core-api/xarraymodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageChinese (Simplified)uh1h hh _documenthsourceNlineNubhcomment)}(h!SPDX-License-Identifier: GPL-2.0+h]h!SPDX-License-Identifier: GPL-2.0+}hhsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhhP/var/lib/git/docbuild/linux/Documentation/translations/zh_CN/core-api/xarray.rsthKubhnote)}(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&]uh1hhhhhhKubh field_body)}(h"Documentation/core-api/xarray.rst h]h)}(h!Documentation/core-api/xarray.rsth]h!Documentation/core-api/xarray.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翻译}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhj hhhKubh)}(h\司延腾 Yanteng Si 周彬彬 Binbin Zhou h]h)}(h[司延腾 Yanteng Si 周彬彬 Binbin Zhou h](h司延腾 Yanteng Si <}(hj hhhNhNubh reference)}(hsiyanteng@loongson.cnh]hsiyanteng@loongson.cn}(hj*hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:siyanteng@loongson.cnuh1j(hj ubh> 周彬彬 Binbin Zhou <}(hj hhhNhNubj))}(hzhoubinbin@loongson.cnh]hzhoubinbin@loongson.cn}(hj>hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:zhoubinbin@loongson.cnuh1j(hj ubh>}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhj ubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(h校译h]h校译}(hjghhhNhNubah}(h]h ]h"]h$]h&]uh1hhjdhhhKubh)}(hhh]h}(h]h ]h"]h$]h&]uh1hhjdubeh}(h]h ]h"]h$]h&]uh1hhhhK hhhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhhhKubhtarget)}(h.. _cn_core-api_xarray:h]h}(h]h ]h"]h$]h&]refidcn-core-api-xarrayuh1jhKhhhhhhubhsection)}(hhh](htitle)}(hXArrayh]hXArray}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhKubh)}(hhh]h)}(hhh](h)}(h作者h]h作者}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhKubh)}(hMatthew Wilcox h]h)}(hMatthew Wilcoxh]hMatthew Wilcox}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubah}(h]h ]h"]h$]h&]uh1hhjhhhhhKubj)}(hhh](j)}(h概览h]h概览}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhKubh)}(hXXArray是一个抽象的数据类型,它的行为就像一个非常大的指针数组。它满足了许多与哈 希或传统可调整大小的数组相同的需求。与哈希不同的是,它允许你以一种高效的缓存方 式合理地转到下一个或上一个条目。与可调整大小的数组相比,不需要复制数据或改变MMU 的映射来增加数组。与双链表相比,它的内存效率更高,可并行,对缓存更友好。它利用 RCU的优势来执行查找而不需要锁定。h]hXXArray是一个抽象的数据类型,它的行为就像一个非常大的指针数组。它满足了许多与哈 希或传统可调整大小的数组相同的需求。与哈希不同的是,它允许你以一种高效的缓存方 式合理地转到下一个或上一个条目。与可调整大小的数组相比,不需要复制数据或改变MMU 的映射来增加数组。与双链表相比,它的内存效率更高,可并行,对缓存更友好。它利用 RCU的优势来执行查找而不需要锁定。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hXt当使用的索引是密集聚集的时候,XArray的实现是有效的;而哈希对象并使用哈希作为索引 将不会有好的表现。XArray对小的索引进行了优化,不过对大的索引仍有良好的性能。如果 你的索引可以大于 ``ULONG_MAX`` ,那么XArray就不适合你的数据类型。XArray最重要 的用户是页面高速缓存。h](hX当使用的索引是密集聚集的时候,XArray的实现是有效的;而哈希对象并使用哈希作为索引 将不会有好的表现。XArray对小的索引进行了优化,不过对大的索引仍有良好的性能。如果 你的索引可以大于 }(hjhhhNhNubhliteral)}(h ``ULONG_MAX``h]h ULONG_MAX}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubhb ,那么XArray就不适合你的数据类型。XArray最重要 的用户是页面高速缓存。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK hjhhubh)}(hXQ普通指针可以直接存储在XArray中。它们必须是4字节对齐的,这对任何从kmalloc()和 alloc_page()返回的指针来说都是如此。这对任意的用户空间指针和函数指针来说都不是 真的。你可以存储指向静态分配对象的指针,只要这些对象的对齐方式至少是4(字节)。h]hXQ普通指针可以直接存储在XArray中。它们必须是4字节对齐的,这对任何从kmalloc()和 alloc_page()返回的指针来说都是如此。这对任意的用户空间指针和函数指针来说都不是 真的。你可以存储指向静态分配对象的指针,只要这些对象的对齐方式至少是4(字节)。}(hj&hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK%hjhhubh)}(hX.你也可以在XArray中存储0到 ``LONG_MAX`` 之间的整数。你必须首先使用xa_mk_value() 将其转换为一个条目。当你从XArray中检索一个条目时,你可以通过调用xa_is_value()检 查它是否是一个值条目,并通过调用xa_to_value()将它转换回一个整数。h](h#你也可以在XArray中存储0到 }(hj4hhhNhNubj )}(h ``LONG_MAX``h]hLONG_MAX}(hj<hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj4ubh 之间的整数。你必须首先使用xa_mk_value() 将其转换为一个条目。当你从XArray中检索一个条目时,你可以通过调用xa_is_value()检 查它是否是一个值条目,并通过调用xa_to_value()将它转换回一个整数。}(hj4hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK)hjhhubh)}(hX一些用户希望对他们存储在XArray中的指针进行标记。你可以调用xa_tag_pointer()来创建 一个带有标签的条目,xa_untag_pointer()将一个有标签的条目转回一个无标签的指针, xa_pointer_tag()来检索一个条目的标签。标签指针使用相同的位,用于区分值条目和普通 指针,所以你必须决定他们是否要在任何特定的XArray中存储值条目或标签指针。h]hX一些用户希望对他们存储在XArray中的指针进行标记。你可以调用xa_tag_pointer()来创建 一个带有标签的条目,xa_untag_pointer()将一个有标签的条目转回一个无标签的指针, xa_pointer_tag()来检索一个条目的标签。标签指针使用相同的位,用于区分值条目和普通 指针,所以你必须决定他们是否要在任何特定的XArray中存储值条目或标签指针。}(hjThhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK-hjhhubh)}(h\XArray不支持存储IS_ERR()指针,因为有些指针与值条目或内部条目冲突。h]h\XArray不支持存储IS_ERR()指针,因为有些指针与值条目或内部条目冲突。}(hjbhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK2hjhhubh)}(hXXArray的一个不寻常的特点是能够创建占据一系列索引的条目。一旦存储到其中,查询该范围 内的任何索引将返回与查询该范围内任何其他索引相同的条目。存储到任何索引都会存储所有 的索引条目。多索引条目可以明确地分割成更小的条目,或者将其存储 ``NULL`` 到任何条目中 都会使XArray忘记范围。h](hXSXArray的一个不寻常的特点是能够创建占据一系列索引的条目。一旦存储到其中,查询该范围 内的任何索引将返回与查询该范围内任何其他索引相同的条目。存储到任何索引都会存储所有 的索引条目。多索引条目可以明确地分割成更小的条目,或者将其存储 }(hjphhhNhNubj )}(h``NULL``h]hNULL}(hjxhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjpubh2 到任何条目中 都会使XArray忘记范围。}(hjphhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK4hjhhubeh}(h]id1ah ]h"]概览ah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h 普通APIh]h 普通API}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhK:ubh)}(h首先初始化一个XArray,对于静态分配的XArray可以用DEFINE_XARRAY(),对于动态分配的 XArray可以用xa_init()。一个新初始化的XArray在每个索引处都包含一个 ``NULL`` 指针。h](h首先初始化一个XArray,对于静态分配的XArray可以用DEFINE_XARRAY(),对于动态分配的 XArray可以用xa_init()。一个新初始化的XArray在每个索引处都包含一个 }(hjhhhNhNubj )}(h``NULL``h]hNULL}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hjubh 指针。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj-hhubh)}(hX,没有内存可供分配是可能的,特别是如果你传递了一组限制性的GFP标志。在这种情况下,这些函数会返回一 个特殊的值,可以用xa_err()把它变成一个错误值。如果你不需要确切地知道哪个错误发生,使用xa_is_err() 会更有效一些。h]hX,没有内存可供分配是可能的,特别是如果你传递了一组限制性的GFP标志。在这种情况下,这些函数会返回一 个特殊的值,可以用xa_err()把它变成一个错误值。如果你不需要确切地知道哪个错误发生,使用xa_is_err() 会更有效一些。}(hjLhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj-hhubeh}(h]id3ah ]h"] 内存分配ah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h锁h]h锁}(hjehhhNhNubah}(h]h ]h"]h$]h&]uh1jhjbhhhhhKubh)}(hm当使用普通API时,你不必担心锁的问题。XArray使用RCU和一个内部自旋锁来同步访问:h]hm当使用普通API时,你不必担心锁的问题。XArray使用RCU和一个内部自旋锁来同步访问:}(hjshhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjbhhubhdefinition_list)}(hhh](hdefinition_list_item)}(h)不需要锁: * xa_empty() * xa_marked() h](hterm)}(h 不需要锁:h]h 不需要锁:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhKhjubh definition)}(hhh]h bullet_list)}(hhh](h list_item)}(h xa_empty()h]h)}(hjh]h xa_empty()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_marked() h]h)}(h xa_marked()h]h xa_marked()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]bullet*uh1jhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhKhjubj)}(h采取RCU读锁: * xa_load() * xa_for_each() * xa_for_each_start() * xa_for_each_range() * xa_find() * xa_find_after() * xa_extract() * xa_get_mark() h](j)}(h采取RCU读锁:h]h采取RCU读锁:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhKhjubj)}(hhh]j)}(hhh](j)}(h xa_load()h]h)}(hjh]h xa_load()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_for_each()h]h)}(hjh]h xa_for_each()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_for_each_start()h]h)}(hj3h]hxa_for_each_start()}(hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj1ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_for_each_range()h]h)}(hjJh]hxa_for_each_range()}(hjLhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjHubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_find()h]h)}(hjah]h xa_find()}(hjchhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj_ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_find_after()h]h)}(hjxh]hxa_find_after()}(hjzhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjvubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_extract()h]h)}(hjh]h xa_extract()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_get_mark() h]h)}(h xa_get_mark()h]h xa_get_mark()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1jhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhKhjhhubj)}(hX|内部使用xa_lock: * xa_store() * xa_store_bh() * xa_store_irq() * xa_insert() * xa_insert_bh() * xa_insert_irq() * xa_erase() * xa_erase_bh() * xa_erase_irq() * xa_cmpxchg() * xa_cmpxchg_bh() * xa_cmpxchg_irq() * xa_store_range() * xa_alloc() * xa_alloc_bh() * xa_alloc_irq() * xa_reserve() * xa_reserve_bh() * xa_reserve_irq() * xa_destroy() * xa_set_mark() * xa_clear_mark() h](j)}(h内部使用xa_lock:h]h内部使用xa_lock:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhKhjubj)}(hhh]j)}(hhh](j)}(h xa_store()h]h)}(hjh]h xa_store()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_store_bh()h]h)}(hjh]h xa_store_bh()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_store_irq()h]h)}(hjh]hxa_store_irq()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_insert()h]h)}(hj-h]h xa_insert()}(hj/hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj+ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_insert_bh()h]h)}(hjDh]hxa_insert_bh()}(hjFhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjBubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_insert_irq()h]h)}(hj[h]hxa_insert_irq()}(hj]hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjYubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_erase()h]h)}(hjrh]h xa_erase()}(hjthhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjpubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_erase_bh()h]h)}(hjh]h xa_erase_bh()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_erase_irq()h]h)}(hjh]hxa_erase_irq()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_cmpxchg()h]h)}(hjh]h xa_cmpxchg()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_cmpxchg_bh()h]h)}(hjh]hxa_cmpxchg_bh()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_cmpxchg_irq()h]h)}(hjh]hxa_cmpxchg_irq()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_store_range()h]h)}(hjh]hxa_store_range()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_alloc()h]h)}(hjh]h xa_alloc()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_alloc_bh()h]h)}(hj*h]h xa_alloc_bh()}(hj,hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj(ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_alloc_irq()h]h)}(hjAh]hxa_alloc_irq()}(hjChhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj?ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_reserve()h]h)}(hjXh]h xa_reserve()}(hjZhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjVubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_reserve_bh()h]h)}(hjoh]hxa_reserve_bh()}(hjqhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjmubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_reserve_irq()h]h)}(hjh]hxa_reserve_irq()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_destroy()h]h)}(hjh]h xa_destroy()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h xa_set_mark()h]h)}(hjh]h xa_set_mark()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hxa_clear_mark() h]h)}(hxa_clear_mark()h]hxa_clear_mark()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1jhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhKhjhhubj)}(h假设进入时持有xa_lock: * __xa_store() * __xa_insert() * __xa_erase() * __xa_cmpxchg() * __xa_alloc() * __xa_set_mark() * __xa_clear_mark() h](j)}(h假设进入时持有xa_lock:h]h假设进入时持有xa_lock:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhKhjubj)}(hhh]j)}(hhh](j)}(h __xa_store()h]h)}(hj h]h __xa_store()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h __xa_insert()h]h)}(hj$ h]h __xa_insert()}(hj& hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj" ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h __xa_erase()h]h)}(hj; h]h __xa_erase()}(hj= hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj9 ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h__xa_cmpxchg()h]h)}(hjR h]h__xa_cmpxchg()}(hjT hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjP ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h __xa_alloc()h]h)}(hji h]h __xa_alloc()}(hjk hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjg ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h__xa_set_mark()h]h)}(hj h]h__xa_set_mark()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj~ ubah}(h]h ]h"]h$]h&]uh1jhj ubj)}(h__xa_clear_mark() h]h)}(h__xa_clear_mark()h]h__xa_clear_mark()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]jjuh1jhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhKhjhhubeh}(h]h ]h"]h$]h&]uh1jhjbhhhNhNubh)}(hX如果你想利用锁来保护你存储在XArray中的数据结构,你可以在调用xa_load()之前调用xa_lock(),然后在 调用xa_unlock()之前对你找到的对象进行一个引用计数。这将防止存储操作在查找对象和增加refcount期间 从数组中删除对象。你也可以使用RCU来避免解除对已释放内存的引用,但对这一点的解释已经超出了本文的范 围。h]hX如果你想利用锁来保护你存储在XArray中的数据结构,你可以在调用xa_load()之前调用xa_lock(),然后在 调用xa_unlock()之前对你找到的对象进行一个引用计数。这将防止存储操作在查找对象和增加refcount期间 从数组中删除对象。你也可以使用RCU来避免解除对已释放内存的引用,但对这一点的解释已经超出了本文的范 围。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjbhhubh)}(h在修改数组时,XArray不会禁用中断或softirqs。从中断或softirq上下文中读取XArray是安全的,因为RCU锁 提供了足够的保护。h]h在修改数组时,XArray不会禁用中断或softirqs。从中断或softirq上下文中读取XArray是安全的,因为RCU锁 提供了足够的保护。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjbhhubh)}(h例如,如果你想在进程上下文中存储XArray中的条目,然后在softirq上下文中擦除它们,你可以这样做::h]h例如,如果你想在进程上下文中存储XArray中的条目,然后在softirq上下文中擦除它们,你可以这样做:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjbhhubh literal_block)}(hX6void foo_init(struct foo *foo) { xa_init_flags(&foo->array, XA_FLAGS_LOCK_BH); } int foo_store(struct foo *foo, unsigned long index, void *entry) { int err; xa_lock_bh(&foo->array); err = xa_err(__xa_store(&foo->array, index, entry, GFP_KERNEL)); if (!err) foo->count++; xa_unlock_bh(&foo->array); return err; } /* foo_erase()只在软中断上下文中调用 */ void foo_erase(struct foo *foo, unsigned long index) { xa_lock(&foo->array); __xa_erase(&foo->array, index); foo->count--; xa_unlock(&foo->array); }h]hX6void foo_init(struct foo *foo) { xa_init_flags(&foo->array, XA_FLAGS_LOCK_BH); } int foo_store(struct foo *foo, unsigned long index, void *entry) { int err; xa_lock_bh(&foo->array); err = xa_err(__xa_store(&foo->array, index, entry, GFP_KERNEL)); if (!err) foo->count++; xa_unlock_bh(&foo->array); return err; } /* foo_erase()只在软中断上下文中调用 */ void foo_erase(struct foo *foo, unsigned long index) { xa_lock(&foo->array); __xa_erase(&foo->array, index); foo->count--; xa_unlock(&foo->array); }}hj sbah}(h]h ]h"]h$]h&]hhuh1j hhhKhjbhhubh)}(h如果你要从中断或softirq上下文中修改XArray,你需要使用xa_init_flags()初始化数组,传递 ``XA_FLAGS_LOCK_IRQ`` 或 ``XA_FLAGS_LOCK_BH`` (参数)。h](hq如果你要从中断或softirq上下文中修改XArray,你需要使用xa_init_flags()初始化数组,传递 }(hj hhhNhNubj )}(h``XA_FLAGS_LOCK_IRQ``h]hXA_FLAGS_LOCK_IRQ}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh 或 }(hj hhhNhNubj )}(h``XA_FLAGS_LOCK_BH``h]hXA_FLAGS_LOCK_BH}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh (参数)。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjbhhubh)}(h上面的例子还显示了一个常见的模式,即希望在存储端扩展xa_lock的覆盖范围,以保护与数组相关的一些统计 数据。h]h上面的例子还显示了一个常见的模式,即希望在存储端扩展xa_lock的覆盖范围,以保护与数组相关的一些统计 数据。}(hj1 hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjbhhubh)}(hXu与中断上下文共享XArray也是可能的,可以在中断处理程序和进程上下文中都使用xa_lock_irqsave(),或者 在进程上下文中使用xa_lock_irq(),在中断处理程序中使用xa_lock()。一些更常见的模式有一些辅助函数, 如xa_store_bh()、xa_store_irq()、xa_erase_bh()、xa_erase_irq()、xa_cmpxchg_bh() 和xa_cmpxchg_irq()。h]hXu与中断上下文共享XArray也是可能的,可以在中断处理程序和进程上下文中都使用xa_lock_irqsave(),或者 在进程上下文中使用xa_lock_irq(),在中断处理程序中使用xa_lock()。一些更常见的模式有一些辅助函数, 如xa_store_bh()、xa_store_irq()、xa_erase_bh()、xa_erase_irq()、xa_cmpxchg_bh() 和xa_cmpxchg_irq()。}(hj? hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjbhhubh)}(hX 有时你需要用一个mutex来保护对XArray的访问,因为这个锁在锁的层次结构中位于另一个mutex之上。这并不 意味着你有权使用像__xa_erase()这样的函数而不占用xa_lock;xa_lock是用来进行lockdep验证的,将来也 会用于其他用途。h]hX 有时你需要用一个mutex来保护对XArray的访问,因为这个锁在锁的层次结构中位于另一个mutex之上。这并不 意味着你有权使用像__xa_erase()这样的函数而不占用xa_lock;xa_lock是用来进行lockdep验证的,将来也 会用于其他用途。}(hjM hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjbhhubh)}(h__xa_set_mark() 和 __xa_clear_mark() 函数也适用于你查找一个条目并想原子化地设置或清除一个标记的 情况。在这种情况下,使用高级API可能更有效,因为它将使你免于走两次树。h]h__xa_set_mark() 和 __xa_clear_mark() 函数也适用于你查找一个条目并想原子化地设置或清除一个标记的 情况。在这种情况下,使用高级API可能更有效,因为它将使你免于走两次树。}(hj[ hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjbhhubeh}(h]id4ah ]h"]锁ah$]h&]uh1jhjhhhhhKubeh}(h]apiah ]h"] 普通apiah$]h&]uh1jhjhhhhhK:ubj)}(hhh](j)}(h 高级APIh]h 高级API}(hj| hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjy hhhhhKubh)}(hX高级API提供了更多的灵活性和更好的性能,但代价是接口可能更难使用,保障措施更少。高级API没有为你加锁, 你需要在修改数组的时候使用xa_lock。在对数组进行只读操作时,你可以选择使用xa_lock或RCU锁。你可以在 同一个数组上混合使用高级和普通操作;事实上,普通API是以高级API的形式实现的。高级API只对具有GPL兼容 许可证的模块可用。h]hX高级API提供了更多的灵活性和更好的性能,但代价是接口可能更难使用,保障措施更少。高级API没有为你加锁, 你需要在修改数组的时候使用xa_lock。在对数组进行只读操作时,你可以选择使用xa_lock或RCU锁。你可以在 同一个数组上混合使用高级和普通操作;事实上,普通API是以高级API的形式实现的。高级API只对具有GPL兼容 许可证的模块可用。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjy hhubh)}(hX高级API是基于xa_state的。这是一个不透明的数据结构,你使用XA_STATE()宏在堆栈中声明。这个宏初始化了 xa_state,准备开始在XArray上移动。它被用作一个游标来保持在XArray中的位置,并让你把各种操作组合在一 起,而不必每次都从头开始。xa_state的内容受rcu_read_lock()或xas_lock()的保护。如果需要删除保护状态 和树的这些锁中的任何一个,你必须调用xas_pause()以便将来的调用不会依赖于状态中未受保护的部分。h]hX高级API是基于xa_state的。这是一个不透明的数据结构,你使用XA_STATE()宏在堆栈中声明。这个宏初始化了 xa_state,准备开始在XArray上移动。它被用作一个游标来保持在XArray中的位置,并让你把各种操作组合在一 起,而不必每次都从头开始。xa_state的内容受rcu_read_lock()或xas_lock()的保护。如果需要删除保护状态 和树的这些锁中的任何一个,你必须调用xas_pause()以便将来的调用不会依赖于状态中未受保护的部分。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjy hhubh)}(hXxa_state也被用来存储错误(store errors)。你可以调用xas_error()来检索错误。所有的操作在进行之前都 会检查xa_state是否处于错误状态,所以你没有必要在每次调用之后检查错误;你可以连续进行多次调用,只在 方便的时候检查。目前XArray代码本身产生的错误只有 ``ENOMEM`` 和 ``EINVAL`` ,但它支持任意的错误, 以防你想自己调用xas_set_err()。h](hXUxa_state也被用来存储错误(store errors)。你可以调用xas_error()来检索错误。所有的操作在进行之前都 会检查xa_state是否处于错误状态,所以你没有必要在每次调用之后检查错误;你可以连续进行多次调用,只在 方便的时候检查。目前XArray代码本身产生的错误只有 }(hj hhhNhNubj )}(h ``ENOMEM``h]hENOMEM}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh 和 }(hj hhhNhNubj )}(h ``EINVAL``h]hEINVAL}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubhK ,但它支持任意的错误, 以防你想自己调用xas_set_err()。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhjy hhubh)}(hX如果xa_state持有 ``ENOMEM`` 错误,调用xas_nomem()将尝试使用指定的gfp标志分配更多的内存,并将其缓 存在xa_state中供下一次尝试。这个想法是,你拿着xa_lock,尝试操作,然后放弃锁。该操作试图在持有锁的情 况下分配内存,但它更有可能失败。一旦你放弃了锁,xas_nomem()可以更努力地尝试分配更多内存。如果值得重 试该操作,它将返回 ``true`` (即出现了内存错误,分配了更多的内存)。如果它之前已经分配了内存,并且 该内存没有被使用,也没有错误(或者一些不是 ``ENOMEM`` 的错误),那么它将释放之前分配的内存。h](h如果xa_state持有 }(hj hhhNhNubj )}(h ``ENOMEM``h]hENOMEM}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubhX 错误,调用xas_nomem()将尝试使用指定的gfp标志分配更多的内存,并将其缓 存在xa_state中供下一次尝试。这个想法是,你拿着xa_lock,尝试操作,然后放弃锁。该操作试图在持有锁的情 况下分配内存,但它更有可能失败。一旦你放弃了锁,xas_nomem()可以更努力地尝试分配更多内存。如果值得重 试该操作,它将返回 }(hj hhhNhNubj )}(h``true``h]htrue}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh (即出现了内存错误,分配了更多的内存)。如果它之前已经分配了内存,并且 该内存没有被使用,也没有错误(或者一些不是 }(hj hhhNhNubj )}(h ``ENOMEM``h]hENOMEM}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh: 的错误),那么它将释放之前分配的内存。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM hjy hhubj)}(hhh](j)}(h 内部条目h]h 内部条目}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj hhhhhMubh)}(hXXArray为它自己的目的保留了一些条目。这些条目从未通过正常的API暴露出来,但是当使用高级API时,有可能看 到它们。通常,处理它们的最好方法是把它们传递给xas_retry(),如果它返回 ``true`` ,就重试操作。h](hXArray为它自己的目的保留了一些条目。这些条目从未通过正常的API暴露出来,但是当使用高级API时,有可能看 到它们。通常,处理它们的最好方法是把它们传递给xas_retry(),如果它返回 }(hj- hhhNhNubj )}(h``true``h]htrue}(hj5 hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj- ubh ,就重试操作。}(hj- hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMhj hhubhtable)}(hhh]htgroup)}(hhh](hcolspec)}(hhh]h}(h]h ]h"]h$]h&]colwidthKuh1jW hjT ubjX )}(hhh]h}(h]h ]h"]h$]h&]colwidthKuh1jW hjT ubjX )}(hhh]h}(h]h ]h"]h$]h&]colwidthKuh1jW hjT ubhtbody)}(hhh](hrow)}(hhh](hentry)}(hhh]h)}(h名称h]h名称}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1j hj~ ubj )}(hhh]h)}(h检测h]h检测}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1j hj~ ubj )}(hhh]h)}(h用途h]h用途}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1j hj~ ubeh}(h]h ]h"]h$]h&]uh1j| hjy ubj} )}(hhh](j )}(hhh]h)}(hNodeh]hNode}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1j hj ubj )}(hhh]h)}(h xa_is_node()h]h xa_is_node()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1j hj ubj )}(hhh]h)}(hH一个XArray节点。 在使用多索引xa_state时可能是可见的。h]hH一个XArray节点。 在使用多索引xa_state时可能是可见的。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1j hj ubeh}(h]h ]h"]h$]h&]uh1j| hjy ubj} )}(hhh](j )}(hhh]h)}(hSiblingh]hSibling}(hj" hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM!hj ubah}(h]h ]h"]h$]h&]uh1j hj ubj )}(hhh]h)}(hxa_is_sibling()h]hxa_is_sibling()}(hj9 hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM"hj6 ubah}(h]h ]h"]h$]h&]uh1j hj ubj )}(hhh]h)}(h`一个多索引条目的非典型条目。该值表示该节点中的哪个槽有典型条目。h]h`一个多索引条目的非典型条目。该值表示该节点中的哪个槽有典型条目。}(hjP hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM#hjM ubah}(h]h ]h"]h$]h&]uh1j hj ubeh}(h]h ]h"]h$]h&]uh1j| hjy ubj} )}(hhh](j )}(hhh]h)}(hRetryh]hRetry}(hjp hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM%hjm ubah}(h]h ]h"]h$]h&]uh1j hjj ubj )}(hhh]h)}(h xa_is_retry()h]h xa_is_retry()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM&hj ubah}(h]h ]h"]h$]h&]uh1j hjj ubj )}(hhh]h)}(h这个条目目前正在被一个拥有xa_lock的线程修改。在这个RCU周期结束时,包含该条目的节点可能会被释放。 你应该从数组的头部重新开始查找。h]h这个条目目前正在被一个拥有xa_lock的线程修改。在这个RCU周期结束时,包含该条目的节点可能会被释放。 你应该从数组的头部重新开始查找。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM'hj ubah}(h]h ]h"]h$]h&]uh1j hjj ubeh}(h]h ]h"]h$]h&]uh1j| hjy ubj} )}(hhh](j )}(hhh]h)}(hZeroh]hZero}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM*hj ubah}(h]h ]h"]h$]h&]uh1j hj ubj )}(hhh]h)}(h xa_is_zero()h]h xa_is_zero()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM+hj ubah}(h]h ]h"]h$]h&]uh1j hj ubj )}(hhh]h)}(hZero条目通过普通API显示为 ``NULL`` ,但在XArray中占有一个条目,可用于保留索引供将来使用。这是 通过为分配的条目分配XArrays来使用的,这些条目是 ``NULL`` 。h](h#Zero条目通过普通API显示为 }(hj hhhNhNubj )}(h``NULL``h]hNULL}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh ,但在XArray中占有一个条目,可用于保留索引供将来使用。这是 通过为分配的条目分配XArrays来使用的,这些条目是 }(hj hhhNhNubj )}(h``NULL``h]hNULL}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh 。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM,hj ubah}(h]h ]h"]h$]h&]uh1j hj ubeh}(h]h ]h"]h$]h&]uh1j| hjy ubeh}(h]h ]h"]h$]h&]uh1jw hjT ubeh}(h]h ]h"]h$]h&]colsKuh1jR hjO ubah}(h]h ]h"]h$]h&]uh1jM hj hhhNhNubh)}(hh其他内部条目可能会在未来被添加。在可能的情况下,它们将由xas_retry()处理。h]hh其他内部条目可能会在未来被添加。在可能的情况下,它们将由xas_retry()处理。}(hj= hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM/hj hhubeh}(h]id6ah ]h"] 内部条目ah$]h&]uh1jhjy hhhhhMubj)}(hhh](j)}(h 附加函数h]h 附加函数}(hjV hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjS hhhhhM2ubh)}(hxas_create_range()函数分配了所有必要的内存来存储一个范围内的每一个条目。如果它不能分配内存,它将在 xa_state中设置ENOMEM。h]hxas_create_range()函数分配了所有必要的内存来存储一个范围内的每一个条目。如果它不能分配内存,它将在 xa_state中设置ENOMEM。}(hjd hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM4hjS hhubh)}(hX你可以使用xas_init_marks()将一个条目上的标记重置为默认状态。这通常是清空所有标记,除非XArray被标记 为 ``XA_FLAGS_TRACK_FREE`` ,在这种情况下,标记0被设置,所有其他标记被清空。使用xas_store()将一个 条目替换为另一个条目不会重置该条目上的标记;如果你想重置标记,你应该明确地这样做。h](h你可以使用xas_init_marks()将一个条目上的标记重置为默认状态。这通常是清空所有标记,除非XArray被标记 为 }(hjr hhhNhNubj )}(h``XA_FLAGS_TRACK_FREE``h]hXA_FLAGS_TRACK_FREE}(hjz hhhNhNubah}(h]h ]h"]h$]h&]uh1j hjr ubh ,在这种情况下,标记0被设置,所有其他标记被清空。使用xas_store()将一个 条目替换为另一个条目不会重置该条目上的标记;如果你想重置标记,你应该明确地这样做。}(hjr hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM7hjS hhubh)}(hxas_load()会尽可能地将xa_state移动到该条目附近。如果你知道xa_state已经移动到了该条目,并且需要检查 该条目是否有变化,你可以使用xas_reload()来保存一个函数调用。h]hxas_load()会尽可能地将xa_state移动到该条目附近。如果你知道xa_state已经移动到了该条目,并且需要检查 该条目是否有变化,你可以使用xas_reload()来保存一个函数调用。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM;hjS hhubh)}(hX如果你需要移动到XArray中的不同索引,可以调用xas_set()。这可以将光标重置到树的顶端,这通常会使下一个 操作将光标移动到树中想要的位置。如果你想移动到下一个或上一个索引,调用xas_next()或xas_prev()。设置 索引不会使光标在数组中移动,所以不需要锁,而移动到下一个或上一个索引则需要锁。h]hX如果你需要移动到XArray中的不同索引,可以调用xas_set()。这可以将光标重置到树的顶端,这通常会使下一个 操作将光标移动到树中想要的位置。如果你想移动到下一个或上一个索引,调用xas_next()或xas_prev()。设置 索引不会使光标在数组中移动,所以不需要锁,而移动到下一个或上一个索引则需要锁。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM>hjS hhubh)}(hX你可以使用xas_find()搜索下一个当前条目。这相当于xa_find()和xa_find_after();如果光标已经移动到了 一个条目,那么它将找到当前引用的条目之后的下一个条目。如果没有,它将返回xa_state索引处的条目。使用 xas_next_entry()而不是xas_find()来移动到下一个当前条目,在大多数情况下会节省一个函数调用,但代价 是发出更多内联代码。h]hX你可以使用xas_find()搜索下一个当前条目。这相当于xa_find()和xa_find_after();如果光标已经移动到了 一个条目,那么它将找到当前引用的条目之后的下一个条目。如果没有,它将返回xa_state索引处的条目。使用 xas_next_entry()而不是xas_find()来移动到下一个当前条目,在大多数情况下会节省一个函数调用,但代价 是发出更多内联代码。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMBhjS hhubh)}(hXxas_find_marked()函数也是如此。如果xa_state没有被移动过,它将返回xa_state的索引处的条目,如果它 被标记了。否则,它将返回xa_state所引用的条目之后的第一个被标记的条目。xas_next_marked()函数等同 于xas_next_entry()。h]hXxas_find_marked()函数也是如此。如果xa_state没有被移动过,它将返回xa_state的索引处的条目,如果它 被标记了。否则,它将返回xa_state所引用的条目之后的第一个被标记的条目。xas_next_marked()函数等同 于xas_next_entry()。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMGhjS hhubh)}(hX当使用xas_for_each()或xas_for_each_marked()在XArray的某个范围内进行迭代时,可能需要暂时停止迭代。 xas_pause()函数的存在就是为了这个目的。在你完成了必要的工作并希望恢复后,xa_state处于适当的状态,在 你最后处理的条目后继续迭代。如果你在迭代时禁用了中断,那么暂停迭代并在每一个 ``XA_CHECK_SCHED`` 条目 中重新启用中断是很好的做法。h](hX}当使用xas_for_each()或xas_for_each_marked()在XArray的某个范围内进行迭代时,可能需要暂时停止迭代。 xas_pause()函数的存在就是为了这个目的。在你完成了必要的工作并希望恢复后,xa_state处于适当的状态,在 你最后处理的条目后继续迭代。如果你在迭代时禁用了中断,那么暂停迭代并在每一个 }(hj hhhNhNubj )}(h``XA_CHECK_SCHED``h]hXA_CHECK_SCHED}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj ubh2 条目 中重新启用中断是很好的做法。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMKhjS hhubh)}(hxas_get_mark(), xas_set_mark()和xas_clear_mark()函数要求xa_state光标已经被移动到XArray中的适当位 置;如果你在之前调用了xas_pause()或xas_set(),它们将不会有任何作用。h]hxas_get_mark(), xas_set_mark()和xas_clear_mark()函数要求xa_state光标已经被移动到XArray中的适当位 置;如果你在之前调用了xas_pause()或xas_set(),它们将不会有任何作用。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMPhjS hhubh)}(h你可以调用xas_set_update(),让XArray每次更新一个节点时都调用一个回调函数。这被页面缓存的workingset 代码用来维护其只包含阴影项的节点列表。h]h你可以调用xas_set_update(),让XArray每次更新一个节点时都调用一个回调函数。这被页面缓存的workingset 代码用来维护其只包含阴影项的节点列表。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMShjS hhubeh}(h]id7ah ]h"] 附加函数ah$]h&]uh1jhjy hhhhhM2ubj)}(hhh](j)}(h多索引条目h]h多索引条目}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMWubh)}(hXXArray有能力将多个索引联系在一起,因此对一个索引的操作会影响到所有的索引。例如,存储到任何索引将改变 从任何索引检索的条目的值。在任何索引上设置或清除一个标记,都会在每个被绑在一起的索引上设置或清除该标 记。目前的实现只允许将2的整数倍的范围绑在一起;例如指数64-127可以绑在一起,但2-6不能。这可以节省大量 的内存;例如,将512个条目绑在一起可以节省4kB以上的内存。h]hXXArray有能力将多个索引联系在一起,因此对一个索引的操作会影响到所有的索引。例如,存储到任何索引将改变 从任何索引检索的条目的值。在任何索引上设置或清除一个标记,都会在每个被绑在一起的索引上设置或清除该标 记。目前的实现只允许将2的整数倍的范围绑在一起;例如指数64-127可以绑在一起,但2-6不能。这可以节省大量 的内存;例如,将512个条目绑在一起可以节省4kB以上的内存。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMYhjhhubh)}(hX你可以通过使用XA_STATE_ORDER()或xas_set_order(),然后调用xas_store()来创建一个多索引条目。用一个 多索引的xa_state调用xas_load()会把xa_state移动到树中的正确位置,但是返回值没有意义,有可能是一个内 部条目或 ``NULL`` ,即使在范围内有一个条目存储。调用xas_find_conflict()将返回该范围内的第一个条目, 如果该范围内没有条目,则返回 ``NULL`` 。xas_for_each_conflict()迭代器将遍历每个与指定范围重叠的条目。h](hX你可以通过使用XA_STATE_ORDER()或xas_set_order(),然后调用xas_store()来创建一个多索引条目。用一个 多索引的xa_state调用xas_load()会把xa_state移动到树中的正确位置,但是返回值没有意义,有可能是一个内 部条目或 }(hj-hhhNhNubj )}(h``NULL``h]hNULL}(hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1j hj-ubh ,即使在范围内有一个条目存储。调用xas_find_conflict()将返回该范围内的第一个条目, 如果该范围内没有条目,则返回 }(hj-hhhNhNubj )}(h``NULL``h]hNULL}(hjGhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj-ubhT 。xas_for_each_conflict()迭代器将遍历每个与指定范围重叠的条目。}(hj-hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM^hjhhubh)}(hXj如果xas_load()遇到一个多索引条目,xa_state中的xa_index将不会被改变。当遍历一个XArray或者调用xas_find() 时,如果初始索引在一个多索引条目的中间,它将不会被改变。随后的调用或迭代将把索引移到范围内的第一个索引。 每个条目只会被返回一次,不管它占据了多少个索引。h]hXj如果xas_load()遇到一个多索引条目,xa_state中的xa_index将不会被改变。当遍历一个XArray或者调用xas_find() 时,如果初始索引在一个多索引条目的中间,它将不会被改变。随后的调用或迭代将把索引移到范围内的第一个索引。 每个条目只会被返回一次,不管它占据了多少个索引。}(hj_hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMchjhhubh)}(h不支持使用xas_next()或xas_prev()来处理一个多索引的xa_state。在一个多索引的条目上使用这两个函数中的任 何一个都会显示出同级的条目;这些条目应该被调用者跳过。h]h不支持使用xas_next()或xas_prev()来处理一个多索引的xa_state。在一个多索引的条目上使用这两个函数中的任 何一个都会显示出同级的条目;这些条目应该被调用者跳过。}(hjmhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMghjhhubh)}(hX2在一个多索引条目的任何一个索引中存储 ``NULL`` ,将把每个索引的条目设置为 ``NULL`` ,并解除绑定。通过调 用xas_split_alloc(),在没有xa_lock的情况下,可以将一个多索引条目分割成占据较小范围的条目,然后再取锁并 调用xas_split()。h](h7在一个多索引条目的任何一个索引中存储 }(hj{hhhNhNubj )}(h``NULL``h]hNULL}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj{ubh) ,将把每个索引的条目设置为 }(hj{hhhNhNubj )}(h``NULL``h]hNULL}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j hj{ubh ,并解除绑定。通过调 用xas_split_alloc(),在没有xa_lock的情况下,可以将一个多索引条目分割成占据较小范围的条目,然后再取锁并 调用xas_split()。}(hj{hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMjhjhhubeh}(h]id8ah ]h"]多索引条目ah$]h&]uh1jhjy hhhhhMWubeh}(h]id5ah ]h"] 高级apiah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h函数和结构体h]h函数和结构体}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMoubh)}(h该API在以下内核代码中:h]h该API在以下内核代码中:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMqhjhhubh)}(hinclude/linux/xarray.hh]hinclude/linux/xarray.h}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMshjhhubh)}(h lib/xarray.ch]h lib/xarray.c}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMuhjhhubeh}(h]id9ah ]h"]函数和结构体ah$]h&]uh1jhjhhhhhMoubeh}(h](xarrayjeh ]h"](xarraycn_core-api_xarrayeh$]h&]uh1jhhhhhhhKexpect_referenced_by_name}jjsexpect_referenced_by_id}jjsubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(jN generatorN datestampN source_linkN source_urlN toc_backlinksj footnote_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_handlerj/error_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}j]jasnameids}(jjjjjjjv js jqjnj*j'j_j\jn jk jjjP jM j jjjjju nametypes}(jjjjv jqj*j_jn jjP j jjuh}(jjjjjjjs jjnjj'jtj\j-jk jbjjy jM j jjS jjjju footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}j=K sRparse_messages]transform_messages]hsystem_message)}(hhh]h)}(hhh]h8Hyperlink target "cn-core-api-xarray" is not referenced.}hjsbah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]levelKtypeINFOsourcehlineKuh1juba transformerN include_log]4Documentation/translations/zh_CN/core-api/xarray.rst(NNNNta decorationNhhub.