(index<- ) ./libnative/io/mod.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
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::process::ProcessConfig;
31 use std::io::signal::Signum;
32 use std::os;
33 use std::rt::rtio;
34 use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket};
35 use std::rt::rtio::{RtioUnixListener, RtioPipe, RtioFileStream, RtioProcess};
36 use std::rt::rtio::{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<Box<RtioTcpStream:Send>> {
170 net::TcpStream::connect(addr, timeout).map(|s| {
171 box s as Box<RtioTcpStream:Send>
172 })
173 }
174 fn tcp_bind(&mut self, addr: SocketAddr)
175 -> IoResult<Box<RtioTcpListener:Send>> {
176 net::TcpListener::bind(addr).map(|s| {
177 box s as Box<RtioTcpListener:Send>
178 })
179 }
180 fn udp_bind(&mut self, addr: SocketAddr)
181 -> IoResult<Box<RtioUdpSocket:Send>> {
182 net::UdpSocket::bind(addr).map(|u| box u as Box<RtioUdpSocket:Send>)
183 }
184 fn unix_bind(&mut self, path: &CString)
185 -> IoResult<Box<RtioUnixListener:Send>> {
186 pipe::UnixListener::bind(path).map(|s| {
187 box s as Box<RtioUnixListener:Send>
188 })
189 }
190 fn unix_connect(&mut self, path: &CString,
191 timeout: Option<u64>) -> IoResult<Box<RtioPipe:Send>> {
192 pipe::UnixStream::connect(path, timeout).map(|s| {
193 box s as Box<RtioPipe:Send>
194 })
195 }
196 fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
197 hint: Option<ai::Hint>) -> IoResult<Vec<ai::Info>> {
198 addrinfo::GetAddrInfoRequest::run(host, servname, hint)
199 }
200
201 // filesystem operations
202 fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior)
203 -> Box<RtioFileStream:Send> {
204 let close = match close {
205 rtio::CloseSynchronously | rtio::CloseAsynchronously => true,
206 rtio::DontClose => false
207 };
208 box file::FileDesc::new(fd, close) as Box<RtioFileStream:Send>
209 }
210 fn fs_open(&mut self, path: &CString, fm: io::FileMode, fa: io::FileAccess)
211 -> IoResult<Box<RtioFileStream:Send>> {
212 file::open(path, fm, fa).map(|fd| box fd as Box<RtioFileStream:Send>)
213 }
214 fn fs_unlink(&mut self, path: &CString) -> IoResult<()> {
215 file::unlink(path)
216 }
217 fn fs_stat(&mut self, path: &CString) -> IoResult<io::FileStat> {
218 file::stat(path)
219 }
220 fn fs_mkdir(&mut self, path: &CString,
221 mode: io::FilePermission) -> IoResult<()> {
222 file::mkdir(path, mode)
223 }
224 fn fs_chmod(&mut self, path: &CString,
225 mode: io::FilePermission) -> IoResult<()> {
226 file::chmod(path, mode)
227 }
228 fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> {
229 file::rmdir(path)
230 }
231 fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> {
232 file::rename(path, to)
233 }
234 fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult<Vec<Path>> {
235 file::readdir(path)
236 }
237 fn fs_lstat(&mut self, path: &CString) -> IoResult<io::FileStat> {
238 file::lstat(path)
239 }
240 fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> {
241 file::chown(path, uid, gid)
242 }
243 fn fs_readlink(&mut self, path: &CString) -> IoResult<Path> {
244 file::readlink(path)
245 }
246 fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
247 file::symlink(src, dst)
248 }
249 fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
250 file::link(src, dst)
251 }
252 fn fs_utime(&mut self, src: &CString, atime: u64,
253 mtime: u64) -> IoResult<()> {
254 file::utime(src, atime, mtime)
255 }
256
257 // misc
258 fn timer_init(&mut self) -> IoResult<Box<RtioTimer:Send>> {
259 timer::Timer::new().map(|t| box t as Box<RtioTimer:Send>)
260 }
261 fn spawn(&mut self, config: ProcessConfig)
262 -> IoResult<(Box<RtioProcess:Send>,
263 Vec<Option<Box<RtioPipe:Send>>>)> {
264 process::Process::spawn(config).map(|(p, io)| {
265 (box p as Box<RtioProcess:Send>,
266 io.move_iter().map(|p| p.map(|p| {
267 box p as Box<RtioPipe:Send>
268 })).collect())
269 })
270 }
271 fn kill(&mut self, pid: libc::pid_t, signum: int) -> IoResult<()> {
272 process::Process::kill(pid, signum)
273 }
274 fn pipe_open(&mut self, fd: c_int) -> IoResult<Box<RtioPipe:Send>> {
275 Ok(box file::FileDesc::new(fd, true) as Box<RtioPipe:Send>)
276 }
277 fn tty_open(&mut self, fd: c_int, _readable: bool)
278 -> IoResult<Box<RtioTTY:Send>> {
279 if unsafe { libc::isatty(fd) } != 0 {
280 Ok(box file::FileDesc::new(fd, true) as Box<RtioTTY:Send>)
281 } else {
282 Err(IoError {
283 kind: io::MismatchedFileTypeForOperation,
284 desc: "file descriptor is not a TTY",
285 detail: None,
286 })
287 }
288 }
289 fn signal(&mut self, _signal: Signum, _channel: Sender<Signum>)
290 -> IoResult<Box<RtioSignal:Send>> {
291 Err(unimpl())
292 }
293 }
libnative/io/mod.rs:154:30-154:30 -struct- definition:
/// native I/O functionality.
pub struct IoFactory {
cannot_construct_outside_of_this_module: ()
references:- 5166: impl rtio::IoFactory for IoFactory {
167: // networking
libnative/task.rs:
112: awoken: bool, // used to prevent spurious wakeups
113: io: io::IoFactory, // local I/O factory
libnative/io/mod.rs:
161: net::init();
162: IoFactory { cannot_construct_outside_of_this_module: () }
163: }
libnative/io/mod.rs:134:1-134:1 -fn- definition:
fn keep_going(data: &[u8], f: |*u8, uint| -> i64) -> i64 {
let origamt = data.len();
let mut data = data.as_ptr();
references:- 4libnative/io/net.rs:
845: if write_everything {
846: ret = keep_going(buf, |inner, len| {
847: written = buf.len() - len;
libnative/io/file_unix.rs:
270: fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
271: let ret = keep_going(buf, |buf, len| {
272: unsafe {
libnative/io/mod.rs:89:1-89:1 -fn- definition:
fn last_error() -> IoError {
IoError::last_error()
}
references:- 2796: if ret != 0 {
97: Err(last_error())
98: } else {
libnative/io/net.rs:
144: fn last_error() -> io::IoError {
145: super::last_error()
146: }
libnative/io/process.rs:
835: 0 => None,
836: n => fail!("unknown waitpid error `{}`: {}", n, super::last_error()),
837: }
libnative/io/util.rs:
109: -1 => Err(last_error()),
110: _ => Ok(()),
libnative/io/file_unix.rs:
113: }) {
114: -1 => Err(super::last_error()),
115: n => Ok(n as int)
--
344: match retry(|| unsafe { libc::open(path.with_ref(|p| p), flags, mode) }) {
345: -1 => Err(super::last_error()),
346: fd => Ok(FileDesc::new(fd, true)),
--
392: } else {
393: Err(super::last_error())
394: }
--
519: 0 => Ok(mkstat(&stat, p)),
520: _ => Err(super::last_error()),
521: }
libnative/io/pipe_unix.rs:
83: match retry(|| unsafe { libc::connect(inner.fd, addrp, len) }) {
84: -1 => Err(super::last_error()),
85: _ => Ok(inner)
--
221: match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } {
222: -1 => Err(super::last_error()),
223: _ => Ok(UnixAcceptor { listener: self, deadline: 0 })
--
256: }) {
257: -1 => Err(super::last_error()),
258: fd => Ok(UnixStream::new(UnsafeArc::new(Inner::new(fd))))
libnative/io/util.rs:
163: }) {
164: -1 => Err(last_error()),
165: 0 => Err(timeout("timed out")),
libnative/io/mod.rs:79:1-79:1 -NK_AS_STR_TODO- definition:
pub type IoResult<T> = Result<T, IoError>;
fn unimpl() -> IoError {
IoError {
references:- 103libnative/io/net.rs:
libnative/io/process.rs:
libnative/io/file_unix.rs:
libnative/io/timer_unix.rs:
libnative/io/pipe_unix.rs:
libnative/io/net.rs:
libnative/io/mod.rs:81:1-81:1 -fn- definition:
fn unimpl() -> IoError {
IoError {
kind: io::IoUnavailable,
references:- 4290: -> IoResult<Box<RtioSignal:Send>> {
291: Err(unimpl())
292: }
libnative/io/process.rs:
73: if config.extra_io.len() > 0 {
74: return Err(super::unimpl());
75: }
libnative/io/file_unix.rs:
204: fn set_raw(&mut self, _raw: bool) -> Result<(), IoError> {
205: Err(super::unimpl())
206: }
207: fn get_winsize(&mut self) -> Result<(int, int), IoError> {
208: Err(super::unimpl())
209: }
libnative/io/mod.rs:94:37-94:37 -fn- definition:
// unix has nonzero values as errors
fn mkerr_libc(ret: libc::c_int) -> IoResult<()> {
if ret != 0 {
references:- 20libnative/io/net.rs:
396: fn close_write(&mut self) -> IoResult<()> {
397: super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) })
398: }
399: fn close_read(&mut self) -> IoResult<()> {
400: super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) })
401: }
libnative/io/process.rs:
235: let r = libc::funcs::posix88::signal::kill(pid, signal as c_int);
236: super::mkerr_libc(r)
237: }
libnative/io/util.rs:
57: let set = nb as libc::c_int;
58: super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
59: }
libnative/io/file_unix.rs:
164: fn truncate(&mut self, offset: i64) -> Result<(), IoError> {
165: super::mkerr_libc(retry(|| unsafe {
166: libc::ftruncate(self.fd(), offset as libc::off_t)
--
413: pub fn rmdir(p: &CString) -> IoResult<()> {
414: super::mkerr_libc(retry(|| unsafe {
415: libc::rmdir(p.with_ref(|p| p))
--
419: pub fn chown(p: &CString, uid: int, gid: int) -> IoResult<()> {
420: super::mkerr_libc(retry(|| unsafe {
421: libc::chown(p.with_ref(|p| p), uid as libc::uid_t,
--
528: };
529: super::mkerr_libc(retry(|| unsafe {
530: libc::utime(p.with_ref(|p| p), &buf)
libnative/io/pipe_unix.rs:
183: fn close_write(&mut self) -> IoResult<()> {
184: super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) })
185: }
186: fn close_read(&mut self) -> IoResult<()> {
187: super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) })
188: }
libnative/io/file_unix.rs:
452: pub fn link(src: &CString, dst: &CString) -> IoResult<()> {
453: super::mkerr_libc(retry(|| unsafe {
454: libc::link(src.with_ref(|p| p), dst.with_ref(|p| p))
libnative/io/mod.rs:125:10-125:10 -fn- definition:
fn retry(f: || -> libc::c_int) -> libc::c_int {
loop {
match f() {
references:- 37libnative/io/net.rs:
libnative/io/process.rs:
libnative/io/util.rs:
libnative/io/file_unix.rs:
libnative/io/pipe_unix.rs:
libnative/io/process.rs: