]> git.lizzy.rs Git - rust.git/commitdiff
std: Expose that LocalIo may not always be available
authorAlex Crichton <alex@alexcrichton.com>
Fri, 13 Dec 2013 01:30:41 +0000 (17:30 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 24 Dec 2013 22:42:00 +0000 (14:42 -0800)
It is not the case that all programs will always be able to acquire an instance
of the LocalIo borrow, so this commit exposes this limitation by returning
Option<LocalIo> from LocalIo::borrow().

At the same time, a helper method LocalIo::maybe_raise() has been added in order
to encapsulate the functionality of raising on io_error if there is on local I/O
available.

src/libstd/io/fs.rs
src/libstd/io/net/addrinfo.rs
src/libstd/io/net/tcp.rs
src/libstd/io/net/udp.rs
src/libstd/io/net/unix.rs
src/libstd/io/pipe.rs
src/libstd/io/process.rs
src/libstd/io/signal.rs
src/libstd/io/stdio.rs
src/libstd/io/timer.rs
src/libstd/rt/rtio.rs

index a1465ca7b33a0068c67dc233570cf3f8ed5eb885..ded1d254f3f5a746c5cf8c7ef15f6895daf8456b 100644 (file)
@@ -54,7 +54,7 @@
 use rt::rtio::{RtioFileStream, IoFactory, LocalIo};
 use io;
 use option::{Some, None, Option};
-use result::{Ok, Err, Result};
+use result::{Ok, Err};
 use path;
 use path::{Path, GenericPath};
 use vec::{OwnedVector, ImmutableVector};
@@ -75,17 +75,6 @@ pub struct File {
     priv last_nread: int,
 }
 
-fn io_raise<T>(f: |io: &mut IoFactory| -> Result<T, IoError>) -> Option<T> {
-    let mut io = LocalIo::borrow();
-    match f(io.get()) {
-        Ok(t) => Some(t),
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
-            None
-        }
-    }
-}
-
 impl File {
     /// Open a file at `path` in the mode specified by the `mode` and `access`
     /// arguments
@@ -131,18 +120,15 @@ impl File {
     pub fn open_mode(path: &Path,
                      mode: FileMode,
                      access: FileAccess) -> Option<File> {
-        let mut io = LocalIo::borrow();
-        match io.get().fs_open(&path.to_c_str(), mode, access) {
-            Ok(fd) => Some(File {
-                path: path.clone(),
-                fd: fd,
-                last_nread: -1
-            }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+        LocalIo::maybe_raise(|io| {
+            io.fs_open(&path.to_c_str(), mode, access).map(|fd| {
+                File {
+                    path: path.clone(),
+                    fd: fd,
+                    last_nread: -1
+                }
+            })
+        })
     }
 
     /// Attempts to open a file in read-only mode. This function is equivalent to
@@ -242,7 +228,7 @@ pub fn truncate(&mut self, size: i64) {
 /// directory, the user lacks permissions to remove the file, or if some
 /// other filesystem-level error occurs.
 pub fn unlink(path: &Path) {
-    io_raise(|io| io.fs_unlink(&path.to_c_str()));
+    LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str()));
 }
 
 /// Given a path, query the file system to get information about a file,
@@ -270,7 +256,9 @@ pub fn unlink(path: &Path) {
 /// requisite permissions to perform a `stat` call on the given path or if
 /// there is no entry in the filesystem at the provided path.
 pub fn stat(path: &Path) -> FileStat {
-    io_raise(|io| io.fs_stat(&path.to_c_str())).unwrap_or_else(dummystat)
+    LocalIo::maybe_raise(|io| {
+        io.fs_stat(&path.to_c_str())
+    }).unwrap_or_else(dummystat)
 }
 
 fn dummystat() -> FileStat {
@@ -306,7 +294,9 @@ fn dummystat() -> FileStat {
 ///
 /// See `stat`
 pub fn lstat(path: &Path) -> FileStat {
-    io_raise(|io| io.fs_lstat(&path.to_c_str())).unwrap_or_else(dummystat)
+    LocalIo::maybe_raise(|io| {
+        io.fs_lstat(&path.to_c_str())
+    }).unwrap_or_else(dummystat)
 }
 
 /// Rename a file or directory to a new name.
@@ -324,7 +314,7 @@ pub fn lstat(path: &Path) -> FileStat {
 /// the process lacks permissions to view the contents, or if some other
 /// intermittent I/O error occurs.
 pub fn rename(from: &Path, to: &Path) {
-    io_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str()));
+    LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str()));
 }
 
 /// Copies the contents of one file to another. This function will also
@@ -395,7 +385,7 @@ pub fn copy(from: &Path, to: &Path) {
 /// condition. Some possible error situations are not having the permission to
 /// change the attributes of a file or the file not existing.
 pub fn chmod(path: &Path, mode: io::FilePermission) {
-    io_raise(|io| io.fs_chmod(&path.to_c_str(), mode));
+    LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode));
 }
 
 /// Change the user and group owners of a file at the specified path.
@@ -404,7 +394,7 @@ pub fn chmod(path: &Path, mode: io::FilePermission) {
 ///
 /// This function will raise on the `io_error` condition on failure.
 pub fn chown(path: &Path, uid: int, gid: int) {
-    io_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid));
+    LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid));
 }
 
 /// Creates a new hard link on the filesystem. The `dst` path will be a
