Asphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextEnglish}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget/core-api/watch_queuemodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/zh_TW/core-api/watch_queuemodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/it_IT/core-api/watch_queuemodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/ja_JP/core-api/watch_queuemodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/ko_KR/core-api/watch_queuemodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/sp_SP/core-api/watch_queuemodnameN 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:spacepreserveuh1hhhhhhU/var/lib/git/docbuild/linux/Documentation/translations/zh_CN/core-api/watch_queue.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/watch_queue.rst h]h)}(h&Documentation/core-api/watch_queue.rsth]h&Documentation/core-api/watch_queue.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)}(hhh]h}(h]h ]h"]h$]h&]uh1hhj ubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhhhKubh)}(h.周彬彬 Binbin Zhou h](h周彬彬 Binbin Zhou <}(hj1hhhNhNubh reference)}(hzhoubinbin@loongson.cnh]hzhoubinbin@loongson.cn}(hj;hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:zhoubinbin@loongson.cnuh1j9hj1ubh>}(hj1hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK hhhhubh)}(hhh]h)}(hhh](h)}(h校译h]h校译}(hj[hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjXhhhKubh)}(hhh]h}(h]h ]h"]h$]h&]uh1hhjXubeh}(h]h ]h"]h$]h&]uh1hhhhK hjUhhubah}(h]h ]h"]h$]h&]uh1hhhhhhhhK ubh)}(hV司延腾 Yanteng Si 吴想成 Wu Xiangcheng h](h司延腾 Yanteng Si <}(hj~hhhNhNubj:)}(hsiyanteng@loongson.cnh]hsiyanteng@loongson.cn}(hjhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:siyanteng@loongson.cnuh1j9hj~ubh> 吴想成 Wu Xiangcheng <}(hj~hhhNhNubj:)}(hbobwxc@email.cnh]hbobwxc@email.cn}(hjhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:bobwxc@email.cnuh1j9hj~ubh>}(hj~hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK hhhhubhsection)}(hhh](htitle)}(h通用通知机制h]h通用通知机制}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhKubh)}(h通用通知机制是建立在标准管道驱动之上的,它可以有效地将来自内核的通知消息拼接到用 户空间打开的管道中。这可以与以下方面结合使用::h]h通用通知机制是建立在标准管道驱动之上的,它可以有效地将来自内核的通知消息拼接到用 户空间打开的管道中。这可以与以下方面结合使用:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh literal_block)}(h* Key/keyring 通知h]h* Key/keyring 通知}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjhhubh)}(h0通知缓冲区可以通过以下方式启用:h]h0通知缓冲区可以通过以下方式启用:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh block_quote)}(hJ“General setup”/“General notification queue” (CONFIG_WATCH_QUEUE) h]h)}(hI“General setup”/“General notification queue” (CONFIG_WATCH_QUEUE)h]hI“General setup”/“General notification queue” (CONFIG_WATCH_QUEUE)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhhhKhjhhubh)}(h文档包含以下章节:h]h文档包含以下章节:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubhtopic)}(hhh]h bullet_list)}(hhh](h list_item)}(hhh]h)}(hhh]j:)}(hhh]h概述}(hj/hhhNhNubah}(h]id10ah ]h"]h$]h&]refidid2uh1j9hj,ubah}(h]h ]h"]h$]h&]uh1hhj)ubah}(h]h ]h"]h$]h&]uh1j'hj$ubj()}(hhh]h)}(hhh]j:)}(hhh]h 消息结构}(hjQhhhNhNubah}(h]id11ah ]h"]h$]h&]refidid3uh1j9hjNubah}(h]h ]h"]h$]h&]uh1hhjKubah}(h]h ]h"]h$]h&]uh1j'hj$ubj()}(hhh]h)}(hhh]j:)}(hhh]h观测列表(通知源)API}(hjshhhNhNubah}(h]id12ah ]h"]h$]h&]refidapiuh1j9hjpubah}(h]h ]h"]h$]h&]uh1hhjmubah}(h]h ]h"]h$]h&]uh1j'hj$ubj()}(hhh]h)}(hhh]j:)}(hhh]h!观测队列(通知输出)API}(hjhhhNhNubah}(h]id13ah ]h"]h$]h&]refidid4uh1j9hjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1j'hj$ubj()}(hhh]h)}(hhh]j:)}(hhh]h观测订阅API}(hjhhhNhNubah}(h]id14ah ]h"]h$]h&]refidid5uh1j9hjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1j'hj$ubj()}(hhh]h)}(hhh]j:)}(hhh]h通知发布API}(hjhhhNhNubah}(h]id15ah ]h"]h$]h&]refidid6uh1j9hjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1j'hj$ubj()}(hhh]h)}(hhh]j:)}(hhh]h 观测源}(hjhhhNhNubah}(h]id16ah ]h"]h$]h&]refidid7uh1j9hjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1j'hj$ubj()}(hhh]h)}(hhh]j:)}(hhh]h 事件过滤}(hjhhhNhNubah}(h]id17ah ]h"]h$]h&]refidid8uh1j9hjubah}(h]h ]h"]h$]h&]uh1hhjubah}(h]h ]h"]h$]h&]uh1j'hj$ubj()}(hhh]h)}(hhh]j:)}(hhh]h用户空间代码示例}(hj?hhhNhNubah}(h]id18ah ]h"]h$]h&]refidid9uh1j9hj<ubah}(h]h ]h"]h$]h&]uh1hhj9ubah}(h]h ]h"]h$]h&]uh1j'hj$ubeh}(h]h ]h"]h$]h&]uh1j"hjhhhNhNubah}(h]contentsah ](contentslocaleh"]contentsah$]h&]uh1jhhhK"hjhhubj)}(hhh](j)}(h概述h]h概述}(hjnhhhNhNubah}(h]h ]h"]h$]h&]refidj8uh1jhjkhhhhhK%ubh)}(hXP该设施以一种特殊模式打开的管道形式出现,管道的内部环形缓冲区用于保存内核生成的消 息。然后通过read()读出这些消息。在此类管道上禁用拼接以及类似的操作,因为它们希望 在某些情况下将其添加的内容还原到环中-这可能最终会与通知消息重叠。h]hXP该设施以一种特殊模式打开的管道形式出现,管道的内部环形缓冲区用于保存内核生成的消 息。然后通过read()读出这些消息。在此类管道上禁用拼接以及类似的操作,因为它们希望 在某些情况下将其添加的内容还原到环中-这可能最终会与通知消息重叠。}(hj}hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK'hjkhhubh)}(h管道的所有者必须告诉内核它想通过该管道观察哪些源。只有连接到该管道上的源才会将消 息插入其中。请注意,一个源可能绑定到多个管道,并同时将消息插入到所有管道中。h]h管道的所有者必须告诉内核它想通过该管道观察哪些源。只有连接到该管道上的源才会将消 息插入其中。请注意,一个源可能绑定到多个管道,并同时将消息插入到所有管道中。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK+hjkhhubh)}(hl还可以将过滤器放置在管道上,以便在不感兴趣时可以忽略某些源类型和子事件。h]hl还可以将过滤器放置在管道上,以便在不感兴趣时可以忽略某些源类型和子事件。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK.hjkhhubh)}(hX如果环中没有可用的插槽,或者没有预分配的消息缓冲区可用,则将丢弃消息。在这两种情 况下,read()都会在读取缓冲区中当前的最后一条消息后,将WATCH_META_LOSS_NOTIFICATION 插入到输出缓冲区中。h]hX如果环中没有可用的插槽,或者没有预分配的消息缓冲区可用,则将丢弃消息。在这两种情 况下,read()都会在读取缓冲区中当前的最后一条消息后,将WATCH_META_LOSS_NOTIFICATION 插入到输出缓冲区中。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK0hjkhhubh)}(h请注意,当生成一个通知时,内核不会等待消费者收集它,而是继续执行。这意味着可以在 持有自旋锁的同时生成通知,并且还可以保护内核不被用户空间故障无限期地阻碍。h]h请注意,当生成一个通知时,内核不会等待消费者收集它,而是继续执行。这意味着可以在 持有自旋锁的同时生成通知,并且还可以保护内核不被用户空间故障无限期地阻碍。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK4hjkhhubeh}(h]j>ah ]h"]概述ah$]h&]uh1jhjhhhhhK%ubj)}(hhh](j)}(h 消息结构h]h 消息结构}(hjhhhNhNubah}(h]h ]h"]h$]h&]j|jZuh1jhjhhhhhK9ubh)}(h,通知消息由一个简短的头部开始::h]h+通知消息由一个简短的头部开始:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK;hjhhubj)}(hhstruct watch_notification { __u32 type:24; __u32 subtype:8; __u32 info; };h]hhstruct watch_notification { __u32 type:24; __u32 subtype:8; __u32 info; };}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhK=hjhhubh)}(hX“type”表示通知记录的来源,“subtype”表示该来源的记录类型(见下文观测源章节)。该类 型也可以是“WATCH_TYPE_META”。这是一个由观测队列本身在内部生成的特殊记录类型。有两 个子类型:h]hX“type”表示通知记录的来源,“subtype”表示该来源的记录类型(见下文观测源章节)。该类 型也可以是“WATCH_TYPE_META”。这是一个由观测队列本身在内部生成的特殊记录类型。有两 个子类型:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKChjhhubj)}(hA* WATCH_META_REMOVAL_NOTIFICATION * WATCH_META_LOSS_NOTIFICATION h]j#)}(hhh](j()}(hWATCH_META_REMOVAL_NOTIFICATIONh]h)}(hjh]hWATCH_META_REMOVAL_NOTIFICATION}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKGhj ubah}(h]h ]h"]h$]h&]uh1j'hj ubj()}(hWATCH_META_LOSS_NOTIFICATION h]h)}(hWATCH_META_LOSS_NOTIFICATIONh]hWATCH_META_LOSS_NOTIFICATION}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKHhj#ubah}(h]h ]h"]h$]h&]uh1j'hj ubeh}(h]h ]h"]h$]h&]bullet*uh1j"hhhKGhjubah}(h]h ]h"]h$]h&]uh1jhhhKGhjhhubh)}(hf第一个表示安装了观察的对象已被删除或销毁,第二个表示某些消息已丢失。h]hf第一个表示安装了观察的对象已被删除或销毁,第二个表示某些消息已丢失。}(hjIhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKJhjhhubh)}(h+“info”表示一系列东西,包括:h]h+“info”表示一系列东西,包括:}(hjWhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKLhjhhubj)}(hX.* 消息的长度,以字节为单位,包括头(带有WATCH_INFO_LENGTH的掩码,并按 WATCH_INFO_LENGTH__SHIFT移位)。这表示记录的大小,可能在8到127字节之间。 * 观测ID(带有WATCH_INFO_ID掩码,并按WATCH_INFO_ID__SHIFT移位)。这表示观测的主 叫ID,可能在0到255之间。多个观测组可以共享一个队列,这提供了一种区分它们的方法。 * 特定类型的字段(WATCH_INFO_TYPE_INFO)。这是由通知生产者设置的,以指示类型和 子类型的某些特定含义。 h]j#)}(hhh](j()}(h消息的长度,以字节为单位,包括头(带有WATCH_INFO_LENGTH的掩码,并按 WATCH_INFO_LENGTH__SHIFT移位)。这表示记录的大小,可能在8到127字节之间。 h]h)}(h消息的长度,以字节为单位,包括头(带有WATCH_INFO_LENGTH的掩码,并按 WATCH_INFO_LENGTH__SHIFT移位)。这表示记录的大小,可能在8到127字节之间。h]h消息的长度,以字节为单位,包括头(带有WATCH_INFO_LENGTH的掩码,并按 WATCH_INFO_LENGTH__SHIFT移位)。这表示记录的大小,可能在8到127字节之间。}(hjphhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKNhjlubah}(h]h ]h"]h$]h&]uh1j'hjiubj()}(h观测ID(带有WATCH_INFO_ID掩码,并按WATCH_INFO_ID__SHIFT移位)。这表示观测的主 叫ID,可能在0到255之间。多个观测组可以共享一个队列,这提供了一种区分它们的方法。 h]h)}(h观测ID(带有WATCH_INFO_ID掩码,并按WATCH_INFO_ID__SHIFT移位)。这表示观测的主 叫ID,可能在0到255之间。多个观测组可以共享一个队列,这提供了一种区分它们的方法。h]h观测ID(带有WATCH_INFO_ID掩码,并按WATCH_INFO_ID__SHIFT移位)。这表示观测的主 叫ID,可能在0到255之间。多个观测组可以共享一个队列,这提供了一种区分它们的方法。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKQhjubah}(h]h ]h"]h$]h&]uh1j'hjiubj()}(h特定类型的字段(WATCH_INFO_TYPE_INFO)。这是由通知生产者设置的,以指示类型和 子类型的某些特定含义。 h]h)}(h特定类型的字段(WATCH_INFO_TYPE_INFO)。这是由通知生产者设置的,以指示类型和 子类型的某些特定含义。h]h特定类型的字段(WATCH_INFO_TYPE_INFO)。这是由通知生产者设置的,以指示类型和 子类型的某些特定含义。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKThjubah}(h]h ]h"]h$]h&]uh1j'hjiubeh}(h]h ]h"]h$]h&]jAjBuh1j"hhhKNhjeubah}(h]h ]h"]h$]h&]uh1jhhhKNhjhhubh)}(h?除长度外,信息中的所有内容都可以用于过滤。h]h?除长度外,信息中的所有内容都可以用于过滤。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKWhjhhubh)}(hQ头部后面可以有补充信息。此格式是由类型和子类型决定的。h]hQ头部后面可以有补充信息。此格式是由类型和子类型决定的。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKYhjhhubeh}(h]j`ah ]h"] 消息结构ah$]h&]uh1jhjhhhhhK9ubj)}(hhh](j)}(h观测列表(通知源)APIh]h观测列表(通知源)API}(hjhhhNhNubah}(h]h ]h"]h$]h&]j|j|uh1jhjhhhhhK]ubh)}(hXx“观测列表“是订阅通知源的观测者的列表。列表可以附加到对象(比如键或超级块),也可 以是全局的(比如对于设备事件)。从用户空间的角度来看,一个非全局的观测列表通常是 通过引用它所属的对象来引用的(比如使用KEYCTL_NOTIFY并给它一个密钥序列号来观测特定 的密钥)。h]hXx“观测列表“是订阅通知源的观测者的列表。列表可以附加到对象(比如键或超级块),也可 以是全局的(比如对于设备事件)。从用户空间的角度来看,一个非全局的观测列表通常是 通过引用它所属的对象来引用的(比如使用KEYCTL_NOTIFY并给它一个密钥序列号来观测特定 的密钥)。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK_hjhhubh)}(h3为了管理观测列表,提供了以下函数:h]h3为了管理观测列表,提供了以下函数:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKdhjhhubj)}(hX* :: void init_watch_list(struct watch_list *wlist, void (*release_watch)(struct watch *wlist)); 初始化一个观测列表。 如果 ``release_watch`` 不是NULL,那么这表示当watch_list对 象被销毁时,应该调用函数来丢弃观测列表对被观测对象的任何引用。 * ``void remove_watch_list(struct watch_list *wlist);`` 这将删除订阅watch_list的所有观测,并释放它们,然后销毁watch_list对象本身。 h]j#)}(hhh](j()}(hXA:: void init_watch_list(struct watch_list *wlist, void (*release_watch)(struct watch *wlist)); 初始化一个观测列表。 如果 ``release_watch`` 不是NULL,那么这表示当watch_list对 象被销毁时,应该调用函数来丢弃观测列表对被观测对象的任何引用。 h](j)}(hpvoid init_watch_list(struct watch_list *wlist, void (*release_watch)(struct watch *wlist));h]hpvoid init_watch_list(struct watch_list *wlist, void (*release_watch)(struct watch *wlist));}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhKhhjubh)}(h初始化一个观测列表。 如果 ``release_watch`` 不是NULL,那么这表示当watch_list对 象被销毁时,应该调用函数来丢弃观测列表对被观测对象的任何引用。h](h&初始化一个观测列表。 如果 }(hj)hhhNhNubhliteral)}(h``release_watch``h]h release_watch}(hj3hhhNhNubah}(h]h ]h"]h$]h&]uh1j1hj)ubh 不是NULL,那么这表示当watch_list对 象被销毁时,应该调用函数来丢弃观测列表对被观测对象的任何引用。}(hj)hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKkhjubeh}(h]h ]h"]h$]h&]uh1j'hjubj()}(h``void remove_watch_list(struct watch_list *wlist);`` 这将删除订阅watch_list的所有观测,并释放它们,然后销毁watch_list对象本身。 h](h)}(h5``void remove_watch_list(struct watch_list *wlist);``h]j2)}(hjWh]h1void remove_watch_list(struct watch_list *wlist);}(hjYhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjUubah}(h]h ]h"]h$]h&]uh1hhhhKnhjQubh)}(he这将删除订阅watch_list的所有观测,并释放它们,然后销毁watch_list对象本身。h]he这将删除订阅watch_list的所有观测,并释放它们,然后销毁watch_list对象本身。}(hjlhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKphjQubeh}(h]h ]h"]h$]h&]uh1j'hjubeh}(h]h ]h"]h$]h&]jAjBuh1j"hhhKfhjubah}(h]h ]h"]h$]h&]uh1jhhhKfhjhhubeh}(h]jah ]h"]观测列表(通知源)apiah$]h&]uh1jhjhhhhhK]ubj)}(hhh](j)}(h!观测队列(通知输出)APIh]h!观测队列(通知输出)API}(hjhhhNhNubah}(h]h ]h"]h$]h&]j|juh1jhjhhhhhKtubh)}(h“观测队列”是由应用程序分配的用以记录通知的缓冲区,其工作原理完全隐藏在管道设备驱 动中,但必须获得对它的引用才能设置观测。可以通过以下方式进行管理:h]h“观测队列”是由应用程序分配的用以记录通知的缓冲区,其工作原理完全隐藏在管道设备驱 动中,但必须获得对它的引用才能设置观测。可以通过以下方式进行管理:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKvhjhhubj)}(hX* ``struct watch_queue *get_watch_queue(int fd);`` 由于观测队列在内核中通过实现缓冲区的管道的文件描述符表示,用户空间必须通过系 统调用传递该文件描述符,这可以用于从系统调用中查找指向观测队列的不透明指针。 * ``void put_watch_queue(struct watch_queue *wqueue);`` 该函数用以丢弃从 ``get_watch_queue()`` 获得的引用。 h]j#)}(hhh](j()}(hX``struct watch_queue *get_watch_queue(int fd);`` 由于观测队列在内核中通过实现缓冲区的管道的文件描述符表示,用户空间必须通过系 统调用传递该文件描述符,这可以用于从系统调用中查找指向观测队列的不透明指针。 h](h)}(h0``struct watch_queue *get_watch_queue(int fd);``h]j2)}(hjh]h,struct watch_queue *get_watch_queue(int fd);}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubah}(h]h ]h"]h$]h&]uh1hhhhKyhjubh)}(h由于观测队列在内核中通过实现缓冲区的管道的文件描述符表示,用户空间必须通过系 统调用传递该文件描述符,这可以用于从系统调用中查找指向观测队列的不透明指针。h]h由于观测队列在内核中通过实现缓冲区的管道的文件描述符表示,用户空间必须通过系 统调用传递该文件描述符,这可以用于从系统调用中查找指向观测队列的不透明指针。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK{hjubeh}(h]h ]h"]h$]h&]uh1j'hjubj()}(hz``void put_watch_queue(struct watch_queue *wqueue);`` 该函数用以丢弃从 ``get_watch_queue()`` 获得的引用。 h](h)}(h5``void put_watch_queue(struct watch_queue *wqueue);``h]j2)}(hjh]h1void put_watch_queue(struct watch_queue *wqueue);}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubah}(h]h ]h"]h$]h&]uh1hhhhK~hjubh)}(hA该函数用以丢弃从 ``get_watch_queue()`` 获得的引用。h](h该函数用以丢弃从 }(hjhhhNhNubj2)}(h``get_watch_queue()``h]hget_watch_queue()}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubh 获得的引用。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1j'hjubeh}(h]h ]h"]h$]h&]jAjBuh1j"hhhKyhjubah}(h]h ]h"]h$]h&]uh1jhhhKyhjhhubeh}(h]jah ]h"]!观测队列(通知输出)apiah$]h&]uh1jhjhhhhhKtubj)}(hhh](j)}(h观测订阅APIh]h观测订阅API}(hj?hhhNhNubah}(h]h ]h"]h$]h&]j|juh1jhj<hhhhhKubh)}(h“观测”是观测列表上的订阅,表示观测队列,从而表示应写入通知记录的缓冲区。观测队列 对象还可以携带该对象的过滤规则,由用户空间设置。watch结构体的某些部分可以由驱动程 序设置::h]h“观测”是观测列表上的订阅,表示观测队列,从而表示应写入通知记录的缓冲区。观测队列 对象还可以携带该对象的过滤规则,由用户空间设置。watch结构体的某些部分可以由驱动程 序设置:}(hjMhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj<hhubj)}(hXAstruct watch { union { u32 info_id; /* 在info字段中进行OR运算的ID */ ... }; void *private; /* 被观测对象的私有数据 */ u64 id; /* 内部标识符 */ ... };h]hXAstruct watch { union { u32 info_id; /* 在info字段中进行OR运算的ID */ ... }; void *private; /* 被观测对象的私有数据 */ u64 id; /* 内部标识符 */ ... };}hj[sbah}(h]h ]h"]h$]h&]hhuh1jhhhKhj<hhubh)}(h``info_id`` 值是从用户空间获得并按WATCH_INFO_ID__SHIFT移位的8位数字。当通知写入关 联的观测队列缓冲区时,这将与struct watch_notification::info的WATCH_INFO_ID字段进 行或运算。h](j2)}(h ``info_id``h]hinfo_id}(hjmhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjiubh 值是从用户空间获得并按WATCH_INFO_ID__SHIFT移位的8位数字。当通知写入关 联的观测队列缓冲区时,这将与struct watch_notification::info的WATCH_INFO_ID字段进 行或运算。}(hjihhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj<hhubh)}(hy``private`` 字段是与watch_list相关联的驱动程序数据,并由 ``watch_list::release_watch()`` 函数清除。h](j2)}(h ``private``h]hprivate}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubh? 字段是与watch_list相关联的驱动程序数据,并由 }(hjhhhNhNubj2)}(h``watch_list::release_watch()``h]hwatch_list::release_watch()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubh 函数清除。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj<hhubh)}(hG``id`` 字段是源的ID。使用不同ID发布的通知将被忽略。h](j2)}(h``id``h]hid}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubhA 字段是源的ID。使用不同ID发布的通知将被忽略。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj<hhubh)}(h"提供以下函数来管理观测:h]h"提供以下函数来管理观测:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj<hhubj)}(hX* ``void init_watch(struct watch *watch, struct watch_queue *wqueue);`` 初始化一个观测对象,把它的指针设置到观察队列中,使用适当的限制来避免死锁。 * ``int add_watch_to_object(struct watch *watch, struct watch_list *wlist);`` 将观测订阅到观测列表(通知源)。watch结构体中的driver-settable字段必须在调用 它之前设置。 * :: int remove_watch_from_object(struct watch_list *wlist, struct watch_queue *wqueue, u64 id, false); 从观测列表中删除一个观测,该观测必须与指定的观测队列(``wqueue``)和对象标识 符(``id``)匹配。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到观测队列 表示该观测已被删除。 * ``int remove_watch_from_object(struct watch_list *wlist, NULL, 0, true);`` 从观测列表中删除所有观测。预计这将被称为销毁前的准备工作,届时新的观测将无法 访问观测列表。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到每个订阅观测 的观测队列,以表明该观测已被删除。 h]j#)}(hhh](j()}(h``void init_watch(struct watch *watch, struct watch_queue *wqueue);`` 初始化一个观测对象,把它的指针设置到观察队列中,使用适当的限制来避免死锁。 h](h)}(hE``void init_watch(struct watch *watch, struct watch_queue *wqueue);``h]j2)}(hjh]hAvoid init_watch(struct watch *watch, struct watch_queue *wqueue);}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(ho初始化一个观测对象,把它的指针设置到观察队列中,使用适当的限制来避免死锁。h]ho初始化一个观测对象,把它的指针设置到观察队列中,使用适当的限制来避免死锁。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1j'hjubj()}(h``int add_watch_to_object(struct watch *watch, struct watch_list *wlist);`` 将观测订阅到观测列表(通知源)。watch结构体中的driver-settable字段必须在调用 它之前设置。 h](h)}(hK``int add_watch_to_object(struct watch *watch, struct watch_list *wlist);``h]j2)}(hjh]hGint add_watch_to_object(struct watch *watch, struct watch_list *wlist);}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(h{将观测订阅到观测列表(通知源)。watch结构体中的driver-settable字段必须在调用 它之前设置。h]h{将观测订阅到观测列表(通知源)。watch结构体中的driver-settable字段必须在调用 它之前设置。}(hj.hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1j'hjubj()}(hX:: int remove_watch_from_object(struct watch_list *wlist, struct watch_queue *wqueue, u64 id, false); 从观测列表中删除一个观测,该观测必须与指定的观测队列(``wqueue``)和对象标识 符(``id``)匹配。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到观测队列 表示该观测已被删除。 h](j)}(hint remove_watch_from_object(struct watch_list *wlist, struct watch_queue *wqueue, u64 id, false);h]hint remove_watch_from_object(struct watch_list *wlist, struct watch_queue *wqueue, u64 id, false);}hjFsbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjBubh)}(h从观测列表中删除一个观测,该观测必须与指定的观测队列(``wqueue``)和对象标识 符(``id``)匹配。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到观测队列 表示该观测已被删除。h](hQ从观测列表中删除一个观测,该观测必须与指定的观测队列(}(hjThhhNhNubj2)}(h ``wqueue``h]hwqueue}(hj\hhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjTubh)和对象标识 符(}(hjThhhNhNubj2)}(h``id``h]hid}(hjnhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjTubh)匹配。通知(}(hjThhhNhNubj2)}(h#``WATCH_META_REMOVAL_NOTIFICATION``h]hWATCH_META_REMOVAL_NOTIFICATION}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjTubh:)被发送到观测队列 表示该观测已被删除。}(hjThhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjBubeh}(h]h ]h"]h$]h&]uh1j'hjubj()}(hXW``int remove_watch_from_object(struct watch_list *wlist, NULL, 0, true);`` 从观测列表中删除所有观测。预计这将被称为销毁前的准备工作,届时新的观测将无法 访问观测列表。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到每个订阅观测 的观测队列,以表明该观测已被删除。 h](h)}(hJ``int remove_watch_from_object(struct watch_list *wlist, NULL, 0, true);``h]j2)}(hjh]hFint remove_watch_from_object(struct watch_list *wlist, NULL, 0, true);}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hX 从观测列表中删除所有观测。预计这将被称为销毁前的准备工作,届时新的观测将无法 访问观测列表。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到每个订阅观测 的观测队列,以表明该观测已被删除。h](h从观测列表中删除所有观测。预计这将被称为销毁前的准备工作,届时新的观测将无法 访问观测列表。通知(}(hjhhhNhNubj2)}(h#``WATCH_META_REMOVAL_NOTIFICATION``h]hWATCH_META_REMOVAL_NOTIFICATION}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubhU)被发送到每个订阅观测 的观测队列,以表明该观测已被删除。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1j'hjubeh}(h]h ]h"]h$]h&]jAjBuh1j"hhhKhjubah}(h]h ]h"]h$]h&]uh1jhhhKhj<hhubeh}(h]jah ]h"]观测订阅apiah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h通知发布APIh]h通知发布API}(hjhhhNhNubah}(h]h ]h"]h$]h&]j|juh1jhjhhhhhKubh)}(h\要将通知发布到观测列表以便订阅的观测可以看到,应使用以下函数::h]h[要将通知发布到观测列表以便订阅的观测可以看到,应使用以下函数:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hvoid post_watch_notification(struct watch_list *wlist, struct watch_notification *n, const struct cred *cred, u64 id);h]hvoid post_watch_notification(struct watch_list *wlist, struct watch_notification *n, const struct cred *cred, u64 id);}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjhhubh)}(h应预先设置通知格式,并应传入一个指向头部(``n``)的指针。通知可能大于此值,并且缓 冲槽为单位的大小在 ``n->info & WATCH_INFO_LENGTH`` 中注明。h](h?应预先设置通知格式,并应传入一个指向头部(}(hjhhhNhNubj2)}(h``n``h]hn}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubhP)的指针。通知可能大于此值,并且缓 冲槽为单位的大小在 }(hjhhhNhNubj2)}(h``n->info & WATCH_INFO_LENGTH``h]hn->info & WATCH_INFO_LENGTH}(hj9hhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjubh 中注明。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(h``cred`` 结构体表示源(对象)的证书,并传递给LSM,例如SELinux,以允许或禁止根据该队 列(对象)的证书在每个单独队列中记录注释。h](j2)}(h``cred``h]hcred}(hjUhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjQubh 结构体表示源(对象)的证书,并传递给LSM,例如SELinux,以允许或禁止根据该队 列(对象)的证书在每个单独队列中记录注释。}(hjQhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hn``id`` 是源对象ID(如密钥上的序列号)。只有设置相同ID的观测才能看到这个通知。h](j2)}(h``id``h]hid}(hjqhhhNhNubah}(h]h ]h"]h$]h&]uh1j1hjmubhh 是源对象ID(如密钥上的序列号)。只有设置相同ID的观测才能看到这个通知。}(hjmhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]jah ]h"]通知发布apiah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h 观测源h]h 观测源}(hjhhhNhNubah}(h]h ]h"]h$]h&]j|juh1jhjhhhhhKubh)}(hM任何特定的缓冲区都可以从多个源获取信息。 这些源包括:h]hM任何特定的缓冲区都可以从多个源获取信息。 这些源包括:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(h* WATCH_TYPE_KEY_NOTIFY 这种类型的通知表示密钥和密钥环的变化,包括密钥环内容或密钥属性的变化。 更多信息请参见Documentation/security/keys/core.rst。 h]j#)}(hhh]j()}(hWATCH_TYPE_KEY_NOTIFY 这种类型的通知表示密钥和密钥环的变化,包括密钥环内容或密钥属性的变化。 更多信息请参见Documentation/security/keys/core.rst。 h](h)}(hWATCH_TYPE_KEY_NOTIFYh]hWATCH_TYPE_KEY_NOTIFY}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hi这种类型的通知表示密钥和密钥环的变化,包括密钥环内容或密钥属性的变化。h]hi这种类型的通知表示密钥和密钥环的变化,包括密钥环内容或密钥属性的变化。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(h<更多信息请参见Documentation/security/keys/core.rst。h]h<更多信息请参见Documentation/security/keys/core.rst。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1j'hjubah}(h]h ]h"]h$]h&]jAjBuh1j"hhhKhjubah}(h]h ]h"]h$]h&]uh1jhhhKhjhhubeh}(h]j ah ]h"] 观测源ah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h 事件过滤h]h 事件过滤}(hj hhhNhNubah}(h]h ]h"]h$]h&]j|j&uh1jhjhhhhhKubh)}(hV当创建观测队列后,我们可以应用一组过滤器以限制接收的事件::h]hU当创建观测队列后,我们可以应用一组过滤器以限制接收的事件:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(histruct watch_notification_filter filter = { ... }; ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter)h]histruct watch_notification_filter filter = { ... }; ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter)}hj sbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjhhubh)}(h&过滤器的描述的类型变量是::h]h%过滤器的描述的类型变量是:}(hj* hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hstruct watch_notification_filter { __u32 nr_filters; __u32 __reserved; struct watch_notification_type_filter filters[]; };h]hstruct watch_notification_filter { __u32 nr_filters; __u32 __reserved; struct watch_notification_type_filter filters[]; };}hj8 sbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjhhubh)}(h其中“nr_filters”表示filters[]数组中过滤器的数量,而“__reserved”应为0。 “filter”数组有以下类型的元素::h]h其中“nr_filters”表示filters[]数组中过滤器的数量,而“__reserved”应为0。 “filter”数组有以下类型的元素:}(hjF hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hstruct watch_notification_type_filter { __u32 type; __u32 info_filter; __u32 info_mask; __u32 subtype_filter[8]; };h]hstruct watch_notification_type_filter { __u32 type; __u32 info_filter; __u32 info_mask; __u32 subtype_filter[8]; };}hjT sbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjhhubh)}(h 其中:h]h 其中:}(hjb hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(hX* ``type`` 是过滤的事件类型,应类似于“WATCH_TYPE_KEY_NOTIFY”。 * ``info_filter`` 与 ``info_mask`` 充当通知记录的信息字段的过滤器,只有在以下情 况,通知才会写入缓冲区:: (watch.info & info_mask) == info_filter 例如,这可以用于忽略不在一个挂载树上的观测点的事件。 * ``subtype_filter`` 是一个位掩码,表示感兴趣的子类型。subtype_filter[0]的 bit[0]对应子类型0,bit[1]对应子类型1,以此类推。 h]j#)}(hhh](j()}(hO``type`` 是过滤的事件类型,应类似于“WATCH_TYPE_KEY_NOTIFY”。 h]h)}(hN``type`` 是过滤的事件类型,应类似于“WATCH_TYPE_KEY_NOTIFY”。h](j2)}(h``type``h]htype}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j1hj{ ubhF 是过滤的事件类型,应类似于“WATCH_TYPE_KEY_NOTIFY”。}(hj{ hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjw ubah}(h]h ]h"]h$]h&]uh1j'hjt ubj()}(hX``info_filter`` 与 ``info_mask`` 充当通知记录的信息字段的过滤器,只有在以下情 况,通知才会写入缓冲区:: (watch.info & info_mask) == info_filter 例如,这可以用于忽略不在一个挂载树上的观测点的事件。 h](h)}(h``info_filter`` 与 ``info_mask`` 充当通知记录的信息字段的过滤器,只有在以下情 况,通知才会写入缓冲区::h](j2)}(h``info_filter``h]h info_filter}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j1hj ubh 与 }(hj hhhNhNubj2)}(h ``info_mask``h]h info_mask}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j1hj ubhf 充当通知记录的信息字段的过滤器,只有在以下情 况,通知才会写入缓冲区:}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj ubj)}(h'(watch.info & info_mask) == info_filterh]h'(watch.info & info_mask) == info_filter}hj sbah}(h]h ]h"]h$]h&]hhuh1jhhhKhj ubh)}(hN例如,这可以用于忽略不在一个挂载树上的观测点的事件。h]hN例如,这可以用于忽略不在一个挂载树上的观测点的事件。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubeh}(h]h ]h"]h$]h&]uh1j'hjt ubj()}(h``subtype_filter`` 是一个位掩码,表示感兴趣的子类型。subtype_filter[0]的 bit[0]对应子类型0,bit[1]对应子类型1,以此类推。 h]h)}(h``subtype_filter`` 是一个位掩码,表示感兴趣的子类型。subtype_filter[0]的 bit[0]对应子类型0,bit[1]对应子类型1,以此类推。h](j2)}(h``subtype_filter``h]hsubtype_filter}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1j1hj ubh 是一个位掩码,表示感兴趣的子类型。subtype_filter[0]的 bit[0]对应子类型0,bit[1]对应子类型1,以此类推。}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1j'hjt ubeh}(h]h ]h"]h$]h&]jAjBuh1j"hhhKhjp ubah}(h]h ]h"]h$]h&]uh1jhhhKhjhhubh)}(hk若ioctl()的参数为NULL,则过滤器将被移除,并且来自观测源的所有事件都将通过。h]hk若ioctl()的参数为NULL,则过滤器将被移除,并且来自观测源的所有事件都将通过。}(hj# hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubeh}(h]j,ah ]h"] 事件过滤ah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h用户空间代码示例h]h用户空间代码示例}(hj; hhhNhNubah}(h]h ]h"]h$]h&]j|jHuh1jhj8 hhhhhMubh)}(h 缓冲区的创建如下所示::h]h缓冲区的创建如下所示:}(hjI hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj8 hhubj)}(hDpipe2(fds, O_TMPFILE); ioctl(fds[1], IOC_WATCH_QUEUE_SET_SIZE, 256);h]hDpipe2(fds, O_TMPFILE); ioctl(fds[1], IOC_WATCH_QUEUE_SET_SIZE, 256);}hjW sbah}(h]h ]h"]h$]h&]hhuh1jhhhM hj8 hhubh)}(h5它可以被设置成接收密钥环变化的通知::h]h4它可以被设置成接收密钥环变化的通知:}(hje hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM hj8 hhubj)}(hAkeyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fds[1], 0x01);h]hAkeyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fds[1], 0x01);}hjs sbah}(h]h ]h"]h$]h&]hhuh1jhhhMhj8 hhubh)}(h5然后,这些通知可以被如下方式所使用::h]h4然后,这些通知可以被如下方式所使用:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj8 hhubj)}(hX>static void consumer(int rfd, struct watch_queue_buffer *buf) { unsigned char buffer[128]; ssize_t buf_len; while (buf_len = read(rfd, buffer, sizeof(buffer)), buf_len > 0 ) { void *p = buffer; void *end = buffer + buf_len; while (p < end) { union { struct watch_notification n; unsigned char buf1[128]; } n; size_t largest, len; largest = end - p; if (largest > 128) largest = 128; memcpy(&n, p, largest); len = (n->info & WATCH_INFO_LENGTH) >> WATCH_INFO_LENGTH__SHIFT; if (len == 0 || len > largest) return; switch (n.n.type) { case WATCH_TYPE_META: got_meta(&n.n); case WATCH_TYPE_KEY_NOTIFY: saw_key_change(&n.n); break; } p += len; } } }h]hX>static void consumer(int rfd, struct watch_queue_buffer *buf) { unsigned char buffer[128]; ssize_t buf_len; while (buf_len = read(rfd, buffer, sizeof(buffer)), buf_len > 0 ) { void *p = buffer; void *end = buffer + buf_len; while (p < end) { union { struct watch_notification n; unsigned char buf1[128]; } n; size_t largest, len; largest = end - p; if (largest > 128) largest = 128; memcpy(&n, p, largest); len = (n->info & WATCH_INFO_LENGTH) >> WATCH_INFO_LENGTH__SHIFT; if (len == 0 || len > largest) return; switch (n.n.type) { case WATCH_TYPE_META: got_meta(&n.n); case WATCH_TYPE_KEY_NOTIFY: saw_key_change(&n.n); break; } p += len; } } }}hj sbah}(h]h ]h"]h$]h&]hhuh1jhhhMhj8 hhubeh}(h]jNah ]h"]用户空间代码示例ah$]h&]uh1jhjhhhhhMubeh}(h]id1ah ]h"]通用通知机制ah$]h&]uh1jhhhhhhhKubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(jN 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_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}nameids}(j j jhjcjj>jj`jjj9jjjjjjj j5 j,j jNu nametypes}(j jhjjjj9jjjj5 j uh}(j jjcjj>jkj`jjjjjjj<jjj jj,jjNj8 j8j/jZjQj|jsjjjjjjjjj&jjHj?u footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}j KsRparse_messages]transform_messages] transformerN include_log]9Documentation/translations/zh_CN/core-api/watch_queue.rst(NNNNta decorationNhhub.