]> git.lizzy.rs Git - rust.git/blobdiff - src/libnative/io/process.rs
auto merge of #15999 : Kimundi/rust/fix_folder, r=nikomatsakis
[rust.git] / src / libnative / io / process.rs
index d8486cb9f0942c64cf7b101affebf09f7bb66d2d..c89a40d65135144f880d0904619392942793a434 100644 (file)
 
 use libc::{pid_t, c_void, c_int};
 use libc;
+use std::c_str::CString;
+use std::io;
 use std::mem;
 use std::os;
 use std::ptr;
-use std::rt::rtio;
 use std::rt::rtio::{ProcessConfig, IoResult, IoError};
-use std::c_str::CString;
+use std::rt::rtio;
 
 use super::file;
 use super::util;
@@ -42,7 +43,7 @@ pub struct Process {
     /// A handle to the process - on unix this will always be NULL, but on
     /// windows it will be a HANDLE to the process, which will prevent the
     /// pid being re-used until the handle is closed.
-    handle: *(),
+    handle: *mut (),
 
     /// None until finish() is called.
     exit_code: Option<rtio::ProcessExit>,
@@ -73,47 +74,43 @@ pub fn spawn(cfg: ProcessConfig)
 
         fn get_io(io: rtio::StdioContainer,
                   ret: &mut Vec<Option<file::FileDesc>>)
-            -> (Option<os::Pipe>, c_int)
+            -> IoResult<Option<file::FileDesc>>
         {
             match io {
-                rtio::Ignored => { ret.push(None); (None, -1) }
-                rtio::InheritFd(fd) => { ret.push(None); (None, fd) }
+                rtio::Ignored => { ret.push(None); Ok(None) }
+                rtio::InheritFd(fd) => {
+                    ret.push(None);
+                    Ok(Some(file::FileDesc::new(fd, true)))
+                }
                 rtio::CreatePipe(readable, _writable) => {
-                    let pipe = os::pipe();
+                    let (reader, writer) = try!(pipe());
                     let (theirs, ours) = if readable {
-                        (pipe.input, pipe.out)
+                        (reader, writer)
                     } else {
-                        (pipe.out, pipe.input)
+                        (writer, reader)
                     };
-                    ret.push(Some(file::FileDesc::new(ours, true)));
-                    (Some(pipe), theirs)
+                    ret.push(Some(ours));
+                    Ok(Some(theirs))
                 }
             }
         }
 
         let mut ret_io = Vec::new();
-        let (in_pipe, in_fd) = get_io(cfg.stdin, &mut ret_io);
-        let (out_pipe, out_fd) = get_io(cfg.stdout, &mut ret_io);
-        let (err_pipe, err_fd) = get_io(cfg.stderr, &mut ret_io);
-
-        let res = spawn_process_os(cfg, in_fd, out_fd, err_fd);
-
-        unsafe {
-            for pipe in in_pipe.iter() { let _ = libc::close(pipe.input); }
-            for pipe in out_pipe.iter() { let _ = libc::close(pipe.out); }
-            for pipe in err_pipe.iter() { let _ = libc::close(pipe.out); }
-        }
+        let res = spawn_process_os(cfg,
+                                   try!(get_io(cfg.stdin, &mut ret_io)),
+                                   try!(get_io(cfg.stdout, &mut ret_io)),
+                                   try!(get_io(cfg.stderr, &mut ret_io)));
 
         match res {
             Ok(res) => {
-                Ok((Process {
-                        pid: res.pid,
-                        handle: res.handle,
-                        exit_code: None,
-                        exit_signal: None,
-                        deadline: 0,
-                    },
-                    ret_io))
+                let p = Process {
+                    pid: res.pid,
+                    handle: res.handle,
+                    exit_code: None,
+                    exit_signal: None,
+                    deadline: 0,
+                };
+                Ok((p, ret_io))
             }
             Err(e) => Err(e)
         }
@@ -173,7 +170,7 @@ fn kill(&mut self, signum: int) -> IoResult<()> {
             Some(..) => return Err(IoError {
                 code: ERROR as uint,
                 extra: 0,
-                detail: Some("can't kill an exited process".to_str()),
+                detail: Some("can't kill an exited process".to_string()),
             }),
             None => {}
         }
@@ -194,6 +191,37 @@ fn drop(&mut self) {
     }
 }
 
