@@ -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 , Acquire , Relaxed } ;
12
13
use crate :: sys:: c;
13
14
use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
14
15
use crate :: time:: Duration ;
@@ -114,35 +115,36 @@ 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
- } ) ;
135
- }
136
-
137
- 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 ( ) ;
138
+ if WSA_INITIALIZED . compare_exchange ( false , true , AcqRel , Acquire ) . is_err ( ) {
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
142
}
143
143
}
144
144
}
145
145
146
+ pub fn cleanup ( ) { }
147
+
146
148
/// Returns the last error from the Windows socket interface.
147
149
fn last_error ( ) -> io:: Error {
148
150
io:: Error :: from_raw_os_error ( unsafe { c:: WSAGetLastError ( ) } )
0 commit comments