@@ -8,7 +8,8 @@ use crate::net::{Shutdown, SocketAddr};
88use crate :: os:: windows:: io:: {
99 AsRawSocket , AsSocket , BorrowedSocket , FromRawSocket , IntoRawSocket , OwnedSocket , RawSocket ,
1010} ;
11- use crate :: sync:: OnceLock ;
11+ use crate :: sync:: atomic:: Atomic ;
12+ use crate :: sync:: atomic:: Ordering :: { AcqRel , Relaxed } ;
1213use crate :: sys:: c;
1314use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
1415use crate :: time:: Duration ;
@@ -114,33 +115,38 @@ pub(super) mod netc {
114115#[ expect( missing_debug_implementations) ]
115116pub struct Socket ( OwnedSocket ) ;
116117
117- static WSA_CLEANUP : OnceLock < unsafe extern "system" fn ( ) -> i32 > = OnceLock :: new ( ) ;
118+ static WSA_INITIALIZED : Atomic < bool > = Atomic :: < bool > :: new ( false ) ;
118119
119120/// Checks whether the Windows socket interface has been started already, and
120121/// if not, starts it.
122+ #[ inline]
121123pub fn init ( ) {
122- let _ = WSA_CLEANUP . get_or_init ( || unsafe {
124+ if !WSA_INITIALIZED . load ( Relaxed ) {
125+ wsa_startup ( ) ;
126+ }
127+ }
128+
129+ #[ cold]
130+ fn wsa_startup ( ) {
131+ unsafe {
123132 let mut data: c:: WSADATA = mem:: zeroed ( ) ;
124133 let ret = c:: WSAStartup (
125134 0x202 , // version 2.2
126135 & mut data,
127136 ) ;
128137 assert_eq ! ( ret, 0 ) ;
129-
130- // Only register `WSACleanup` if `WSAStartup` is actually ever called.
131- // Workaround to prevent linking to `WS2_32.dll` when no network functionality is used .
132- // See issue #85441.
133- c :: WSACleanup
134- } ) ;
138+ if WSA_INITIALIZED . swap ( true , AcqRel ) {
139+ // If another thread raced with us and called WSAStartup first then call
140+ // WSACleanup so it's as though WSAStartup was only called once .
141+ c :: WSACleanup ( ) ;
142+ }
143+ }
135144}
136145
137146pub fn cleanup ( ) {
138- // only perform cleanup if network functionality was actually initialized
139- if let Some ( cleanup) = WSA_CLEANUP . get ( ) {
140- unsafe {
141- cleanup ( ) ;
142- }
143- }
147+ // We don't need to call WSACleanup here because exiting the process will cause
148+ // the OS to clean everything for us, which is faster than doing it manually.
149+ // See #141799.
144150}
145151
146152/// Returns the last error from the Windows socket interface.
0 commit comments