@@ -15,14 +15,38 @@ use std::sync::atomic::{AtomicU64, Ordering};
1515use std:: sync:: { Mutex , OnceLock } ;
1616use std:: time:: Instant ;
1717
18- #[ inline]
19- unsafe fn get_errno ( ) -> c_int {
20- * libc:: __errno_location ( )
18+ /// RAII guard that snapshots `errno` on creation and restores it on drop.
19+ ///
20+ /// I/O profiling wrappers intercept libc calls and run additional logic (timing, sampling) that
21+ /// can clobber `errno`. Callers of the original syscall expect `errno` to reflect the syscall
22+ /// result, not our wrapper internals. Create an `ErrnoBackup` right after the original syscall
23+ /// returns and let it live until the end of the wrapper function, its `Drop` impl will
24+ /// transparently restore the original `errno` value.
25+ struct ErrnoBackup {
26+ errno : c_int ,
27+ location : * mut c_int ,
28+ }
29+
30+ impl ErrnoBackup {
31+ /// Snapshots the current `errno` value.
32+ #[ inline]
33+ unsafe fn new ( ) -> Self {
34+ let location = libc:: __errno_location ( ) ;
35+ Self {
36+ errno : * location,
37+ location,
38+ }
39+ }
2140}
2241
23- #[ inline]
24- unsafe fn set_errno ( errno : c_int ) {
25- * libc:: __errno_location ( ) = errno;
42+ impl Drop for ErrnoBackup {
43+ /// Restores `errno` value.
44+ #[ inline]
45+ fn drop ( & mut self ) {
46+ unsafe {
47+ * self . location = self . errno ;
48+ }
49+ }
2650}
2751
2852static mut ORIG_POLL : unsafe extern "C" fn ( * mut libc:: pollfd , u64 , c_int ) -> i32 = libc:: poll;
@@ -37,7 +61,7 @@ static mut ORIG_POLL: unsafe extern "C" fn(*mut libc::pollfd, u64, c_int) -> i32
3761unsafe extern "C" fn observed_poll ( fds : * mut libc:: pollfd , nfds : u64 , timeout : c_int ) -> i32 {
3862 let start = Instant :: now ( ) ;
3963 let ret = ORIG_POLL ( fds, nfds, timeout) ;
40- let ret_errno = get_errno ( ) ;
64+ let _errno_backup = ErrnoBackup :: new ( ) ;
4165 let duration = start. elapsed ( ) ;
4266
4367 if !fds. is_null ( ) {
@@ -73,7 +97,6 @@ unsafe extern "C" fn observed_poll(fds: *mut libc::pollfd, nfds: u64, timeout: c
7397 }
7498 }
7599
76- set_errno ( ret_errno) ;
77100 ret
78101}
79102
@@ -87,7 +110,7 @@ unsafe extern "C" fn observed_recv(
87110) -> isize {
88111 let start = Instant :: now ( ) ;
89112 let len = ORIG_RECV ( socket, buf, length, flags) ;
90- let ret_errno = get_errno ( ) ;
113+ let _errno_backup = ErrnoBackup :: new ( ) ;
91114 let duration = start. elapsed ( ) ;
92115
93116 let duration_nanos = duration. as_nanos ( ) as u64 ;
@@ -102,7 +125,6 @@ unsafe extern "C" fn observed_recv(
102125 }
103126 }
104127
105- set_errno ( ret_errno) ;
106128 len
107129}
108130
@@ -116,7 +138,7 @@ unsafe extern "C" fn observed_recvmsg(
116138) -> isize {
117139 let start = Instant :: now ( ) ;
118140 let len = ORIG_RECVMSG ( socket, msg, flags) ;
119- let ret_errno = get_errno ( ) ;
141+ let _errno_backup = ErrnoBackup :: new ( ) ;
120142 let duration = start. elapsed ( ) ;
121143
122144 let duration_nanos = duration. as_nanos ( ) as u64 ;
@@ -131,7 +153,6 @@ unsafe extern "C" fn observed_recvmsg(
131153 }
132154 }
133155
134- set_errno ( ret_errno) ;
135156 len
136157}
137158
@@ -154,7 +175,7 @@ unsafe extern "C" fn observed_recvfrom(
154175) -> isize {
155176 let start = Instant :: now ( ) ;
156177 let len = ORIG_RECVFROM ( socket, buf, length, flags, address, address_len) ;
157- let ret_errno = get_errno ( ) ;
178+ let _errno_backup = ErrnoBackup :: new ( ) ;
158179 let duration = start. elapsed ( ) ;
159180
160181 let duration_nanos = duration. as_nanos ( ) as u64 ;
@@ -169,7 +190,6 @@ unsafe extern "C" fn observed_recvfrom(
169190 }
170191 }
171192
172- set_errno ( ret_errno) ;
173193 len
174194}
175195
@@ -183,7 +203,7 @@ unsafe extern "C" fn observed_send(
183203) -> isize {
184204 let start = Instant :: now ( ) ;
185205 let len = ORIG_SEND ( socket, buf, length, flags) ;
186- let ret_errno = get_errno ( ) ;
206+ let _errno_backup = ErrnoBackup :: new ( ) ;
187207 let duration = start. elapsed ( ) ;
188208
189209 let duration_nanos = duration. as_nanos ( ) as u64 ;
@@ -198,7 +218,6 @@ unsafe extern "C" fn observed_send(
198218 }
199219 }
200220
201- set_errno ( ret_errno) ;
202221 len
203222}
204223
@@ -211,7 +230,7 @@ unsafe extern "C" fn observed_sendmsg(
211230) -> isize {
212231 let start = Instant :: now ( ) ;
213232 let len = ORIG_SENDMSG ( socket, msg, flags) ;
214- let ret_errno = get_errno ( ) ;
233+ let _errno_backup = ErrnoBackup :: new ( ) ;
215234 let duration = start. elapsed ( ) ;
216235
217236 let duration_nanos = duration. as_nanos ( ) as u64 ;
@@ -226,7 +245,6 @@ unsafe extern "C" fn observed_sendmsg(
226245 }
227246 }
228247
229- set_errno ( ret_errno) ;
230248 len
231249}
232250
@@ -244,7 +262,7 @@ unsafe extern "C" fn observed_fwrite(
244262) -> usize {
245263 let start = Instant :: now ( ) ;
246264 let len = ORIG_FWRITE ( ptr, size, nobj, stream) ;
247- let ret_errno = get_errno ( ) ;
265+ let _errno_backup = ErrnoBackup :: new ( ) ;
248266 let duration = start. elapsed ( ) ;
249267
250268 let duration_nanos = duration. as_nanos ( ) as u64 ;
@@ -258,15 +276,14 @@ unsafe extern "C" fn observed_fwrite(
258276 }
259277 }
260278
261- set_errno ( ret_errno) ;
262279 len
263280}
264281
265282static mut ORIG_WRITE : unsafe extern "C" fn ( c_int , * const c_void , usize ) -> isize = libc:: write;
266283unsafe extern "C" fn observed_write ( fd : c_int , buf : * const c_void , count : usize ) -> isize {
267284 let start = Instant :: now ( ) ;
268285 let len = ORIG_WRITE ( fd, buf, count) ;
269- let ret_errno = get_errno ( ) ;
286+ let _errno_backup = ErrnoBackup :: new ( ) ;
270287 let duration = start. elapsed ( ) ;
271288
272289 let duration_nanos = duration. as_nanos ( ) as u64 ;
@@ -299,7 +316,6 @@ unsafe extern "C" fn observed_write(fd: c_int, buf: *const c_void, count: usize)
299316 }
300317 }
301318
302- set_errno ( ret_errno) ;
303319 len
304320}
305321
@@ -316,7 +332,7 @@ unsafe extern "C" fn observed_fread(
316332) -> usize {
317333 let start = Instant :: now ( ) ;
318334 let len = ORIG_FREAD ( ptr, size, nobj, stream) ;
319- let ret_errno = get_errno ( ) ;
335+ let _errno_backup = ErrnoBackup :: new ( ) ;
320336 let duration = start. elapsed ( ) ;
321337
322338 let duration_nanos = duration. as_nanos ( ) as u64 ;
@@ -330,15 +346,14 @@ unsafe extern "C" fn observed_fread(
330346 }
331347 }
332348
333- set_errno ( ret_errno) ;
334349 len
335350}
336351
337352static mut ORIG_READ : unsafe extern "C" fn ( c_int , * mut c_void , usize ) -> isize = libc:: read;
338353unsafe extern "C" fn observed_read ( fd : c_int , buf : * mut c_void , count : usize ) -> isize {
339354 let start = Instant :: now ( ) ;
340355 let len = ORIG_READ ( fd, buf, count) ;
341- let ret_errno = get_errno ( ) ;
356+ let _errno_backup = ErrnoBackup :: new ( ) ;
342357 let duration = start. elapsed ( ) ;
343358
344359 let duration_nanos = duration. as_nanos ( ) as u64 ;
@@ -369,19 +384,17 @@ unsafe extern "C" fn observed_read(fd: c_int, buf: *mut c_void, count: usize) ->
369384 }
370385 }
371386
372- set_errno ( ret_errno) ;
373387 len
374388}
375389
376390static mut ORIG_CLOSE : unsafe extern "C" fn ( i32 ) -> i32 = libc:: close;
377391/// The sole purpose of this function is to remove the `fd` from the `FD_CACHE`
378392unsafe extern "C" fn observed_close ( fd : i32 ) -> i32 {
379393 let ret = ORIG_CLOSE ( fd) ;
380- let ret_errno = get_errno ( ) ;
394+ let _errno_backup = ErrnoBackup :: new ( ) ;
381395 let cache = FD_CACHE . get_or_init ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
382396 let mut cache = cache. lock ( ) . unwrap ( ) ;
383397 cache. remove ( & fd) ;
384- set_errno ( ret_errno) ;
385398 ret
386399}
387400
0 commit comments