]> git.lizzy.rs Git - rust.git/blob - src/libnative/io/mod.rs
rollup merge of #17355 : gamazeps/issue17210
[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)]
25
26 use libc::{mod, c_int};
27 use std::c_str::CString;
28 use std::os;
29 use std::rt::rtio::{mod, IoResult, IoError};
30 use std::num;
31
32 // Local re-exports
33 pub use self::file::FileDesc;
34 pub use self::process::Process;
35
36 mod helper_thread;
37
38 // Native I/O implementations
39 pub mod addrinfo;
40 pub mod net;
41 pub mod process;
42 mod util;
43
44 #[cfg(unix)]
45 #[path = "file_unix.rs"]
46 pub mod file;
47 #[cfg(windows)]
48 #[path = "file_windows.rs"]
49 pub mod file;
50
51 #[cfg(target_os = "macos")]
52 #[cfg(target_os = "ios")]
53 #[cfg(target_os = "freebsd")]
54 #[cfg(target_os = "dragonfly")]
55 #[cfg(target_os = "android")]
56 #[cfg(target_os = "linux")]
57 #[path = "timer_unix.rs"]
58 pub mod timer;
59
60 #[cfg(target_os = "windows")]
61 #[path = "timer_windows.rs"]
62 pub mod timer;
63
64 #[cfg(unix)]
65 #[path = "pipe_unix.rs"]
66 pub mod pipe;
67
68 #[cfg(windows)]
69 #[path = "pipe_windows.rs"]
70 pub mod pipe;
71
72 #[cfg(windows)]
73 #[path = "tty_windows.rs"]
74 mod tty;
75
76 #[cfg(unix)]    #[path = "c_unix.rs"]  mod c;
77 #[cfg(windows)] #[path = "c_windows.rs"] mod c;
78
79 fn unimpl() -> IoError {
80     #[cfg(unix)] use libc::ENOSYS as ERROR;
81     #[cfg(windows)] use libc::ERROR_CALL_NOT_IMPLEMENTED as ERROR;
82     IoError {
83         code: ERROR as uint,
84         extra: 0,
85         detail: Some("not yet supported by the `native` runtime, maybe try `green`.".to_string()),
86     }
87 }
88
89 fn last_error() -> IoError {
90     let errno = os::errno() as uint;
91     IoError {
92         code: os::errno() as uint,
93         extra: 0,
94         detail: Some(os::error_string(errno)),
95     }
96 }
97
98 // unix has nonzero values as errors
99 fn mkerr_libc <Int: num::Zero>(ret: Int) -> IoResult<()> {
100     if !ret.is_zero() {
101         Err(last_error())
102     } else {
103         Ok(())
104     }
105 }
106
107 // windows has zero values as errors
108 #[cfg(windows)]
109 fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
110     if ret == 0 {
111         Err(last_error())
112     } else {
113         Ok(())
114     }
115 }
116
117 #[cfg(windows)]
118 #[inline]
119 fn retry<I> (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020
120
121 #[cfg(unix)]
122 #[inline]
123 fn retry<I: PartialEq + num::One + Neg<I>> (f: || -> I) -> I {
124     let minus_one = -num::one::<I>();
125     loop {
126         let n = f();
127         if n == minus_one && os::errno() == libc::EINTR as int { }
128         else { return n }
129     }
130 }
131
132
133 fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 {
134     let origamt = data.len();
135     let mut data = data.as_ptr();
136     let mut amt = origamt;
137     while amt > 0 {
138         let ret = retry(|| f(data, amt));
139         if ret == 0 {
140             break
141         } else if ret != -1 {
142             amt -= ret as uint;
143             data = unsafe { data.offset(ret as int) };
144         } else {
145             return ret;
146         }
147     }
148     return (origamt - amt) as i64;
149 }
150
151 /// Implementation of rt::rtio's IoFactory trait to generate handles to the
152 /// native I/O functionality.
153 pub struct IoFactory {
154     _cannot_construct_outside_of_this_module: ()
155 }
156
157 impl IoFactory {
158     pub fn new() -> IoFactory {
159         net::init();
160         IoFactory { _cannot_construct_outside_of_this_module: () }
161     }
162 }
163
164 impl rtio::IoFactory for IoFactory {
165     // networking
166     fn tcp_connect(&mut self, addr: rtio::SocketAddr,
167                    timeout: Option<u64>)
168         -> IoResult<Box<rtio::RtioTcpStream + Send>>
169     {
170         net::TcpStream::connect(addr, timeout).map(|s| {
171             box s as Box<rtio::RtioTcpStream + Send>
172         })
173     }
174     fn tcp_bind(&mut self, addr: rtio::SocketAddr)
175                 -> IoResult<Box<rtio::RtioTcpListener + Send>> {
176         net::TcpListener::bind(addr).map(|s| {
177             box s as Box<rtio::RtioTcpListener + Send>
178         })
179     }
180     fn udp_bind(&mut self, addr: rtio::SocketAddr)
181                 -> IoResult<Box<rtio::RtioUdpSocket + Send>> {
182         net::UdpSocket::bind(addr).map(|u| {
183             box u as Box<rtio::RtioUdpSocket + Send>
184         })
185     }
186     fn unix_bind(&mut self, path: &CString)
187                  -> IoResult<Box<rtio::RtioUnixListener + Send>> {
188         pipe::UnixListener::bind(path).map(|s| {
189             box s as Box<rtio::RtioUnixListener + Send>
190         })
191     }
192     fn unix_connect(&mut self, path: &CString,
193                     timeout: Option<u64>) -> IoResult<Box<rtio::RtioPipe + Send>> {
194         pipe::UnixStream::connect(path, timeout).map(|s| {
195             box s as Box<rtio::RtioPipe + Send>
196         })
197     }
198     fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
199                           hint: Option<rtio::AddrinfoHint>)
200         -> IoResult<Vec<rtio::AddrinfoInfo>>
201     {
202         addrinfo::GetAddrInfoRequest::run(host, servname, hint)
203     }
204
205     // filesystem operations
206     fn fs_from_raw_fd(&mut self, fd: c_int, close: rtio::CloseBehavior)
207                       -> Box<rtio::RtioFileStream + Send> {
208         let close = match close {
209             rtio::CloseSynchronously | rtio::CloseAsynchronously => true,
210             rtio::DontClose => false
211         };
212         box file::FileDesc::new(fd, close) as Box<rtio::RtioFileStream + Send>
213     }
214     fn fs_open(&mut self, path: &CString, fm: rtio::FileMode,
215                fa: rtio::FileAccess)
216         -> IoResult<Box<rtio::RtioFileStream + Send>>
217     {
218         file::open(path, fm, fa).map(|fd| box fd as Box<rtio::RtioFileStream + Send>)
219     }
220     fn fs_unlink(&mut self, path: &CString) -> IoResult<()> {
221         file::unlink(path)
222     }
223     fn fs_stat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
224         file::stat(path)
225     }
226     fn fs_mkdir(&mut self, path: &CString, mode: uint) -> IoResult<()> {
227         file::mkdir(path, mode)
228     }
229     fn fs_chmod(&mut self, path: &CString, mode: uint) -> IoResult<()> {
230         file::chmod(path, mode)
231     }
232     fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> {
233         file::rmdir(path)
234     }
235     fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> {
236         file::rename(path, to)
237     }
238     fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult<Vec<CString>> {
239         file::readdir(path)
240     }
241     fn fs_lstat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
242         file::lstat(path)
243     }
244     fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> {
245         file::chown(path, uid, gid)
246     }
247     fn fs_readlink(&mut self, path: &CString) -> IoResult<CString> {
248         file::readlink(path)
249     }
250     fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
251         file::symlink(src, dst)
252     }
253     fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
254         file::link(src, dst)
255     }
256     fn fs_utime(&mut self, src: &CString, atime: u64,
257                 mtime: u64) -> IoResult<()> {
258         file::utime(src, atime, mtime)
259     }
260
261     // misc
262     fn timer_init(&mut self) -> IoResult<Box<rtio::RtioTimer + Send>> {
263         timer::Timer::new().map(|t| box t as Box<rtio::RtioTimer + Send>)
264     }
265     fn spawn(&mut self, cfg: rtio::ProcessConfig)
266             -> IoResult<(Box<rtio::RtioProcess + Send>,
267                          Vec<Option<Box<rtio::RtioPipe + Send>>>)> {
268         process::Process::spawn(cfg).map(|(p, io)| {
269             (box p as Box<rtio::RtioProcess + Send>,
270              io.into_iter().map(|p| p.map(|p| {
271                  box p as Box<rtio::RtioPipe + Send>
272              })).collect())
273         })
274     }
275     fn kill(&mut self, pid: libc::pid_t, signum: int) -> IoResult<()> {
276         process::Process::kill(pid, signum)
277     }
278     fn pipe_open(&mut self, fd: c_int) -> IoResult<Box<rtio::RtioPipe + Send>> {
279         Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioPipe + Send>)
280     }
281     #[cfg(unix)]
282     fn tty_open(&mut self, fd: c_int, _readable: bool)
283                 -> IoResult<Box<rtio::RtioTTY + Send>> {
284         if unsafe { libc::isatty(fd) } != 0 {
285             Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioTTY + Send>)
286         } else {
287             Err(IoError {
288                 code: libc::ENOTTY as uint,
289                 extra: 0,
290                 detail: None,
291             })
292         }
293     }
294     #[cfg(windows)]
295     fn tty_open(&mut self, fd: c_int, _readable: bool)
296                 -> IoResult<Box<rtio::RtioTTY + Send>> {
297         if tty::is_tty(fd) {
298             Ok(box tty::WindowsTTY::new(fd) as Box<rtio::RtioTTY + Send>)
299         } else {
300             Err(IoError {
301                 code: libc::ERROR_INVALID_HANDLE as uint,
302                 extra: 0,
303                 detail: None,
304             })
305         }
306     }
307     fn signal(&mut self, _signal: int, _cb: Box<rtio::Callback>)
308               -> IoResult<Box<rtio::RtioSignal + Send>> {
309         Err(unimpl())
310     }
311 }