@@ -415,7 +405,7 @@ pub fn chown(path: &Path, uid: int, gid: int) {
 ///
 /// This function will raise on the `io_error` condition on failure.
 pub fn link(src: &Path, dst: &Path) {
-    io_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str()));
+    LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str()));
 }
 
 /// Creates a new symbolic link on the filesystem. The `dst` path will be a
@@ -425,7 +415,7 @@ pub fn link(src: &Path, dst: &Path) {
 ///
 /// This function will raise on the `io_error` condition on failure.
 pub fn symlink(src: &Path, dst: &Path) {
-    io_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str()));
+    LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str()));
 }
 
 /// Reads a symlink, returning the file that the symlink points to.
@@ -436,7 +426,7 @@ pub fn symlink(src: &Path, dst: &Path) {
 /// conditions include reading a file that does not exist or reading a file
 /// which is not a symlink.
 pub fn readlink(path: &Path) -> Option<Path> {
-    io_raise(|io| io.fs_readlink(&path.to_c_str()))
+    LocalIo::maybe_raise(|io| io.fs_readlink(&path.to_c_str()))
 }
 
 /// Create a new, empty directory at the provided path
@@ -456,7 +446,7 @@ pub fn readlink(path: &Path) -> Option<Path> {
 /// to make a new directory at the provided path, or if the directory already
 /// exists.
 pub fn mkdir(path: &Path, mode: FilePermission) {
-    io_raise(|io| io.fs_mkdir(&path.to_c_str(), mode));
+    LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode));
 }
 
 /// Remove an existing, empty directory
@@ -475,7 +465,7 @@ pub fn mkdir(path: &Path, mode: FilePermission) {
 /// to remove the directory at the provided path, or if the directory isn't
 /// empty.
 pub fn rmdir(path: &Path) {
-    io_raise(|io| io.fs_rmdir(&path.to_c_str()));
+    LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str()));
 }
 
 /// Retrieve a vector containing all entries within a provided directory
@@ -502,7 +492,9 @@ pub fn rmdir(path: &Path) {
 /// the process lacks permissions to view the contents or if the `path` points
 /// at a non-directory file
 pub fn readdir(path: &Path) -> ~[Path] {
-    io_raise(|io| io.fs_readdir(&path.to_c_str(), 0)).unwrap_or_else(|| ~[])
+    LocalIo::maybe_raise(|io| {
+        io.fs_readdir(&path.to_c_str(), 0)
+    }).unwrap_or_else(|| ~[])
 }
 
 /// Returns an iterator which will recursively walk the directory structure
@@ -583,7 +575,7 @@ pub fn rmdir_recursive(path: &Path) {
 /// happens.
 // FIXME(#10301) these arguments should not be u64
 pub fn change_file_times(path: &Path, atime: u64, mtime: u64) {
-    io_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime));
+    LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime));
 }
 
 impl Reader for File {
index 7df4fdd22667647b671c7e141cfa4b7eba34dedc..6d968de209ca85f07f3a128bfd8b27b7b6eeec4b 100644 (file)
@@ -18,8 +18,6 @@
 */
 
 use option::{Option, Some, None};
-use result::{Ok, Err};
-use io::{io_error};
 use io::net::ip::{SocketAddr, IpAddr};
 use rt::rtio::{IoFactory, LocalIo};
 use vec::ImmutableVector;
@@ -97,14 +95,7 @@ pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
 ///      consumption just yet.
 fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option<Hint>)
           -> Option<~[Info]> {
-    let mut io = LocalIo::borrow();
-    match io.get().get_host_addresses(hostname, servname, hint) {
-        Ok(i) => Some(i),
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
-            None
-        }
-    }
+    LocalIo::maybe_raise(|io| io.get_host_addresses(hostname, servname, hint))
 }
 
 #[cfg(test)]