+fn pipe() -> IoResult<(file::FileDesc, file::FileDesc)> {
+    #[cfg(unix)] use ERROR = libc::EMFILE;
+    #[cfg(windows)] use ERROR = libc::WSAEMFILE;
+    struct Closer { fd: libc::c_int }
+
+    let os::Pipe { reader, writer } = match unsafe { os::pipe() } {
+        Ok(p) => p,
+        Err(io::IoError { detail, .. }) => return Err(IoError {
+            code: ERROR as uint,
+            extra: 0,
+            detail: detail,
+        })
+    };
+    let mut reader = Closer { fd: reader };
+    let mut writer = Closer { fd: writer };
+
+    let native_reader = file::FileDesc::new(reader.fd, true);
+    reader.fd = -1;
+    let native_writer = file::FileDesc::new(writer.fd, true);
+    writer.fd = -1;
+    return Ok((native_reader, native_writer));
+
+    impl Drop for Closer {
+        fn drop(&mut self) {
+            if self.fd != -1 {
+                let _ = unsafe { libc::close(self.fd) };
+            }
+        }
+    }
+}
+
 #[cfg(windows)]
 unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> {
     let handle = libc::OpenProcess(libc::PROCESS_TERMINATE |
@@ -241,12 +269,14 @@ unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> {
 
 struct SpawnProcessResult {
     pid: pid_t,
-    handle: *(),
+    handle: *mut (),
 }
 
 #[cfg(windows)]
 fn spawn_process_os(cfg: ProcessConfig,
-                    in_fd: c_int, out_fd: c_int, err_fd: c_int)
+                    in_fd: Option<file::FileDesc>,
+                    out_fd: Option<file::FileDesc>,
+                    err_fd: Option<file::FileDesc>)
                  -> IoResult<SpawnProcessResult> {
     use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
     use libc::consts::os::extra::{
@@ -264,15 +294,36 @@ fn spawn_process_os(cfg: ProcessConfig,
     use libc::funcs::extra::msvcrt::get_osfhandle;
 
     use std::mem;
+    use std::iter::Iterator;
+    use std::str::StrSlice;
 
     if cfg.gid.is_some() || cfg.uid.is_some() {
         return Err(IoError {
             code: libc::ERROR_CALL_NOT_IMPLEMENTED as uint,
             extra: 0,
-            detail: Some("unsupported gid/uid requested on windows".to_str()),
+            detail: Some("unsupported gid/uid requested on windows".to_string()),
         })
     }
 
+    // To have the spawning semantics of unix/windows stay the same, we need to
+    // read the *child's* PATH if one is provided. See #15149 for more details.
+    let program = cfg.env.and_then(|env| {
+        for &(ref key, ref v) in env.iter() {
+            if b"PATH" != key.as_bytes_no_nul() { continue }
+
+            // Split the value and test each path to see if the program exists.
+            for path in os::split_paths(v.as_bytes_no_nul()).move_iter() {
+                let path = path.join(cfg.program.as_bytes_no_nul())
+                               .with_extension(os::consts::EXE_EXTENSION);
+                if path.exists() {
+                    return Some(path.to_c_str())
+                }
+            }
+            break
+        }
+        None
+    });
+
     unsafe {
         let mut si = zeroed_startupinfo();
         si.cb = mem::size_of::<STARTUPINFO>() as DWORD;
@@ -283,49 +334,55 @@ fn spawn_process_os(cfg: ProcessConfig,
         // Similarly to unix, we don't actually leave holes for the stdio file
         // descriptors, but rather open up /dev/null equivalents. These
         // equivalents are drawn from libuv's windows process spawning.
-        let set_fd = |fd: c_int, slot: &mut HANDLE, is_stdin: bool| {
-            if fd == -1 {
-                let access = if is_stdin {
-                    libc::FILE_GENERIC_READ
-                } else {
-                    libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES
-                };
-                let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>();
-                let mut sa = libc::SECURITY_ATTRIBUTES {
-                    nLength: size as libc::DWORD,
-                    lpSecurityDescriptor: ptr::mut_null(),
-                    bInheritHandle: 1,
-                };
-                let filename = "NUL".to_utf16().append_one(0);
-                *slot = libc::CreateFileW(filename.as_ptr(),
-                                          access,
-                                          libc::FILE_SHARE_READ |
-                                              libc::FILE_SHARE_WRITE,
-                                          &mut sa,
-                                          libc::OPEN_EXISTING,
-                                          0,
-                                          ptr::mut_null());
-                if *slot == INVALID_HANDLE_VALUE as libc::HANDLE {
-                    return Err(super::last_error())
-                }
-            } else {
-                let orig = get_osfhandle(fd) as HANDLE;
-                if orig == INVALID_HANDLE_VALUE as HANDLE {
-                    return Err(super::last_error())
+        let set_fd = |fd: &Option<file::FileDesc>, slot: &mut HANDLE,
+                      is_stdin: bool| {
+            match *fd {
+                None => {
+                    let access = if is_stdin {
+                        libc::FILE_GENERIC_READ
+                    } else {
+                        libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES
+                    };
+                    let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>();
+                    let mut sa = libc::SECURITY_ATTRIBUTES {
+                        nLength: size as libc::DWORD,
+                        lpSecurityDescriptor: ptr::mut_null(),
+                        bInheritHandle: 1,
+                    };
+                    let filename: Vec<u16> = "NUL".utf16_units().collect();
+                    let filename = filename.append_one(0);
+                    *slot = libc::CreateFileW(filename.as_ptr(),
+                                              access,
+                                              libc::FILE_SHARE_READ |
+                                                  libc::FILE_SHARE_WRITE,
+                                              &mut sa,
+                                              libc::OPEN_EXISTING,
+                                              0,
+                                              ptr::mut_null());
+                    if *slot == INVALID_HANDLE_VALUE as libc::HANDLE {
+                        return Err(super::last_error())
+                    }
                 }
-                if DuplicateHandle(cur_proc, orig, cur_proc, slot,
-                                   0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
-                    return Err(super::last_error())
+                Some(ref fd) => {
+                    let orig = get_osfhandle(fd.fd()) as HANDLE;
+                    if orig == INVALID_HANDLE_VALUE as HANDLE {
+                        return Err(super::last_error())
+                    }
+                    if DuplicateHandle(cur_proc, orig, cur_proc, slot,
+                                       0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+                        return Err(super::last_error())
+                    }
                 }
             }
             Ok(())
         };
 
-        try!(set_fd(in_fd, &mut si.hStdInput, true));
-        try!(set_fd(out_fd, &mut si.hStdOutput, false));
-        try!(set_fd(err_fd, &mut si.hStdError, false));
+        try!(set_fd(&in_fd, &mut si.hStdInput, true));
+        try!(set_fd(&out_fd, &mut si.hStdOutput, false));
+        try!(set_fd(&err_fd, &mut si.hStdError, false));
 
-        let cmd_str = make_command_line(cfg.program, cfg.args);
+        let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program),
+                                        cfg.args);
         let mut pi = zeroed_process_information();
         let mut create_err = None;
 
@@ -337,7 +394,8 @@ fn spawn_process_os(cfg: ProcessConfig,
 
         with_envp(cfg.env, |envp| {
             with_dirp(cfg.cwd, |dirp| {
-                let mut cmd_str = cmd_str.to_utf16().append_one(0);
+                let mut cmd_str: Vec<u16> = cmd_str.as_slice().utf16_units().collect();
+                cmd_str = cmd_str.append_one(0);
                 let created = CreateProcessW(ptr::null(),
                                              cmd_str.as_mut_ptr(),
                                              ptr::mut_null(),
@@ -369,7 +427,7 @@ fn spawn_process_os(cfg: ProcessConfig,
 
         Ok(SpawnProcessResult {
             pid: pi.dwProcessId as pid_t,
-            handle: pi.hProcess as *()
+            handle: pi.hProcess as *mut ()
         })
     }
 }
@@ -464,7 +522,10 @@ fn backslash_run_ends_in_quote(s: &Vec<char>, mut i: uint) -> bool {
 }
 
 #[cfg(unix)]
-fn spawn_process_os(cfg: ProcessConfig, in_fd: c_int, out_fd: c_int, err_fd: c_int)
+fn spawn_process_os(cfg: ProcessConfig,
+                    in_fd: Option<file::FileDesc>,
+                    out_fd: Option<file::FileDesc>,
+                    err_fd: Option<file::FileDesc>)
                 -> IoResult<SpawnProcessResult>
 {
     use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
@@ -478,14 +539,14 @@ mod rustrt {
     }
 
     #[cfg(target_os = "macos")]
-    unsafe fn set_environ(envp: *c_void) {
-        extern { fn _NSGetEnviron() -> *mut *c_void; }
+    unsafe fn set_environ(envp: *const c_void) {
+        extern { fn _NSGetEnviron() -> *mut *const c_void; }
 
         *_NSGetEnviron() = envp;
     }
     #[cfg(not(target_os = "macos"))]
-    unsafe fn set_environ(envp: *c_void) {
-        extern { static mut environ: *c_void; }
+    unsafe fn set_environ(envp: *const c_void) {
+        extern { static mut environ: *const c_void; }
         environ = envp;
     }
 
@@ -494,13 +555,15 @@ unsafe fn set_cloexec(fd: c_int) {
         assert_eq!(ret, 0);
     }
 
-    let dirp = cfg.cwd.map(|c| c.with_ref(|p| p)).unwrap_or(ptr::null());
+    let dirp = cfg.cwd.map(|c| c.as_ptr()).unwrap_or(ptr::null());
+
+    let cfg = unsafe {
+        mem::transmute::<ProcessConfig,ProcessConfig<'static>>(cfg)
+    };
 
     with_envp(cfg.env, proc(envp) {
         with_argv(cfg.program, cfg.args, proc(argv) unsafe {
-            let pipe = os::pipe();
-            let mut input = file::FileDesc::new(pipe.input, true);
-            let mut output = file::FileDesc::new(pipe.out, true);
+            let (mut input, mut output) = try!(pipe());
 
             // We may use this in the child, so perform allocations before the
             // fork
@@ -510,7 +573,7 @@ unsafe fn set_cloexec(fd: c_int) {
 
             let pid = fork();
             if pid < 0 {
-                fail!("failure in fork: {}", os::last_os_error());
+                return Err(super::last_error())
             } else if pid > 0 {
                 drop(output);
                 let mut bytes = [0, ..4];
@@ -529,7 +592,7 @@ unsafe fn set_cloexec(fd: c_int) {
                     Err(..) => {
                         Ok(SpawnProcessResult {
                             pid: pid,
-                            handle: ptr::null()
+                            handle: ptr::mut_null()
                         })
                     }
                     Ok(..) => fail!("short read on the cloexec pipe"),
@@ -586,16 +649,24 @@ fn fail(output: &mut file::FileDesc) -> ! {
             // up /dev/null into that file descriptor. Otherwise, the first file
             // descriptor opened up in the child would be numbered as one of the
             // stdio file descriptors, which is likely to wreak havoc.
-            let setup = |src: c_int, dst: c_int| {
-                let src = if src == -1 {
-                    let flags = if dst == libc::STDIN_FILENO {
-                        libc::O_RDONLY
-                    } else {
-                        libc::O_RDWR
-                    };
-                    devnull.with_ref(|p| libc::open(p, flags, 0))
-                } else {
-                    src
+            let setup = |src: Option<file::FileDesc>, dst: c_int| {
+                let src = match src {
+                    None => {
+                        let flags = if dst == libc::STDIN_FILENO {
+                            libc::O_RDONLY
+                        } else {
+                            libc::O_RDWR
+                        };
+                        libc::open(devnull.as_ptr(), flags, 0)
+                    }
+                    Some(obj) => {
+                        let fd = obj.fd();
+                        // Leak the memory and the file descriptor. We're in the
+                        // child now an all our resources are going to be
+                        // cleaned up very soon
+                        mem::forget(obj);
+                        fd
+                    }
                 };
                 src != -1 && retry(|| dup2(src, dst)) != -1
             };
@@ -621,17 +692,18 @@ fn fail(output: &mut file::FileDesc) -> ! {
             }
             match cfg.uid {
                 Some(u) => {
-                    // When dropping privileges from root, the `setgroups` call will
-                    // remove any extraneous groups. If we don't call this, then
-                    // even though our uid has dropped, we may still have groups
-                    // that enable us to do super-user things. This will fail if we
-                    // aren't root, so don't bother checking the return value, this
-                    // is just done as an optimistic privilege dropping function.
+                    // When dropping privileges from root, the `setgroups` call
+                    // will remove any extraneous groups. If we don't call this,
+                    // then even though our uid has dropped, we may still have
+                    // groups that enable us to do super-user things. This will
+                    // fail if we aren't root, so don't bother checking the
+                    // return value, this is just done as an optimistic
+                    // privilege dropping function.
                     extern {
                         fn setgroups(ngroups: libc::c_int,
-                                     ptr: *libc::c_void) -> libc::c_int;
+                                     ptr: *const libc::c_void) -> libc::c_int;
                     }
-                    let _ = setgroups(0, 0 as *libc::c_void);
+                    let _ = setgroups(0, 0 as *const libc::c_void);
 
                     if libc::setuid(u as libc::uid_t) != 0 {
                         fail(&mut output);
@@ -651,23 +723,24 @@ fn setgroups(ngroups: libc::c_int,
             if !envp.is_null() {
                 set_environ(envp);
             }
-            let _ = execvp(*argv, argv);
+            let _ = execvp(*argv, argv as *mut _);
             fail(&mut output);
         })
     })
 }
 
 #[cfg(unix)]
-fn with_argv<T>(prog: &CString, args: &[CString], cb: proc(**libc::c_char) -> T) -> T {
-    let mut ptrs: Vec<*libc::c_char> = Vec::with_capacity(args.len()+1);
+fn with_argv<T>(prog: &CString, args: &[CString],
+                cb: proc(*const *const libc::c_char) -> T) -> T {
+    let mut ptrs: Vec<*const libc::c_char> = Vec::with_capacity(args.len()+1);
 
     // Convert the CStrings into an array of pointers. Note: the
     // lifetime of the various CStrings involved is guaranteed to be
     // larger than the lifetime of our invocation of cb, but this is
     // technically unsafe as the callback could leak these pointers
     // out of our scope.
-    ptrs.push(prog.with_ref(|buf| buf));
-    ptrs.extend(args.iter().map(|tmp| tmp.with_ref(|buf| buf)));
+    ptrs.push(prog.as_ptr());
+    ptrs.extend(args.iter().map(|tmp| tmp.as_ptr()));
 
     // Add a terminating null pointer (required by libc).
     ptrs.push(ptr::null());
@@ -676,7 +749,8 @@ fn with_argv<T>(prog: &CString, args: &[CString], cb: proc(**libc::c_char) -> T)
 }
 
 #[cfg(unix)]
-fn with_envp<T>(env: Option<&[(CString, CString)]>, cb: proc(*c_void) -> T) -> T {
+fn with_envp<T>(env: Option<&[(&CString, &CString)]>,
+                cb: proc(*const c_void) -> T) -> T {
     // On posixy systems we can pass a char** for envp, which is a
     // null-terminated array of "k=v\0" strings. Since we must create
     // these strings locally, yet expose a raw pointer to them, we
@@ -695,20 +769,20 @@ fn with_envp<T>(env: Option<&[(CString, CString)]>, cb: proc(*c_void) -> T) -> T
             }
 
             // As with `with_argv`, this is unsafe, since cb could leak the pointers.
-            let mut ptrs: Vec<*libc::c_char> =
+            let mut ptrs: Vec<*const libc::c_char> =
                 tmps.iter()
-                    .map(|tmp| tmp.as_ptr() as *libc::c_char)
+                    .map(|tmp| tmp.as_ptr() as *const libc::c_char)
                     .collect();
             ptrs.push(ptr::null());
 
-            cb(ptrs.as_ptr() as *c_void)
+            cb(ptrs.as_ptr() as *const c_void)
         }
         _ => cb(ptr::null())
     }
 }
 
 #[cfg(windows)]
-fn with_envp<T>(env: Option<&[(CString, CString)]>, cb: |*mut c_void| -> T) -> T {
+fn with_envp<T>(env: Option<&[(&CString, &CString)]>, cb: |*mut c_void| -> T) -> T {
     // On win32 we pass an "environment block" which is not a char**, but
     // rather a concatenation of null-terminated k=v\0 sequences, with a final
     // \0 to terminate.
@@ -720,7 +794,7 @@ fn with_envp<T>(env: Option<&[(CString, CString)]>, cb: |*mut c_void| -> T) -> T
                 let kv = format!("{}={}",
                                  pair.ref0().as_str().unwrap(),
                                  pair.ref1().as_str().unwrap());
-                blk.push_all(kv.to_utf16().as_slice());
+                blk.extend(kv.as_slice().utf16_units());
                 blk.push(0);
             }
 
@@ -733,12 +807,14 @@ fn with_envp<T>(env: Option<&[(CString, CString)]>, cb: |*mut c_void| -> T) -> T
 }
 
 #[cfg(windows)]
-fn with_dirp<T>(d: Option<&CString>, cb: |*u16| -> T) -> T {
+fn with_dirp<T>(d: Option<&CString>, cb: |*const u16| -> T) -> T {
     match d {
       Some(dir) => {
           let dir_str = dir.as_str()
                            .expect("expected workingdirectory to be utf-8 encoded");
-          let dir_str = dir_str.to_utf16().append_one(0);
+          let dir_str: Vec<u16> = dir_str.utf16_units().collect();
+          let dir_str = dir_str.append_one(0);
+
           cb(dir_str.as_ptr())
       },
       None => cb(ptr::null())
@@ -746,14 +822,14 @@ fn with_dirp<T>(d: Option<&CString>, cb: |*u16| -> T) -> T {
 }
 
 #[cfg(windows)]
-fn free_handle(handle: *()) {
+fn free_handle(handle: *mut ()) {
     assert!(unsafe {
         libc::CloseHandle(mem::transmute(handle)) != 0
     })
 }
 
 #[cfg(unix)]
-fn free_handle(_handle: *()) {
+fn free_handle(_handle: *mut ()) {
     // unix has no process handle object, just a pid
 }
 
@@ -769,7 +845,9 @@ pub fn WTERMSIG(status: i32) -> i32 { status & 0x7f }
     }
 
     #[cfg(target_os = "macos")]
+    #[cfg(target_os = "ios")]
     #[cfg(target_os = "freebsd")]
+    #[cfg(target_os = "dragonfly")]
     mod imp {
         pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 }
         pub fn WEXITSTATUS(status: i32) -> i32 { status >> 8 }
@@ -966,15 +1044,16 @@ fn waitpid_helper(input: libc::c_int,
                     let now = ::io::timer::now();
                     let ms = if now < deadline {deadline - now} else {0};
                     tv = util::ms_to_timeval(ms);
-                    (&tv as *_, idx)
+                    (&mut tv as *mut _, idx)
                 }
-                None => (ptr::null(), -1),
+                None => (ptr::mut_null(), -1),
             };
 
             // Wait for something to happen
             c::fd_set(&mut set, input);
             c::fd_set(&mut set, read_fd);
-            match unsafe { c::select(max, &set, ptr::null(), ptr::null(), p) } {
+            match unsafe { c::select(max, &mut set, ptr::mut_null(),
+                                     ptr::mut_null(), p) } {
                 // interrupted, retry
                 -1 if os::errno() == libc::EINTR as int => continue,
 
@@ -1084,9 +1163,9 @@ fn drain(fd: libc::c_int) -> bool {
     // which will wake up the other end at some point, so we just allow this
     // signal to be coalesced with the pending signals on the pipe.
     extern fn sigchld_handler(_signum: libc::c_int) {
-        let mut msg = 1;
+        let msg = 1i;
         match unsafe {
-            libc::write(WRITE_FD, &mut msg as *mut _ as *libc::c_void, 1)
+            libc::write(WRITE_FD, &msg as *const _ as *const libc::c_void, 1)
         } {
             1 => {}
             -1 if util::wouldblock() => {} // see above comments