@@ -8,7 +8,8 @@ use crate::net::{Shutdown, SocketAddr};
8
8
use crate :: os:: windows:: io:: {
9
9
AsRawSocket , AsSocket , BorrowedSocket , FromRawSocket , IntoRawSocket , OwnedSocket , RawSocket ,
10
10
} ;
11
- use crate :: sync:: OnceLock ;
11
+ use crate :: sync:: atomic:: Atomic ;
12
+ use crate :: sync:: atomic:: Ordering :: { AcqRel , Relaxed } ;
12
13
use crate :: sys:: c;
13
14
use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
14
15
use crate :: time:: Duration ;
@@ -114,33 +115,38 @@ pub(super) mod netc {
114
115
#[ expect( missing_debug_implementations) ]
115
116
pub struct Socket ( OwnedSocket ) ;
116
117
117
- static WSA_CLEANUP : OnceLock < unsafe extern "system" fn ( ) -> i32 > = OnceLock :: new ( ) ;
118
+ static WSA_INITIALIZED : Atomic < bool > = Atomic :: < bool > :: new ( false ) ;
118
119
119
120
/// Checks whether the Windows socket interface has been started already, and
120
121
/// if not, starts it.
122
+ #[ inline]
121
123
pub 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 {
123
132
let mut data: c:: WSADATA = mem:: zeroed ( ) ;
124
133
let ret = c:: WSAStartup (
125
134
0x202 , // version 2.2
126
135
& mut data,
127
136
) ;
128
137
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
+ }
135
144
}
136
145
137
146
pub 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.
144
150
}
145
151
146
152
/// Returns the last error from the Windows socket interface.
0 commit comments