index db51653d665c9e1d3cdae62e494c379769731190..bd7d8bacb386d8f98cc1a41d74598a7b03775c65 100644 (file)
@@ -26,17 +26,9 @@ fn new(s: ~RtioTcpStream) -> TcpStream {
     }
 
     pub fn connect(addr: SocketAddr) -> Option<TcpStream> {
-        let result = {
-            let mut io = LocalIo::borrow();
-            io.get().tcp_connect(addr)
-        };
-        match result {
-            Ok(s) => Some(TcpStream::new(s)),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+        LocalIo::maybe_raise(|io| {
+            io.tcp_connect(addr).map(TcpStream::new)
+        })
     }
 
     pub fn peer_name(&mut self) -> Option<SocketAddr> {
@@ -94,14 +86,9 @@ pub struct TcpListener {
 
 impl TcpListener {
     pub fn bind(addr: SocketAddr) -> Option<TcpListener> {
-        let mut io = LocalIo::borrow();
-        match io.get().tcp_bind(addr) {
-            Ok(l) => Some(TcpListener { obj: l }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+        LocalIo::maybe_raise(|io| {
+            io.tcp_bind(addr).map(|l| TcpListener { obj: l })
+        })
     }
 
     pub fn socket_name(&mut self) -> Option<SocketAddr> {
index 0a277ee4347b3c2d172719c58acb5ef22cd5463b..159823ba2b533b86e8bfa06eea6c3c86c018b00d 100644 (file)
@@ -21,14 +21,9 @@ pub struct UdpSocket {
 
 impl UdpSocket {
     pub fn bind(addr: SocketAddr) -> Option<UdpSocket> {
-        let mut io = LocalIo::borrow();
-        match io.get().udp_bind(addr) {
-            Ok(s) => Some(UdpSocket { obj: s }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+        LocalIo::maybe_raise(|io| {
+            io.udp_bind(addr).map(|s| UdpSocket { obj: s })
+        })
     }
 
     pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, SocketAddr)> {
index d8abd1fe50d7c2f8892d4d1e9c99c5912cb036ca..8fd256a22f982f1576b145822ada3a3572195491 100644 (file)
@@ -59,14 +59,9 @@ fn new(obj: ~RtioPipe) -> UnixStream {
     ///     stream.write([1, 2, 3]);
     ///
     pub fn connect<P: ToCStr>(path: &P) -> Option<UnixStream> {
-        let mut io = LocalIo::borrow();
-        match io.get().unix_connect(&path.to_c_str()) {
-            Ok(s) => Some(UnixStream::new(s)),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+        LocalIo::maybe_raise(|io| {
+            io.unix_connect(&path.to_c_str()).map(UnixStream::new)
+        })
     }
 }
 
@@ -107,14 +102,9 @@ impl UnixListener {
     ///     }
     ///
     pub fn bind<P: ToCStr>(path: &P) -> Option<UnixListener> {
-        let mut io = LocalIo::borrow();
-        match io.get().unix_bind(&path.to_c_str()) {
-            Ok(s) => Some(UnixListener{ obj: s }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+        LocalIo::maybe_raise(|io| {
+            io.unix_bind(&path.to_c_str()).map(|s| UnixListener { obj: s })
+        })
     }
 }
 
index 252575ee4454f59e760e776c943994c5a5f0a2ab..2349c64a84b272e791849b46dd384d4d4069a795 100644 (file)
 //! enough so that pipes can be created to child processes.
 
 use prelude::*;
-use super::{Reader, Writer};
 use io::{io_error, EndOfFile};
-use io::native::file;
-use rt::rtio::{LocalIo, RtioPipe};
+use libc;
+use rt::rtio::{RtioPipe, LocalIo};
 
 pub struct PipeStream {
     priv obj: ~RtioPipe,
@@ -43,15 +42,10 @@ impl PipeStream {
     ///
     /// If the pipe cannot be created, an error will be raised on the
     /// `io_error` condition.
-    pub fn open(fd: file::fd_t) -> Option<PipeStream> {
-        let mut io = LocalIo::borrow();
-        match io.get().pipe_open(fd) {
-            Ok(obj) => Some(PipeStream { obj: obj }),
-            Err(e) => {
-                io_error::cond.raise(e);
-                None
-            }
-        }
+    pub fn open(fd: libc::c_int) -> Option<PipeStream> {
+        LocalIo::maybe_raise(|io| {
+            io.pipe_open(fd).map(|obj| PipeStream { obj: obj })
+        })
     }
 
     pub fn new(inner: ~RtioPipe) -> PipeStream {
index 001faa1ecaf7b668ae8f5956e2de843fea8732dd..bbb2a7ef3984df2fec2406cc4b9738659e4dfcde 100644 (file)
@@ -119,19 +119,17 @@ impl Process {
     /// Creates a new pipe initialized, but not bound to any particular
     /// source/destination
     pub fn new(config: ProcessConfig) -> Option<Process> {
-        let mut io = LocalIo::borrow();
-        match io.get().spawn(config) {
-            Ok((p, io)) => Some(Process{
-                handle: p,
-                io: io.move_iter().map(|p|
-                    p.map(|p| io::PipeStream::new(p))
-                ).collect()
-            }),
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+        let mut config = Some(config);
+        LocalIo::maybe_raise(|io| {
+            io.spawn(config.take_unwrap()).map(|(p, io)| {
+                Process {
+                    handle: p,
+                    io: io.move_iter().map(|p| {
+                        p.map(|p| io::PipeStream::new(p))
+                    }).collect()
+                }
+            })
+        })
     }
 
     /// Returns the process id of this child process
index 00d84e22c25b21942872d63929a368ebb550631d..4cde35796a642e8abb821718e6a0bff951594d76 100644 (file)
@@ -23,8 +23,7 @@
 use comm::{Port, SharedChan};
 use container::{Map, MutableMap};
 use hashmap;
-use io::io_error;
-use result::{Err, Ok};
+use option::{Some, None};
 use rt::rtio::{IoFactory, LocalIo, RtioSignal};
 
 #[repr(int)]
@@ -122,16 +121,14 @@ pub fn register(&mut self, signum: Signum) -> bool {
         if self.handles.contains_key(&signum) {
             return true; // self is already listening to signum, so succeed
         }
-        let mut io = LocalIo::borrow();
-        match io.get().signal(signum, self.chan.clone()) {
-            Ok(w) => {
-                self.handles.insert(signum, w);
+        match LocalIo::maybe_raise(|io| {
+            io.signal(signum, self.chan.clone())
+        }) {
+            Some(handle) => {
+                self.handles.insert(signum, handle);
                 true
-            },
-            Err(ioerr) => {
-                io_error::cond.raise(ioerr);
-                false
             }
+            None => false
         }
     }
 
index 41337075aa9b96f28952e37b322464d1d5ba0980..0adb83d2015354ce84f62c8699051f9fc8539a6c 100644 (file)
 */
 
 use fmt;
+use io::buffered::LineBufferedWriter;
+use io::{Reader, Writer, io_error, IoError, OtherIoError,
+         standard_error, EndOfFile};
 use libc;
 use option::{Option, Some, None};
 use result::{Ok, Err};
-use io::buffered::LineBufferedWriter;
 use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
-use super::{Reader, Writer, io_error, IoError, OtherIoError,
-            standard_error, EndOfFile};
+use vec;
 
 // And so begins the tale of acquiring a uv handle to a stdio stream on all
 // platforms in all situations. Our story begins by splitting the world into two
@@ -69,19 +70,12 @@ enum StdSource {
 }
 
 fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
-    let mut io = LocalIo::borrow();
-    match io.get().tty_open(fd, readable) {
-        Ok(tty) => f(TTY(tty)),
-        Err(_) => {
-            // It's not really that desirable if these handles are closed
-            // synchronously, and because they're squirreled away in a task
-            // structure the destructors will be run when the task is
-            // attempted to get destroyed. This means that if we run a
-            // synchronous destructor we'll attempt to do some scheduling
-            // operations which will just result in sadness.
-            f(File(io.get().fs_from_raw_fd(fd, DontClose)))
-        }
-    }
+    LocalIo::maybe_raise(|io| {
+        Ok(match io.tty_open(fd, readable) {
+            Ok(tty) => f(TTY(tty)),
+            Err(_) => f(File(io.fs_from_raw_fd(fd, DontClose))),
+        })
+    }).unwrap()
 }
 
 /// Creates a new non-blocking handle to the stdin of the current process.
index c86e1a1890baf9d6536c4f9dc33ef7b4906ebc7f..7c9aa28bfe9a8008aa3fa6c6472248911498ddc4 100644 (file)
@@ -39,9 +39,7 @@
 */
 
 use comm::Port;
-use option::{Option, Some, None};
-use result::{Ok, Err};
-use io::io_error;
+use option::Option;
 use rt::rtio::{IoFactory, LocalIo, RtioTimer};
 
 pub struct Timer {
@@ -60,15 +58,7 @@ impl Timer {
     /// for a number of milliseconds, or to possibly create channels which will
     /// get notified after an amount of time has passed.
     pub fn new() -> Option<Timer> {
-        let mut io = LocalIo::borrow();
-        match io.get().timer_init() {
-            Ok(t) => Some(Timer { obj: t }),
-            Err(ioerr) => {
-                debug!("Timer::init: failed to init: {:?}", ioerr);
-                io_error::cond.raise(ioerr);
-                None
-            }
-        }
+        LocalIo::maybe_raise(|io| io.timer_init().map(|t| Timer { obj: t }))
     }
 
     /// Blocks the current task for `msecs` milliseconds.
index b54231421e3969be21f725ab179998cc9b2a41e3..7207c1a813435e523af24ba7ead6c3467789a005 100644 (file)
@@ -93,36 +93,50 @@ fn drop(&mut self) {
 impl<'a> LocalIo<'a> {
     /// Returns the local I/O: either the local scheduler's I/O services or
     /// the native I/O services.
-    pub fn borrow() -> LocalIo {
-        use rt::sched::Scheduler;
-        use rt::local::Local;
+    pub fn borrow() -> Option<LocalIo> {
+        // XXX: This is currently very unsafely implemented. We don't actually
+        //      *take* the local I/O so there's a very real possibility that we
+        //      can have two borrows at once. Currently there is not a clear way
+        //      to actually borrow the local I/O factory safely because even if
+        //      ownership were transferred down to the functions that the I/O
+        //      factory implements it's just too much of a pain to know when to
+        //      relinquish ownership back into the local task (but that would be
+        //      the safe way of implementing this function).
+        //
+        // In order to get around this, we just transmute a copy out of the task
+        // in order to have what is likely a static lifetime (bad).
+        let mut t: ~Task = Local::take();
+        let ret = t.local_io().map(|t| {
+            unsafe { cast::transmute_copy(&t) }
+        });
+        Local::put(t);
+        return ret;
+    }
 
-        unsafe {
-            // First, attempt to use the local scheduler's I/O services
-            let sched: Option<*mut Scheduler> = Local::try_unsafe_borrow();
-            match sched {
-                Some(sched) => {
-                    match (*sched).event_loop.io() {
-                        Some(factory) => {
-                            return LocalIo {
-                                factory: factory,
-                            }
-                        }
-                        None => {}
+    pub fn maybe_raise<T>(f: |io: &mut IoFactory| -> Result<T, IoError>)
+        -> Option<T>
+    {
+        match LocalIo::borrow() {
+            None => {
+                io::io_error::cond.raise(io::standard_error(io::IoUnavailable));
+                None
+            }
+            Some(mut io) => {
+                match f(io.get()) {
+                    Ok(t) => Some(t),
+                    Err(ioerr) => {
+                        io::io_error::cond.raise(ioerr);
+                        None
                     }
                 }
-                None => {}
-            }
-            // If we don't have a scheduler or the scheduler doesn't have I/O
-            // services, then fall back to the native I/O services.
-            let native_io: &'static mut native::IoFactory =
-                &mut NATIVE_IO_FACTORY;
-            LocalIo {
-                factory: native_io as &mut IoFactory:'static
             }
         }
     }
 
+    pub fn new<'a>(io: &'a mut IoFactory) -> LocalIo<'a> {
+        LocalIo { factory: io }
+    }
+
     /// Returns the underlying I/O factory as a trait reference.
     #[inline]
     pub fn get<'a>(&'a mut self) -> &'a mut IoFactory {