]> git.lizzy.rs Git - rust.git/blob - src/libnative/io/mod.rs
auto merge of #14715 : vhbit/rust/ios-pr2, r=alexcrichton
[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::os;
30 use std::rt::rtio;
31 use std::rt::rtio::{IoResult, IoError};
32
33 // Local re-exports
34 pub use self::file::FileDesc;
35 pub use self::process::Process;
36
37 mod helper_thread;
38
39 // Native I/O implementations
40 pub mod addrinfo;
41 pub mod net;
42 pub mod process;
43 mod util;
44
45 #[cfg(unix)]
46 #[path = "file_unix.rs"]
47 pub mod file;
48 #[cfg(windows)]
49 #[path = "file_win32.rs"]
50 pub mod file;
51
52 #[cfg(target_os = "macos")]
53 #[cfg(target_os = "ios")]
54 #[cfg(target_os = "freebsd")]
55 #[cfg(target_os = "android")]
56 #[cfg(target_os = "linux")]
57 #[path = "timer_unix.rs"]
58 pub mod timer;
59
60 #[cfg(target_os = "win32")]
61 #[path = "timer_win32.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_win32.rs"]
70 pub mod pipe;
71
72 #[cfg(unix)]    #[path = "c_unix.rs"]  mod c;
73 #[cfg(windows)] #[path = "c_win32.rs"] mod c;
74
75 fn unimpl() -> IoError {
76     #[cfg(unix)] use ERROR = libc::ENOSYS;
77     #[cfg(windows)] use ERROR = libc::ERROR_CALL_NOT_IMPLEMENTED;
78     IoError {
79         code: ERROR as uint,
80         extra: 0,
81         detail: Some("not yet supported by the `native` runtime, maybe try `green`.".to_string()),
82     }
83 }
84
85 fn last_error() -> IoError {
86     let errno = os::errno() as uint;
87     IoError {
88         code: os::errno() as uint,
89         extra: 0,
90         detail: Some(os::error_string(errno)),
91     }
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: rtio::SocketAddr,
169                    timeout: Option<u64>)
170         -> IoResult<Box<rtio::RtioTcpStream:Send>>
171     {
172         net::TcpStream::connect(addr, timeout).map(|s| {
173             box s as Box<rtio::RtioTcpStream:Send>
174         })
175     }
176     fn tcp_bind(&mut self, addr: rtio::SocketAddr)
177                 -> IoResult<Box<rtio::RtioTcpListener:Send>> {
178         net::TcpListener::bind(addr).map(|s| {
179             box s as Box<rtio::RtioTcpListener:Send>
180         })
181     }
182     fn udp_bind(&mut self, addr: rtio::SocketAddr)
183                 -> IoResult<Box<rtio::RtioUdpSocket:Send>> {
184         net::UdpSocket::bind(addr).map(|u| {
185             box u as Box<rtio::RtioUdpSocket:Send>
186         })
187     }
188     fn unix_bind(&mut self, path: &CString)
189                  -> IoResult<Box<rtio::RtioUnixListener:Send>> {
190         pipe::UnixListener::bind(path).map(|s| {
191             box s as Box<rtio::RtioUnixListener:Send>
192         })
193     }
194     fn unix_connect(&mut self, path: &CString,
195                     timeout: Option<u64>) -> IoResult<Box<rtio::RtioPipe:Send>> {
196         pipe::UnixStream::connect(path, timeout).map(|s| {
197             box s as Box<rtio::RtioPipe:Send>
198         })
199     }
200     fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
201                           hint: Option<rtio::AddrinfoHint>)
202         -> IoResult<Vec<rtio::AddrinfoInfo>>
203     {
204         addrinfo::GetAddrInfoRequest::run(host, servname, hint)
205     }
206
207     // filesystem operations
208     fn fs_from_raw_fd(&mut self, fd: c_int, close: rtio::CloseBehavior)
209                       -> Box<rtio::RtioFileStream:Send> {
210         let close = match close {
211             rtio::CloseSynchronously | rtio::CloseAsynchronously => true,
212             rtio::DontClose => false
213         };
214         box file::FileDesc::new(fd, close) as Box<rtio::RtioFileStream:Send>
215     }
216     fn fs_open(&mut self, path: &CString, fm: rtio::FileMode,
217                fa: rtio::FileAccess)
218         -> IoResult<Box<rtio::RtioFileStream:Send>>
219     {
220         file::open(path, fm, fa).map(|fd| box fd as Box<rtio::RtioFileStream:Send>)
221     }
222     fn fs_unlink(&mut self, path: &CString) -> IoResult<()> {
223         file::unlink(path)
224     }
225     fn fs_stat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
226         file::stat(path)
227     }
228     fn fs_mkdir(&mut self, path: &CString, mode: uint) -> IoResult<()> {
229         file::mkdir(path, mode)
230     }
231     fn fs_chmod(&mut self, path: &CString, mode: uint) -> IoResult<()> {
232         file::chmod(path, mode)
233     }
234     fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> {
235         file::rmdir(path)
236     }
237     fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> {
238         file::rename(path, to)
239     }
240     fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult<Vec<CString>> {
241         file::readdir(path)
242     }
243     fn fs_lstat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
244         file::lstat(path)
245     }
246     fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> {
247         file::chown(path, uid, gid)
248     }
249     fn fs_readlink(&mut self, path: &CString) -> IoResult<CString> {
250         file::readlink(path)
251     }
252     fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
253         file::symlink(src, dst)
254     }
255     fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
256         file::link(src, dst)
257     }
258     fn fs_utime(&mut self, src: &CString, atime: u64,
259                 mtime: u64) -> IoResult<()> {
260         file::utime(src, atime, mtime)
261     }
262
263     // misc
264     fn timer_init(&mut self) -> IoResult<Box<rtio::RtioTimer:Send>> {
265         timer::Timer::new().map(|t| box t as Box<rtio::RtioTimer:Send>)
266     }
267     fn spawn(&mut self, cfg: rtio::ProcessConfig)
268             -> IoResult<(Box<rtio::RtioProcess:Send>,
269                          Vec<Option<Box<rtio::RtioPipe:Send>>>)> {
270         process::Process::spawn(cfg).map(|(p, io)| {
271             (box p as Box<rtio::RtioProcess:Send>,
272              io.move_iter().map(|p| p.map(|p| {
273                  box p as Box<rtio::RtioPipe:Send>
274              })).collect())
275         })
276     }
277     fn kill(&mut self, pid: libc::pid_t, signum: int) -> IoResult<()> {
278         process::Process::kill(pid, signum)
279     }
280     fn pipe_open(&mut self, fd: c_int) -> IoResult<Box<rtio::RtioPipe:Send>> {
281         Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioPipe:Send>)
282     }
283     fn tty_open(&mut self, fd: c_int, _readable: bool)
284                 -> IoResult<Box<rtio::RtioTTY:Send>> {
285         #[cfg(unix)] use ERROR = libc::ENOTTY;
286         #[cfg(windows)] use ERROR = libc::ERROR_INVALID_HANDLE;
287         if unsafe { libc::isatty(fd) } != 0 {
288             Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioTTY:Send>)
289         } else {
290             Err(IoError {
291                 code: ERROR as uint,
292                 extra: 0,
293                 detail: None,
294             })
295         }
296     }
297     fn signal(&mut self, _signal: int, _cb: Box<rtio::Callback>)
298               -> IoResult<Box<rtio::RtioSignal:Send>> {
299         Err(unimpl())
300     }
301 }