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