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