1 // Copyright 2017 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //! Macro and helper trait for handling interrupted routines. 6 7 use std::io; 8 9 use libc::EINTR; 10 11 /// Trait for determining if a result indicates the operation was interrupted. 12 pub trait InterruptibleResult { 13 /// Returns `true` if this result indicates the operation was interrupted and should be retried, 14 /// and `false` in all other cases. is_interrupted(&self) -> bool15 fn is_interrupted(&self) -> bool; 16 } 17 18 impl<T> InterruptibleResult for crate::Result<T> { is_interrupted(&self) -> bool19 fn is_interrupted(&self) -> bool { 20 matches!(self, Err(e) if e.errno() == EINTR) 21 } 22 } 23 24 impl<T> InterruptibleResult for io::Result<T> { is_interrupted(&self) -> bool25 fn is_interrupted(&self) -> bool { 26 matches!(self, Err(e) if e.kind() == io::ErrorKind::Interrupted) 27 } 28 } 29 30 /// Macro that retries the given expression every time its result indicates it was interrupted (i.e. 31 /// returned `EINTR`). This is useful for operations that are prone to being interrupted by 32 /// signals, such as blocking syscalls. 33 /// 34 /// The given expression `$x` can return 35 /// 36 /// * `crate::linux::Result` in which case the expression is retried if the `Error::errno()` is 37 /// `EINTR`. 38 /// * `std::io::Result` in which case the expression is retried if the `ErrorKind` is 39 /// `ErrorKind::Interrupted`. 40 /// 41 /// Note that if expression returns i32 (i.e. either -1 or error code), then handle_eintr_errno() 42 /// or handle_eintr_rc() should be used instead. 43 /// 44 /// In all cases where the result does not indicate that the expression was interrupted, the result 45 /// is returned verbatim to the caller of this macro. 46 /// 47 /// See the section titled _Interruption of system calls and library functions by signal handlers_ 48 /// on the man page for `signal(7)` to see more information about interruptible syscalls. 49 /// 50 /// To summarize, routines that use one of these syscalls _might_ need to handle `EINTR`: 51 /// 52 /// * `accept(2)` 53 /// * `clock_nanosleep(2)` 54 /// * `connect(2)` 55 /// * `epoll_pwait(2)` 56 /// * `epoll_wait(2)` 57 /// * `fcntl(2)` 58 /// * `fifo(7)` 59 /// * `flock(2)` 60 /// * `futex(2)` 61 /// * `getrandom(2)` 62 /// * `inotify(7)` 63 /// * `io_getevents(2)` 64 /// * `ioctl(2)` 65 /// * `mq_receive(3)` 66 /// * `mq_send(3)` 67 /// * `mq_timedreceive(3)` 68 /// * `mq_timedsend(3)` 69 /// * `msgrcv(2)` 70 /// * `msgsnd(2)` 71 /// * `nanosleep(2)` 72 /// * `open(2)` 73 /// * `pause(2)` 74 /// * `poll(2)` 75 /// * `ppoll(2)` 76 /// * `pselect(2)` 77 /// * `pthread_cond_wait(3)` 78 /// * `pthread_mutex_lock(3)` 79 /// * `read(2)` 80 /// * `readv(2)` 81 /// * `recv(2)` 82 /// * `recvfrom(2)` 83 /// * `recvmmsg(2)` 84 /// * `recvmsg(2)` 85 /// * `select(2)` 86 /// * `sem_timedwait(3)` 87 /// * `sem_wait(3)` 88 /// * `semop(2)` 89 /// * `semtimedop(2)` 90 /// * `send(2)` 91 /// * `sendmsg(2)` 92 /// * `sendto(2)` 93 /// * `setsockopt(2)` 94 /// * `sigsuspend(2)` 95 /// * `sigtimedwait(2)` 96 /// * `sigwaitinfo(2)` 97 /// * `sleep(3)` 98 /// * `usleep(3)` 99 /// * `wait(2)` 100 /// * `wait3(2)` 101 /// * `wait4(2)` 102 /// * `waitid(2)` 103 /// * `waitpid(2)` 104 /// * `write(2)` 105 /// * `writev(2)` 106 /// 107 /// # Examples 108 /// 109 /// ``` 110 /// # use base::handle_eintr; 111 /// # use std::io::stdin; 112 /// # fn main() { 113 /// let mut line = String::new(); 114 /// let res = handle_eintr!(stdin().read_line(&mut line)); 115 /// # } 116 /// ``` 117 #[macro_export] 118 macro_rules! handle_eintr { 119 ($x:expr) => {{ 120 use $crate::unix::handle_eintr::InterruptibleResult; 121 let res; 122 loop { 123 match $x { 124 ref v if v.is_interrupted() => continue, 125 v => { 126 res = v; 127 break; 128 } 129 } 130 } 131 res 132 }}; 133 } 134 135 /// Macro that retries the given expression every time its result indicates it was interrupted. 136 /// It is intended to use with system functions that return `EINTR` and other error codes 137 /// directly as their result. 138 /// Most of reentrant functions use this way of signalling errors. 139 #[macro_export] 140 macro_rules! handle_eintr_rc { 141 ($x:expr) => {{ 142 use libc::EINTR; 143 let mut res; 144 loop { 145 res = $x; 146 if res != EINTR { 147 break; 148 } 149 } 150 res 151 }}; 152 } 153 154 /// Macro that retries the given expression every time its result indicates it was interrupted. 155 /// It is intended to use with system functions that signal error by returning `-1` and setting 156 /// `errno` to appropriate error code (`EINTR`, `EINVAL`, etc.) 157 /// Most of standard non-reentrant libc functions use this way of signalling errors. 158 #[macro_export] 159 macro_rules! handle_eintr_errno { 160 ($x:expr) => {{ 161 use libc::EINTR; 162 use $crate::Error; 163 let mut res; 164 loop { 165 res = $x; 166 if res != -1 || Error::last() != Error::new(EINTR) { 167 break; 168 } 169 } 170 res 171 }}; 172 } 173 174 #[cfg(test)] 175 mod tests { 176 use super::*; 177 use crate::Error as SysError; 178 179 // Sets errno to the given error code. set_errno(e: i32)180 fn set_errno(e: i32) { 181 #[cfg(target_os = "android")] 182 unsafe fn errno_location() -> *mut libc::c_int { 183 libc::__errno() 184 } 185 #[cfg(target_os = "linux")] 186 unsafe fn errno_location() -> *mut libc::c_int { 187 libc::__errno_location() 188 } 189 #[cfg(target_os = "macos")] 190 unsafe fn errno_location() -> *mut libc::c_int { 191 libc::__error() 192 } 193 194 // SAFETY: trivially safe 195 unsafe { 196 *errno_location() = e; 197 } 198 } 199 200 #[test] i32_eintr_rc()201 fn i32_eintr_rc() { 202 let mut count = 3; 203 let mut dummy = || { 204 count -= 1; 205 if count > 0 { 206 EINTR 207 } else { 208 0 209 } 210 }; 211 let res = handle_eintr_rc!(dummy()); 212 assert_eq!(res, 0); 213 assert_eq!(count, 0); 214 } 215 216 #[test] i32_eintr_errno()217 fn i32_eintr_errno() { 218 let mut count = 3; 219 let mut dummy = || { 220 count -= 1; 221 if count > 0 { 222 set_errno(EINTR); 223 -1 224 } else { 225 56 226 } 227 }; 228 let res = handle_eintr_errno!(dummy()); 229 assert_eq!(res, 56); 230 assert_eq!(count, 0); 231 } 232 233 #[test] sys_eintr()234 fn sys_eintr() { 235 let mut count = 7; 236 let mut dummy = || { 237 count -= 1; 238 if count > 1 { 239 Err(SysError::new(EINTR)) 240 } else { 241 Ok(101) 242 } 243 }; 244 let res = handle_eintr!(dummy()); 245 assert_eq!(res, Ok(101)); 246 assert_eq!(count, 1); 247 } 248 249 #[test] io_eintr()250 fn io_eintr() { 251 let mut count = 108; 252 let mut dummy = || { 253 count -= 1; 254 if count > 99 { 255 Err(io::Error::new( 256 io::ErrorKind::Interrupted, 257 "interrupted again :(", 258 )) 259 } else { 260 Ok(32) 261 } 262 }; 263 let res = handle_eintr!(dummy()); 264 assert_eq!(res.unwrap(), 32); 265 assert_eq!(count, 99); 266 } 267 } 268