public inbox for wireguard@lists.zx2c4.com
 help / color / mirror / Atom feed
From: odedkatz <katz.oded@gmail.com>
To: wireguard@lists.zx2c4.com
Cc: odedk@twingate.com, alexey@twingate.com
Subject: [PATCH 1/1] Fix missed-wakeup race in ring buffer Alertable signaling
Date: Tue, 24 Feb 2026 15:47:17 -0800	[thread overview]
Message-ID: <20260224234717.16883-2-katz.oded@gmail.com> (raw)
In-Reply-To: <20260224234717.16883-1-katz.oded@gmail.com>

From: Alexey Lapuka <alexey@twingate.com>

   Add MemoryBarrier() between store-load pairs in the Dekker-style
   synchronization used by the Receive ring's Alertable/Tail protocol.

   On x86-64, WriteRelease/ReadAcquire only prevent compiler reordering
   and provide acquire/release semantics, but do not emit MFENCE — the
   only instruction that prevents store-load reordering across cores.
   Without a full barrier, both the userspace producer and the kernel
   consumer can simultaneously read stale values:

     Userspace: STORE(Tail)  ...  LOAD(Alertable) -> sees FALSE (stale)
     Driver:    STORE(Alertable=TRUE) ... LOAD(Tail) -> sees old tail

   The driver then enters KeWaitForMultipleObjects with no pending
   SetEvent, sleeping until a TCP retransmission (typically 4-5s later)
   re-triggers the send path and wins the race.

   The fix adds MemoryBarrier() (MFENCE on x86) on both sides:
   - api/session.c WintunSendPacket: between WriteULongRelease(Tail) and
     ReadAcquire(Alertable)
   - driver/twintun.c TunProcessReceiveData: between
     WriteRelease(Alertable, TRUE) and ReadULongAcquire(Tail)

   This guarantees that at least one side always observes the other's
   store, preventing the missed wakeup while preserving the Alertable
   optimization that avoids unnecessary SetEvent syscalls.
---
 api/session.c   | 1 +
 driver/wintun.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/api/session.c b/api/session.c
index ab96c64..13d5bca 100644
--- a/api/session.c
+++ b/api/session.c
@@ -302,6 +302,7 @@ WintunSendPacket(TUN_SESSION *Session, const BYTE *Packet)
     if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease)
     {
         WriteULongRelease(&Session->Descriptor.Receive.Ring->Tail, Session->Receive.TailRelease);
+        MemoryBarrier();
         if (ReadAcquire(&Session->Descriptor.Receive.Ring->Alertable))
             SetEvent(Session->Descriptor.Receive.TailMoved);
     }
diff --git a/driver/wintun.c b/driver/wintun.c
index 82e346b..72ba5d3 100644
--- a/driver/wintun.c
+++ b/driver/wintun.c
@@ -481,6 +481,7 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
             if (RingHead == RingTail)
             {
                 WriteRelease(&Ring->Alertable, TRUE);
+                MemoryBarrier();
                 RingTail = ReadULongAcquire(&Ring->Tail);
                 if (RingHead == RingTail)
                 {
-- 
2.43.0


      reply	other threads:[~2026-02-24 23:50 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-24 23:47 [PATCH 0/1] wintun driver get stalled for few sec until another packet is being sent -- approach 2 odedkatz
2026-02-24 23:47 ` odedkatz [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260224234717.16883-2-katz.oded@gmail.com \
    --to=katz.oded@gmail.com \
    --cc=alexey@twingate.com \
    --cc=odedk@twingate.com \
    --cc=wireguard@lists.zx2c4.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox