{"id":6250,"date":"2026-10-22T04:36:27","date_gmt":"2026-10-22T07:36:27","guid":{"rendered":"https:\/\/tucumandevelopers.com\/index.php\/2026\/10\/22\/2-4-the-wait-still-works-in-a-napi-thread\/"},"modified":"2026-10-22T04:36:27","modified_gmt":"2026-10-22T07:36:27","slug":"2-4-the-wait-still-works-in-a-napi-thread","status":"publish","type":"post","link":"https:\/\/tucumandevelopers.com\/index.php\/2026\/10\/22\/2-4-the-wait-still-works-in-a-napi-thread\/","title":{"rendered":"[2\/4] The Wait Still Works in a NAPI Thread"},"content":{"rendered":"<div>\n<div><\/div>\n<p>BH means bottom half, referring here to softirq-side processing. On a non-RT kernel, this BH-disabled region is covered by RCU synchronization.<\/p>\n<p>With <code>PREEMPT_RT<\/code>, BH-disabled tasks can be preempted. That requires a different mechanism. In Linux 7.3, the RT implementation of <code>__local_bh_disable_ip()<\/code> explicitly calls <code>rcu_read_lock()<\/code> on the outermost entry from a preemptible context. The matching exit calls <code>rcu_read_unlock()<\/code>. Entry from an already non-preemptible context relies on that protection instead.<\/p>\n<p>RCU tracks readers preempted inside an explicit read-side region. Switching to another task does not make the suspended poll disappear from the wait.<\/p>\n<p>For RT receive processing through <code>ksoftirqd<\/code>, the enclosing <code>ksoftirqd_run_begin()<\/code> and <code>ksoftirqd_run_end()<\/code> provide the corresponding BH entry and exit. In the paths examined here, protection therefore extends through the interrupt enable. This is not a proof covering every other entry, such as userspace-driven busy polling.<\/p>\n<h2> <a name=\"the-question-the-documentation-leaves-open\" href=\"#the-question-the-documentation-leaves-open\"> <\/a> The question the documentation leaves open <\/h2>\n<p>Does the NAPI guide require these two functions together? No. It warns against data-structure access after completion, yet its example unmasks interrupts afterward. It does not spell out how that unmask should synchronize with shutdown.<\/p>\n<p>That leaves a boundary for driver authors and reviewers to examine. It does not prove that documentation gaps caused bugs, or that different synchronization methods are wrong.<\/p>\n<p>I cover NAPI shutdown races in <a href=\"https:\/\/www.amazon.com\/dp\/B0HLST4J4Y\" target=\"_blank\" rel=\"noopener noreferrer\">Getting Started with Linux Device Drivers, Volume 3<\/a>. Reading beyond the suspicious line gave me something useful to pass to the next reader.<\/p>\n<p>That line of synchronization had a purpose. How did other drivers handle shutdown? In Intel&#8217;s igb, I found a flag check intended to prevent interrupts from being enabled while the device was down. But what if another CPU advanced shutdown just after that check? Next, I follow what happens in that gap.<\/p>\n<\/p><\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Fuente: <a href=\"https:\/\/dev.to\/yutakahirata\/24-the-wait-still-works-in-a-napi-thread-1372\">Art\u00edculo original<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>BH means bottom half, referring here to softirq-side processing. On a non-RT kernel, this BH-disabled region is covered by RCU synchronization. With PREEMPT_RT, BH-disabled tasks can be preempted. That requires a different mechanism. In Linux 7.3, the RT implementation of __local_bh_disable_ip() explicitly calls rcu_read_lock() on the outermost entry from a preemptible context. The matching exit [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":6249,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"webixso_pending_account_ids":""},"categories":[41],"tags":[],"class_list":["post-6250","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devto"],"jetpack_publicize_connections":[],"_links":{"self":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/6250","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/comments?post=6250"}],"version-history":[{"count":0,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/6250\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media\/6249"}],"wp:attachment":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media?parent=6250"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/categories?post=6250"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/tags?post=6250"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}