]> git.lizzy.rs Git - rust.git/blob - src/libnative/io/mod.rs
auto merge of #14563 : dotdash/rust/clone_kill, r=huonw
[rust.git] / src / libnative / io / mod.rs
1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Native thread-blocking I/O implementation
12 //!
13 //! This module contains the implementation of native thread-blocking
14 //! implementations of I/O on all platforms. This module is not intended to be
15 //! used directly, but rather the rust runtime will fall back to using it if
16 //! necessary.
17 //!
18 //! Rust code normally runs inside of green tasks with a local scheduler using
19 //! asynchronous I/O to cooperate among tasks. This model is not always
20 //! available, however, and that's where these native implementations come into
21 //! play. The only dependencies of these modules are the normal system libraries
22 //! that you would find on the respective platform.
23
24 #![allow(non_snake_case_functions)]
25
26 use libc::c_int;
27 use libc;
28 use std::c_str::CString;
29 use std::io;
30 use std::io::IoError;
31 use std::io::net::ip::SocketAddr;
32 use std::io::signal::Signum;
33 use std::os;
34 use std::rt::rtio;
35 use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket};
36 use std::rt::rtio::{RtioUnixListener, RtioPipe, RtioFileStream, RtioProcess};
37 use std::rt::rtio::{RtioSignal, RtioTTY, CloseBehavior, RtioTimer, ProcessConfig};
38 use ai = std::io::net::addrinfo;
39
40 // Local re-exports
41 pub use self::file::FileDesc;
42 pub use self::process::Process;
43
44 mod helper_thread;
45
46 // Native I/O implementations
47 pub mod addrinfo;
48 pub mod net;
49 pub mod process;
50 mod util;
51
52 #[cfg(unix)]
53 #[path = "file_unix.rs"]
54 pub mod file;
55 #[cfg(windows)]
56 #[path = "file_win32.rs"]
57 pub mod file;
58
59 #[cfg(target_os = "macos")]
60 #[cfg(target_os = "freebsd")]
61 #[cfg(target_os = "android")]
62 #[cfg(target_os = "linux")]
63 #[path = "timer_unix.rs"]
64 pub mod timer;
65
66 #[cfg(target_os = "win32")]
67 #[path = "timer_win32.rs"]
68 pub mod timer;
69
70 #[cfg(unix)]
71 #[path = "pipe_unix.rs"]
72 pub mod pipe;
73
74 #[cfg(windows)]
75 #[path = "pipe_win32.rs"]
76 pub mod pipe;
77
78 #[cfg(unix)]    #[path = "c_unix.rs"]  mod c;
79 #[cfg(windows)] #[path = "c_win32.rs"] mod c;
80
81 pub type IoResult<T> = Result<T, IoError>;
82
83 fn unimpl() -> IoError {
84     IoError {
85         kind: io::IoUnavailable,
86         desc: "unimplemented I/O interface",
87         detail: None,
88     }
89 }
90
91 fn last_error() -> IoError {
92     IoError::last_error()
93 }
94
95 // unix has nonzero values as errors
96 fn mkerr_libc(ret: libc::c_int) -> IoResult<()> {
97     if ret != 0 {
98         Err(last_error())
99     } else {
100         Ok(())
101     }
102 }
103
104 // windows has zero values as errors
105 #[cfg(windows)]
106 fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
107     if ret == 0 {
108         Err(last_error())
109     } else {
110         Ok(())
111     }
112 }
113
114 #[cfg(windows)]
115 #[inline]
116 fn retry(f: || -> libc::c_int) -> libc::c_int {
117     loop {
118         match f() {
119             -1 if os::errno() as int == libc::WSAEINTR as int => {}
120             n => return n,
121         }
122     }
123 }
124
125 #[cfg(unix)]
126 #[inline]
127 fn retry(f: || -> libc::c_int) -> libc::c_int {
128     loop {
129         match f() {
130             -1 if os::errno() as int == libc::EINTR as int => {}
131             n => return n,
132         }
133     }
134 }
135
136 fn keep_going(data: &[u8], f: |*u8, uint| -> i64) -> i64 {
137     let origamt = data.len();
138     let mut data = data.as_ptr();
139     let mut amt = origamt;
140     while amt > 0 {
141         let ret = retry(|| f(data, amt) as libc::c_int);
142         if ret == 0 {
143             break
144         } else if ret != -1 {
145             amt -= ret as uint;
146             data = unsafe { data.offset(ret as int) };
147         } else {
148             return ret as i64;
149         }
150     }
151     return (origamt - amt) as i64;
152 }
153
154 /// Implementation of rt::rtio's IoFactory trait to generate handles to the
155 /// native I/O functionality.
156 pub struct IoFactory {
157     cannot_construct_outside_of_this_module: ()
158 }
159
160 impl IoFactory {
161     pub fn new() -> IoFactory {
162         net::init();
163         IoFactory { cannot_construct_outside_of_this_module: () }
164     }
165 }
166
167 impl rtio::IoFactory for IoFactory {
168     // networking
169     fn tcp_connect(&mut self, addr: SocketAddr,
170                    timeout: Option<u64>) -> IoResult<Box<RtioTcpStream:Send>> {
171         net::TcpStream::connect(addr, timeout).map(|s| {
172             box s as Box<RtioTcpStream:Send>
173         })
174     }
175     fn tcp_bind(&mut self, addr: SocketAddr)
176                 -> IoResult<Box<RtioTcpListener:Send>> {
177         net::TcpListener::bind(addr).map(|s| {
178             box s as Box<RtioTcpListener:Send>
179         })
180     }
181     fn udp_bind(&mut self, addr: SocketAddr)
182                 -> IoResult<Box<RtioUdpSocket:Send>> {
183         net::UdpSocket::bind(addr).map(|u| box u as Box<RtioUdpSocket:Send>)
184     }
185     fn unix_bind(&mut self, path: &CString)
186                  -> IoResult<Box<RtioUnixListener:Send>> {
187         pipe::UnixListener::bind(path).map(|s| {
188             box s as Box<RtioUnixListener:Send>
189         })
190     }
191     fn unix_connect(&mut self, path: &CString,
192                     timeout: Option<u64>) -> IoResult<Box<RtioPipe:Send>> {
193         pipe::UnixStream::connect(path, timeout).map(|s| {
194             box s as Box<RtioPipe:Send>
195         })
196     }
197     fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
198                           hint: Option<ai::Hint>) -> IoResult<Vec<ai::Info>> {
199         addrinfo::GetAddrInfoRequest::run(host, servname, hint)
200     }
201
202     // filesystem operations
203     fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior)
204                       -> Box<RtioFileStream:Send> {
205         let close = match close {
206             rtio::CloseSynchronously | rtio::CloseAsynchronously => true,
207             rtio::DontClose => false
208         };
209         box file::FileDesc::new(fd, close) as Box<RtioFileStream:Send>
210     }
211     fn fs_open(&mut self, path: &CString, fm: io::FileMode, fa: io::FileAccess)
212         -> IoResult<Box<RtioFileStream:Send>> {
213         file::open(path, fm, fa).map(|fd| box fd as Box<RtioFileStream:Send>)
214     }
215     fn fs_unlink(&mut self, path: &CString) -> IoResult<()> {
216         file::unlink(path)
217     }
218     fn fs_stat(&mut self, path: &CString) -> IoResult<io::FileStat> {
219         file::stat(path)
220     }
221     fn fs_mkdir(&mut self, path: &CString,
222                 mode: io::FilePermission) -> IoResult<()> {
223         file::mkdir(path, mode)
224     }
225     fn fs_chmod(&mut self, path: &CString,
226                 mode: io::FilePermission) -> IoResult<()> {
227         file::chmod(path, mode)
228     }
229     fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> {
230         file::rmdir(path)
231     }
232     fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> {
233         file::rename(path, to)
234     }
235     fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult<Vec<Path>> {
236         file::readdir(path)
237     }
238     fn fs_lstat(&mut self, path: &CString) -> IoResult<io::FileStat> {
239         file::lstat(path)
240     }
241     fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> {
242         file::chown(path, uid, gid)
243     }
244     fn fs_readlink(&mut self, path: &CString) -> IoResult<Path> {
245         file::readlink(path)
246     }
247     fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
248         file::symlink(src, dst)
249     }
250     fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
251         file::link(src, dst)
252     }
253     fn fs_utime(&mut self, src: &CString, atime: u64,
254                 mtime: u64) -> IoResult<()> {
255         file::utime(src, atime, mtime)
256     }
257
258     // misc
259     fn timer_init(&mut self) -> IoResult<Box<RtioTimer:Send>> {
260         timer::Timer::new().map(|t| box t as Box<RtioTimer:Send>)
261     }
262     fn spawn(&mut self, cfg: ProcessConfig)
263             -> IoResult<(Box<RtioProcess:Send>,
264                          Vec<Option<Box<RtioPipe:Send>>>)> {
265         process::Process::spawn(cfg).map(|(p, io)| {
266             (box p as Box<RtioProcess:Send>,
267              io.move_iter().map(|p| p.map(|p| {
268                  box p as Box<RtioPipe:Send>
269              })).collect())
270         })
271     }
272     fn kill(&mut self, pid: libc::pid_t, signum: int) -> IoResult<()> {
273         process::Process::kill(pid, signum)
274     }
275     fn pipe_open(&mut self, fd: c_int) -> IoResult<Box<RtioPipe:Send>> {
276         Ok(box file::FileDesc::new(fd, true) as Box<RtioPipe:Send>)
277     }
278     fn tty_open(&mut self, fd: c_int, _readable: bool)
279                 -> IoResult<Box<RtioTTY:Send>> {
280         if unsafe { libc::isatty(fd) } != 0 {
281             Ok(box file::FileDesc::new(fd, true) as Box<RtioTTY:Send>)
282         } else {
283             Err(IoError {
284                 kind: io::MismatchedFileTypeForOperation,
285                 desc: "file descriptor is not a TTY",
286                 detail: None,
287             })
288         }
289     }
290     fn signal(&mut self, _signal: Signum, _channel: Sender<Signum>)
291               -> IoResult<Box<RtioSignal:Send>> {
292         Err(unimpl())
293     }
294 }