From c8fb37a521b1f8cf13ddf1ffb81b0a30b05e0706 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 31 May 2025 10:39:09 +0000 Subject: [PATCH] Don't call WSACleanup on process exit --- .../src/sys/net/connection/socket/windows.rs | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index ce975bb2289c2..b71d8b1357b5a 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -8,7 +8,8 @@ use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, }; -use crate::sync::OnceLock; +use crate::sync::atomic::Atomic; +use crate::sync::atomic::Ordering::{AcqRel, Relaxed}; use crate::sys::c; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; @@ -114,33 +115,38 @@ pub(super) mod netc { #[expect(missing_debug_implementations)] pub struct Socket(OwnedSocket); -static WSA_CLEANUP: OnceLock i32> = OnceLock::new(); +static WSA_INITIALIZED: Atomic = Atomic::::new(false); /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. +#[inline] pub fn init() { - let _ = WSA_CLEANUP.get_or_init(|| unsafe { + if !WSA_INITIALIZED.load(Relaxed) { + wsa_startup(); + } +} + +#[cold] +fn wsa_startup() { + unsafe { let mut data: c::WSADATA = mem::zeroed(); let ret = c::WSAStartup( 0x202, // version 2.2 &mut data, ); assert_eq!(ret, 0); - - // Only register `WSACleanup` if `WSAStartup` is actually ever called. - // Workaround to prevent linking to `WS2_32.dll` when no network functionality is used. - // See issue #85441. - c::WSACleanup - }); + if WSA_INITIALIZED.swap(true, AcqRel) { + // If another thread raced with us and called WSAStartup first then call + // WSACleanup so it's as though WSAStartup was only called once. + c::WSACleanup(); + } + } } pub fn cleanup() { - // only perform cleanup if network functionality was actually initialized - if let Some(cleanup) = WSA_CLEANUP.get() { - unsafe { - cleanup(); - } - } + // We don't need to call WSACleanup here because exiting the process will cause + // the OS to clean everything for us, which is faster than doing it manually. + // See #141799. } /// Returns the last error from the Windows socket interface.