Bug 1410702 - P2: Handle EINTR from recvmsg/sendmsg calls. r?kinetik draft
authorDan Glastonbury <dan.glastonbury@gmail.com>
Wed, 25 Oct 2017 14:57:26 +1000
changeset 685924 6e70a08743324c46d6b3eebe7c3afab202c794d0
parent 685923 f4708359411a65fba620e29b235dffbe052e11e9
child 737243 930063946bcbbb053072cb549c1059164bcec781
push id86034
push userbmo:dglastonbury@mozilla.com
push dateWed, 25 Oct 2017 05:03:02 +0000
reviewerskinetik
bugs1410702
milestone58.0a1
Bug 1410702 - P2: Handle EINTR from recvmsg/sendmsg calls. r?kinetik MozReview-Commit-ID: juVD61XSzL
media/audioipc/audioipc/src/msg.rs
--- a/media/audioipc/audioipc/src/msg.rs
+++ b/media/audioipc/audioipc/src/msg.rs
@@ -1,14 +1,32 @@
 use libc;
 use std::io;
 use std::mem;
 use std::os::unix::io::RawFd;
 use std::ptr;
 
+fn cvt(r: libc::ssize_t) -> io::Result<usize> {
+    if r == -1 {
+        Err(io::Error::last_os_error())
+    } else {
+        Ok(r as usize)
+    }
+}
+
+// Convert return of -1 into error message, handling retry on EINTR
+fn cvt_r<F: FnMut() -> libc::ssize_t>(mut f: F) -> io::Result<usize> {
+    loop {
+        match cvt(f()) {
+            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {},
+            other => return other,
+        }
+    }
+}
+
 // Note: The following fields must be laid out together, the OS expects them
 // to be part of a single allocation.
 #[repr(C)]
 struct CmsgSpace {
     cmsghdr: libc::cmsghdr,
     #[cfg(not(target_os = "macos"))]
     __padding: [usize; 0],
     data: libc::c_int,
@@ -54,22 +72,17 @@ pub fn sendmsg(fd: RawFd, to_send: &[u8]
     iovec.iov_len = to_send.len();
 
     cmsg.cmsghdr.cmsg_len = cmsg_len() as _;
     cmsg.cmsghdr.cmsg_level = libc::SOL_SOCKET;
     cmsg.cmsghdr.cmsg_type = libc::SCM_RIGHTS;
 
     cmsg.data = fd_to_send.unwrap_or(-1);
 
-    let result = unsafe { libc::sendmsg(fd, &msghdr, 0) };
-    if result >= 0 {
-        Ok(result as usize)
-    } else {
-        Err(io::Error::last_os_error())
-    }
+    cvt_r(|| unsafe { libc::sendmsg(fd, &msghdr, 0) })
 }
 
 pub fn recvmsg(fd: RawFd, to_recv: &mut [u8]) -> io::Result<(usize, Option<RawFd>)> {
     let mut msghdr: libc::msghdr = unsafe { mem::zeroed() };
     let mut iovec: libc::iovec = unsafe { mem::zeroed() };
     let mut cmsg: CmsgSpace = unsafe { mem::zeroed() };
 
     msghdr.msg_iov = &mut iovec as *mut _;
@@ -80,31 +93,27 @@ pub fn recvmsg(fd: RawFd, to_recv: &mut 
     iovec.iov_base = if to_recv.is_empty() {
         // Empty Vecs have a non-null pointer.
         ptr::null_mut()
     } else {
         to_recv.as_ptr() as *const _ as *mut _
     };
     iovec.iov_len = to_recv.len();
 
-    let result = unsafe { libc::recvmsg(fd, &mut msghdr, 0) };
-    if result >= 0 {
-        let fd = if msghdr.msg_controllen == cmsg_space() as _ &&
-            cmsg.cmsghdr.cmsg_len == cmsg_len() as _ &&
-            cmsg.cmsghdr.cmsg_level == libc::SOL_SOCKET &&
-            cmsg.cmsghdr.cmsg_type == libc::SCM_RIGHTS {
-                Some(cmsg.data)
-            } else {
-                None
-            };
+    let result = try!(cvt_r(|| unsafe { libc::recvmsg(fd, &mut msghdr, 0) }));
+    let fd = if msghdr.msg_controllen == cmsg_space() as _ &&
+        cmsg.cmsghdr.cmsg_len == cmsg_len() as _ &&
+        cmsg.cmsghdr.cmsg_level == libc::SOL_SOCKET &&
+        cmsg.cmsghdr.cmsg_type == libc::SCM_RIGHTS {
+        Some(cmsg.data)
+    } else {
+        None
+    };
 
-        Ok((result as usize, fd))
-    } else {
-        Err(io::Error::last_os_error())
-    }
+    Ok((result as usize, fd))
 }
 
 #[cfg(test)]
 mod tests {
     use libc;
     use std::mem;
     use std::os::unix::net::UnixStream;
     use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};