auto merge of #5960 : brson/rust/io, r=pcwalton
r? This pull request is a grab bag of work on the new scheduler. The most important commit here is where I [outline](https://github.com/brson/rust/blob/io/src/libcore/rt/io/mod.rs) a fairly complete I/O API, based on `Reader` and `Writer` types, as in the current `core::io` module. I've organized this version into a number of modules with declarations for Files, TCP, UDP, Unix sockets, blocking/non-blocking implementations, memory buffers, compression adapters. I'm trying to get this into shape to present on the mailing list. This branch also wires up `spawn` to the new scheduler, and simplifies the core scheduler operations.
This commit is contained in:
commit
6510fd9254
25 changed files with 1905 additions and 219 deletions
59
src/libcore/rt/io/comm_adapters.rs
Normal file
59
src/libcore/rt/io/comm_adapters.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::*;
|
||||
use super::{Reader, Writer};
|
||||
|
||||
struct PortReader<P>;
|
||||
|
||||
impl<P: GenericPort<~[u8]>> PortReader<P> {
|
||||
pub fn new(_port: P) -> PortReader<P> { fail!() }
|
||||
}
|
||||
|
||||
impl<P: GenericPort<~[u8]>> Reader for PortReader<P> {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
struct ChanWriter<C>;
|
||||
|
||||
impl<C: GenericChan<~[u8]>> ChanWriter<C> {
|
||||
pub fn new(_chan: C) -> ChanWriter<C> { fail!() }
|
||||
}
|
||||
|
||||
impl<C: GenericChan<~[u8]>> Writer for ChanWriter<C> {
|
||||
pub fn write(&mut self, _buf: &[u8]) { fail!() }
|
||||
|
||||
pub fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
struct ReaderPort<R>;
|
||||
|
||||
impl<R: Reader> ReaderPort<R> {
|
||||
pub fn new(_reader: R) -> ReaderPort<R> { fail!() }
|
||||
}
|
||||
|
||||
impl<R: Reader> GenericPort<~[u8]> for ReaderPort<R> {
|
||||
fn recv(&self) -> ~[u8] { fail!() }
|
||||
|
||||
fn try_recv(&self) -> Option<~[u8]> { fail!() }
|
||||
}
|
||||
|
||||
struct WriterChan<W>;
|
||||
|
||||
impl<W: Writer> WriterChan<W> {
|
||||
pub fn new(_writer: W) -> WriterChan<W> { fail!() }
|
||||
}
|
||||
|
||||
impl<W: Writer> GenericChan<~[u8]> for WriterChan<W> {
|
||||
fn send(&self, _x: ~[u8]) { fail!() }
|
||||
}
|
||||
|
||||
|
|
@ -9,35 +9,79 @@
|
|||
// except according to those terms.
|
||||
|
||||
use prelude::*;
|
||||
use super::Stream;
|
||||
use super::misc::PathLike;
|
||||
use super::{Reader, Writer, Seek, Close};
|
||||
use super::{IoError, SeekStyle};
|
||||
|
||||
/// Open a file with the default FileMode and FileAccess
|
||||
/// # XXX are there sane defaults here?
|
||||
pub fn open_file<P: PathLike>(_path: &P) -> FileStream { fail!() }
|
||||
|
||||
/// # XXX
|
||||
/// * Ugh, this is ridiculous. What is the best way to represent these options?
|
||||
enum FileMode {
|
||||
/// Opens an existing file. IoError if file does not exist.
|
||||
Open,
|
||||
/// Creates a file. IoError if file exists.
|
||||
Create,
|
||||
/// Opens an existing file or creates a new one.
|
||||
OpenOrCreate,
|
||||
/// Opens an existing file or creates a new one, positioned at EOF.
|
||||
Append,
|
||||
/// Opens an existing file, truncating it to 0 bytes.
|
||||
Truncate,
|
||||
/// Opens an existing file or creates a new one, truncating it to 0 bytes.
|
||||
CreateOrTruncate,
|
||||
}
|
||||
|
||||
enum FileAccess {
|
||||
Read,
|
||||
Write,
|
||||
ReadWrite
|
||||
}
|
||||
|
||||
pub struct FileStream;
|
||||
|
||||
pub impl FileStream {
|
||||
fn new(_path: Path) -> FileStream {
|
||||
impl FileStream {
|
||||
pub fn open<P: PathLike>(_path: &P,
|
||||
_mode: FileMode,
|
||||
_access: FileAccess
|
||||
) -> Result<FileStream, IoError> {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Stream for FileStream {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> uint {
|
||||
impl Reader for FileStream {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> {
|
||||
fail!()
|
||||
}
|
||||
|
||||
fn eof(&mut self) -> bool {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, _v: &const [u8]) {
|
||||
fail!()
|
||||
}
|
||||
impl Writer for FileStream {
|
||||
fn write(&mut self, _v: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl Seek for FileStream {
|
||||
fn tell(&self) -> u64 { fail!() }
|
||||
|
||||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||
}
|
||||
|
||||
impl Close for FileStream {
|
||||
fn close(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn super_simple_smoke_test_lets_go_read_some_files_and_have_a_good_time() {
|
||||
let message = "it's alright. have a good time";
|
||||
let filename = Path("test.txt");
|
||||
let mut outstream = FileStream::new(filename);
|
||||
let filename = &Path("test.txt");
|
||||
let mut outstream = FileStream::open(filename, Create, Read).unwrap();
|
||||
outstream.write(message.to_bytes());
|
||||
}
|
||||
|
|
|
|||
121
src/libcore/rt/io/flate.rs
Normal file
121
src/libcore/rt/io/flate.rs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Some various other I/O types
|
||||
|
||||
// NOTE: These ultimately belong somewhere else
|
||||
|
||||
use prelude::*;
|
||||
use super::*;
|
||||
|
||||
/// A Writer decorator that compresses using the 'deflate' scheme
|
||||
pub struct DeflateWriter<W> {
|
||||
inner_writer: W
|
||||
}
|
||||
|
||||
impl<W: Writer> DeflateWriter<W> {
|
||||
pub fn new(inner_writer: W) -> DeflateWriter<W> {
|
||||
DeflateWriter {
|
||||
inner_writer: inner_writer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Writer> Writer for DeflateWriter<W> {
|
||||
fn write(&mut self, _buf: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl<W: Writer> Decorator<W> for DeflateWriter<W> {
|
||||
fn inner(self) -> W {
|
||||
match self {
|
||||
DeflateWriter { inner_writer: w } => w
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_ref<'a>(&'a self) -> &'a W {
|
||||
match *self {
|
||||
DeflateWriter { inner_writer: ref w } => w
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut W {
|
||||
match *self {
|
||||
DeflateWriter { inner_writer: ref mut w } => w
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A Reader decorator that decompresses using the 'deflate' scheme
|
||||
pub struct InflateReader<R> {
|
||||
inner_reader: R
|
||||
}
|
||||
|
||||
impl<R: Reader> InflateReader<R> {
|
||||
pub fn new(inner_reader: R) -> InflateReader<R> {
|
||||
InflateReader {
|
||||
inner_reader: inner_reader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> Reader for InflateReader<R> {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
impl<R: Reader> Decorator<R> for InflateReader<R> {
|
||||
fn inner(self) -> R {
|
||||
match self {
|
||||
InflateReader { inner_reader: r } => r
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_ref<'a>(&'a self) -> &'a R {
|
||||
match *self {
|
||||
InflateReader { inner_reader: ref r } => r
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut R {
|
||||
match *self {
|
||||
InflateReader { inner_reader: ref mut r } => r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use prelude::*;
|
||||
use super::*;
|
||||
use super::super::mem::*;
|
||||
use super::super::Decorator;
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn smoke_test() {
|
||||
let mem_writer = MemWriter::new();
|
||||
let mut deflate_writer = DeflateWriter::new(mem_writer);
|
||||
let in_msg = "test";
|
||||
let in_bytes = in_msg.to_bytes();
|
||||
deflate_writer.write(in_bytes);
|
||||
deflate_writer.flush();
|
||||
let buf = deflate_writer.inner().inner();
|
||||
let mem_reader = MemReader::new(buf);
|
||||
let mut inflate_reader = InflateReader::new(mem_reader);
|
||||
let mut out_bytes = [0, .. 100];
|
||||
let bytes_read = inflate_reader.read(out_bytes).get();
|
||||
assert!(bytes_read == in_bytes.len());
|
||||
let out_msg = str::from_bytes(out_bytes);
|
||||
assert!(in_msg == out_msg);
|
||||
}
|
||||
}
|
||||
166
src/libcore/rt/io/mem.rs
Normal file
166
src/libcore/rt/io/mem.rs
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Readers and Writers for in-memory buffers
|
||||
//!
|
||||
//! # XXX
|
||||
//!
|
||||
//! * Should probably have something like this for strings.
|
||||
//! * Should they implement Closable? Would take extra state.
|
||||
|
||||
use prelude::*;
|
||||
use super::*;
|
||||
|
||||
|
||||
/// Writes to an owned, growable byte vector
|
||||
pub struct MemWriter {
|
||||
buf: ~[u8]
|
||||
}
|
||||
|
||||
impl MemWriter {
|
||||
pub fn new() -> MemWriter { MemWriter { buf: ~[] } }
|
||||
}
|
||||
|
||||
impl Writer for MemWriter {
|
||||
fn write(&mut self, _buf: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { /* no-op */ }
|
||||
}
|
||||
|
||||
impl Seek for MemWriter {
|
||||
fn tell(&self) -> u64 { fail!() }
|
||||
|
||||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||
}
|
||||
|
||||
impl Decorator<~[u8]> for MemWriter {
|
||||
|
||||
fn inner(self) -> ~[u8] {
|
||||
match self {
|
||||
MemWriter { buf: buf } => buf
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
|
||||
match *self {
|
||||
MemWriter { buf: ref buf } => buf
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
|
||||
match *self {
|
||||
MemWriter { buf: ref mut buf } => buf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads from an owned byte vector
|
||||
pub struct MemReader {
|
||||
buf: ~[u8],
|
||||
pos: uint
|
||||
}
|
||||
|
||||
impl MemReader {
|
||||
pub fn new(buf: ~[u8]) -> MemReader {
|
||||
MemReader {
|
||||
buf: buf,
|
||||
pos: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Reader for MemReader {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
impl Seek for MemReader {
|
||||
fn tell(&self) -> u64 { fail!() }
|
||||
|
||||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||
}
|
||||
|
||||
impl Decorator<~[u8]> for MemReader {
|
||||
|
||||
fn inner(self) -> ~[u8] {
|
||||
match self {
|
||||
MemReader { buf: buf, _ } => buf
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
|
||||
match *self {
|
||||
MemReader { buf: ref buf, _ } => buf
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
|
||||
match *self {
|
||||
MemReader { buf: ref mut buf, _ } => buf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Writes to a fixed-size byte slice
|
||||
struct BufWriter<'self> {
|
||||
buf: &'self mut [u8],
|
||||
pos: uint
|
||||
}
|
||||
|
||||
impl<'self> BufWriter<'self> {
|
||||
pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> {
|
||||
BufWriter {
|
||||
buf: buf,
|
||||
pos: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> Writer for BufWriter<'self> {
|
||||
fn write(&mut self, _buf: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl<'self> Seek for BufWriter<'self> {
|
||||
fn tell(&self) -> u64 { fail!() }
|
||||
|
||||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||
}
|
||||
|
||||
|
||||
/// Reads from a fixed-size byte slice
|
||||
struct BufReader<'self> {
|
||||
buf: &'self [u8],
|
||||
pos: uint
|
||||
}
|
||||
|
||||
impl<'self> BufReader<'self> {
|
||||
pub fn new<'a>(buf: &'a [u8]) -> BufReader<'a> {
|
||||
BufReader {
|
||||
buf: buf,
|
||||
pos: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> Reader for BufReader<'self> {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
impl<'self> Seek for BufReader<'self> {
|
||||
fn tell(&self) -> u64 { fail!() }
|
||||
|
||||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||
}
|
||||
42
src/libcore/rt/io/misc.rs
Normal file
42
src/libcore/rt/io/misc.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use path::*;
|
||||
|
||||
pub trait PathLike {
|
||||
fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T;
|
||||
}
|
||||
|
||||
impl<'self> PathLike for &'self str {
|
||||
fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T {
|
||||
f(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PathLike for Path {
|
||||
fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T {
|
||||
let s = self.to_str();
|
||||
f(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use path::*;
|
||||
use super::PathLike;
|
||||
|
||||
#[test]
|
||||
fn path_like_smoke_test() {
|
||||
let expected = "/home";
|
||||
let path = Path(expected);
|
||||
path.path_as_str(|p| assert!(p == expected));
|
||||
path.path_as_str(|p| assert!(p == expected));
|
||||
}
|
||||
}
|
||||
|
|
@ -8,35 +8,276 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*! Synchronous I/O
|
||||
|
||||
This module defines the Rust interface for synchronous I/O.
|
||||
It supports file access,
|
||||
|
||||
This will likely live in core::io, not core::rt::io.
|
||||
|
||||
# Examples
|
||||
|
||||
Some examples of obvious things you might want to do
|
||||
|
||||
* Read lines from stdin
|
||||
|
||||
for stdin().each_line |line| {
|
||||
println(line)
|
||||
}
|
||||
|
||||
* Read a complete file to a string, (converting newlines?)
|
||||
|
||||
let contents = open("message.txt").read_to_str(); // read_to_str??
|
||||
|
||||
* Write a line to a file
|
||||
|
||||
let file = FileStream::open("message.txt", Create, Write);
|
||||
file.write_line("hello, file!");
|
||||
|
||||
* Iterate over the lines of a file
|
||||
|
||||
* Pull the lines of a file into a vector of strings
|
||||
|
||||
* Connect based on URL? Requires thinking about where the URL type lives
|
||||
and how to make protocol handlers extensible, e.g. the "tcp" protocol
|
||||
yields a `TcpStream`.
|
||||
|
||||
connect("tcp://localhost:8080").write_line("HTTP 1.0 GET /");
|
||||
|
||||
# Terms
|
||||
|
||||
* reader
|
||||
* writer
|
||||
* stream
|
||||
* Blocking vs. non-blocking
|
||||
* synchrony and asynchrony
|
||||
|
||||
I tend to call this implementation non-blocking, because performing I/O
|
||||
doesn't block the progress of other tasks. Is that how we want to present
|
||||
it, 'synchronous but non-blocking'?
|
||||
|
||||
# Error Handling
|
||||
|
||||
# Resource management
|
||||
|
||||
* `close` vs. RAII
|
||||
|
||||
# Paths and URLs
|
||||
|
||||
# std
|
||||
|
||||
Some I/O things don't belong in core
|
||||
|
||||
- url
|
||||
- net - `fn connect`
|
||||
- http
|
||||
- flate
|
||||
|
||||
# XXX
|
||||
|
||||
* Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose.
|
||||
Overloading would be nice.
|
||||
* Add overloading for Path and &str and Url &str
|
||||
* stdin/err/out
|
||||
* print, println, etc.
|
||||
* fsync
|
||||
* relationship with filesystem querying, Directory, File types etc.
|
||||
* Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic?
|
||||
* Trait for things that are both readers and writers, Stream?
|
||||
* How to handle newline conversion
|
||||
* String conversion
|
||||
* File vs. FileStream? File is shorter but could also be used for getting file info
|
||||
- maybe File is for general file querying and *also* has a static `open` method
|
||||
* open vs. connect for generic stream opening
|
||||
* Do we need `close` at all? dtors might be good enough
|
||||
* How does I/O relate to the Iterator trait?
|
||||
* std::base64 filters
|
||||
|
||||
*/
|
||||
|
||||
use prelude::*;
|
||||
|
||||
// Reexports
|
||||
pub use self::stdio::stdin;
|
||||
pub use self::stdio::stdout;
|
||||
pub use self::stdio::stderr;
|
||||
pub use self::stdio::print;
|
||||
pub use self::stdio::println;
|
||||
|
||||
pub use self::file::open_file;
|
||||
pub use self::file::FileStream;
|
||||
pub use self::net::Listener;
|
||||
pub use self::net::ip::IpAddr;
|
||||
pub use self::net::tcp::TcpListener;
|
||||
pub use self::net::tcp::TcpStream;
|
||||
pub use self::net::udp::UdpStream;
|
||||
|
||||
// Some extension traits that all Readers and Writers get.
|
||||
pub use self::util::ReaderUtil;
|
||||
pub use self::util::ReaderByteConversions;
|
||||
pub use self::util::WriterByteConversions;
|
||||
|
||||
/// Synchronous, non-blocking file I/O.
|
||||
pub mod file;
|
||||
|
||||
// FIXME #5370 Strongly want this to be StreamError(&mut Stream)
|
||||
pub struct StreamError;
|
||||
/// Synchronous, non-blocking network I/O.
|
||||
#[path = "net/mod.rs"]
|
||||
pub mod net;
|
||||
|
||||
// XXX: Can't put doc comments on macros
|
||||
// Raised by `Stream` instances on error. Returning `true` from the handler
|
||||
// indicates that the `Stream` should continue, `false` that it should fail.
|
||||
condition! {
|
||||
stream_error: super::StreamError -> bool;
|
||||
/// Readers and Writers for memory buffers and strings.
|
||||
#[cfg(not(stage0))] // XXX Using unsnapshotted features
|
||||
pub mod mem;
|
||||
|
||||
/// Non-blocking access to stdin, stdout, stderr
|
||||
pub mod stdio;
|
||||
|
||||
/// Basic stream compression. XXX: Belongs with other flate code
|
||||
#[cfg(not(stage0))] // XXX Using unsnapshotted features
|
||||
pub mod flate;
|
||||
|
||||
/// Interop between byte streams and pipes. Not sure where it belongs
|
||||
#[cfg(not(stage0))] // XXX "
|
||||
pub mod comm_adapters;
|
||||
|
||||
/// Extension traits
|
||||
mod util;
|
||||
|
||||
/// Non-I/O things needed by the I/O module
|
||||
mod misc;
|
||||
|
||||
/// Thread-blocking implementations
|
||||
pub mod native {
|
||||
/// Posix file I/O
|
||||
pub mod file;
|
||||
/// # XXX - implement this
|
||||
pub mod stdio { }
|
||||
/// Sockets
|
||||
/// # XXX - implement this
|
||||
pub mod net {
|
||||
pub mod tcp { }
|
||||
pub mod udp { }
|
||||
#[cfg(unix)]
|
||||
pub mod unix { }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Stream {
|
||||
/// Read bytes, up to the length of `buf` and place them in `buf`,
|
||||
/// returning the number of bytes read or an `IoError`. Reads
|
||||
/// 0 bytes on EOF.
|
||||
|
||||
/// The type passed to I/O condition handlers to indicate error
|
||||
///
|
||||
/// # XXX
|
||||
///
|
||||
/// Is something like this sufficient? It's kind of archaic
|
||||
pub struct IoError {
|
||||
kind: IoErrorKind,
|
||||
desc: &'static str,
|
||||
detail: Option<~str>
|
||||
}
|
||||
|
||||
pub enum IoErrorKind {
|
||||
FileNotFound,
|
||||
FilePermission,
|
||||
ConnectionFailed,
|
||||
Closed,
|
||||
OtherIoError
|
||||
}
|
||||
|
||||
// XXX: Can't put doc comments on macros
|
||||
// Raised by `I/O` operations on error.
|
||||
condition! {
|
||||
io_error: super::IoError -> ();
|
||||
}
|
||||
|
||||
pub trait Reader {
|
||||
/// Read bytes, up to the length of `buf` and place them in `buf`.
|
||||
/// Returns the number of bytes read, or `None` on EOF.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `reader_error` condition on error
|
||||
fn read(&mut self, buf: &mut [u8]) -> uint;
|
||||
/// Raises the `io_error` condition on error, then returns `None`.
|
||||
///
|
||||
/// # XXX
|
||||
///
|
||||
/// This doesn't take a `len` argument like the old `read`.
|
||||
/// Will people often need to slice their vectors to call this
|
||||
/// and will that be annoying?
|
||||
fn read(&mut self, buf: &mut [u8]) -> Option<uint>;
|
||||
|
||||
/// Return whether the Reader has reached the end of the stream
|
||||
/// Return whether the Reader has reached the end of the stream.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// let reader = FileStream::new()
|
||||
/// while !reader.eof() {
|
||||
/// println(reader.read_line());
|
||||
/// }
|
||||
///
|
||||
/// # XXX
|
||||
///
|
||||
/// What does this return if the Reader is in an error state?
|
||||
fn eof(&mut self) -> bool;
|
||||
}
|
||||
|
||||
pub trait Writer {
|
||||
/// Write the given buffer
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `writer_error` condition on error
|
||||
fn write(&mut self, v: &const [u8]);
|
||||
/// Raises the `io_error` condition on error
|
||||
fn write(&mut self, buf: &[u8]);
|
||||
|
||||
/// Flush output
|
||||
fn flush(&mut self);
|
||||
}
|
||||
|
||||
/// I/O types that may be closed
|
||||
///
|
||||
/// Any further operations performed on a closed resource will raise
|
||||
/// on `io_error`
|
||||
pub trait Close {
|
||||
/// Close the I/O resource
|
||||
fn close(&mut self);
|
||||
}
|
||||
|
||||
pub trait Stream: Reader + Writer + Close { }
|
||||
|
||||
pub enum SeekStyle {
|
||||
/// Seek from the beginning of the stream
|
||||
SeekSet,
|
||||
/// Seek from the end of the stream
|
||||
SeekEnd,
|
||||
/// Seek from the current position
|
||||
SeekCur,
|
||||
}
|
||||
|
||||
/// # XXX
|
||||
/// * Are `u64` and `i64` the right choices?
|
||||
pub trait Seek {
|
||||
fn tell(&self) -> u64;
|
||||
fn seek(&mut self, pos: i64, style: SeekStyle);
|
||||
}
|
||||
|
||||
/// Common trait for decorator types.
|
||||
///
|
||||
/// Provides accessors to get the inner, 'decorated' values. The I/O library
|
||||
/// uses decorators to add functionality like compression and encryption to I/O
|
||||
/// streams.
|
||||
///
|
||||
/// # XXX
|
||||
///
|
||||
/// Is this worth having a trait for? May be overkill
|
||||
pub trait Decorator<T> {
|
||||
/// Destroy the decorator and extract the decorated value
|
||||
///
|
||||
/// # XXX
|
||||
///
|
||||
/// Because this takes `self' one could never 'undecorate' a Reader/Writer
|
||||
/// that has been boxed. Is that ok? This feature is mostly useful for
|
||||
/// extracting the buffer from MemWriter
|
||||
fn inner(self) -> T;
|
||||
|
||||
/// Take an immutable reference to the decorated value
|
||||
fn inner_ref<'a>(&'a self) -> &'a T;
|
||||
|
||||
/// Take a mutable reference to the decorated value
|
||||
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T;
|
||||
}
|
||||
|
|
|
|||
82
src/libcore/rt/io/native/file.rs
Normal file
82
src/libcore/rt/io/native/file.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Blocking posix-based file I/O
|
||||
|
||||
use prelude::*;
|
||||
use super::super::*;
|
||||
use libc::{c_int, FILE};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type fd_t = c_int;
|
||||
|
||||
// Make this a newtype so we can't do I/O on arbitrary integers
|
||||
pub struct FileDesc(fd_t);
|
||||
|
||||
impl FileDesc {
|
||||
/// Create a `FileDesc` from an open C file descriptor.
|
||||
///
|
||||
/// The `FileDesc` takes ownership of the file descriptor
|
||||
/// and will close it upon destruction.
|
||||
pub fn new(_fd: fd_t) -> FileDesc { fail!() }
|
||||
}
|
||||
|
||||
impl Reader for FileDesc {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
impl Writer for FileDesc {
|
||||
fn write(&mut self, _buf: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl Close for FileDesc {
|
||||
fn close(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl Seek for FileDesc {
|
||||
fn tell(&self) -> u64 { fail!() }
|
||||
|
||||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||
}
|
||||
|
||||
pub struct CFile(*FILE);
|
||||
|
||||
impl CFile {
|
||||
/// Create a `CFile` from an open `FILE` pointer.
|
||||
///
|
||||
/// The `CFile` takes ownership of the file descriptor
|
||||
/// and will close it upon destruction.
|
||||
pub fn new(_file: *FILE) -> CFile { fail!() }
|
||||
}
|
||||
|
||||
impl Reader for CFile {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
impl Writer for CFile {
|
||||
fn write(&mut self, _buf: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl Close for CFile {
|
||||
fn close(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl Seek for CFile {
|
||||
fn tell(&self) -> u64 { fail!() }
|
||||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||
}
|
||||
29
src/libcore/rt/io/net/http.rs
Normal file
29
src/libcore/rt/io/net/http.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Simple HTTP client and server
|
||||
|
||||
// XXX This should not be in core
|
||||
|
||||
struct HttpServer;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use unstable::run_in_bare_thread;
|
||||
|
||||
#[test] #[ignore]
|
||||
fn smoke_test() {
|
||||
do run_in_bare_thread {
|
||||
}
|
||||
|
||||
do run_in_bare_thread {
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/libcore/rt/io/net/ip.rs
Normal file
15
src/libcore/rt/io/net/ip.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub enum IpAddr {
|
||||
Ipv4(u8, u8, u8, u8, u16),
|
||||
Ipv6
|
||||
}
|
||||
|
||||
31
src/libcore/rt/io/net/mod.rs
Normal file
31
src/libcore/rt/io/net/mod.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::*;
|
||||
|
||||
pub mod tcp;
|
||||
pub mod udp;
|
||||
pub mod ip;
|
||||
#[cfg(unix)]
|
||||
pub mod unix;
|
||||
pub mod http;
|
||||
|
||||
/// A listener is a value that listens for connections
|
||||
pub trait Listener<S> {
|
||||
/// Wait for and accept an incoming connection
|
||||
///
|
||||
/// Returns `None` on timeout.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises `io_error` condition. If the condition is handled,
|
||||
/// then `accept` returns `None`.
|
||||
fn accept(&mut self) -> Option<S>;
|
||||
}
|
||||
50
src/libcore/rt/io/net/tcp.rs
Normal file
50
src/libcore/rt/io/net/tcp.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::*;
|
||||
use super::*;
|
||||
use super::super::*;
|
||||
use super::ip::IpAddr;
|
||||
|
||||
pub struct TcpStream;
|
||||
|
||||
impl TcpStream {
|
||||
pub fn connect(_addr: IpAddr) -> Result<TcpStream, IoError> {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Reader for TcpStream {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
impl Writer for TcpStream {
|
||||
fn write(&mut self, _buf: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl Close for TcpStream {
|
||||
fn close(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
pub struct TcpListener;
|
||||
|
||||
impl TcpListener {
|
||||
pub fn new(_addr: IpAddr) -> TcpListener {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Listener<TcpStream> for TcpListener {
|
||||
fn accept(&mut self) -> Option<TcpStream> { fail!() }
|
||||
}
|
||||
51
src/libcore/rt/io/net/udp.rs
Normal file
51
src/libcore/rt/io/net/udp.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::*;
|
||||
use super::*;
|
||||
use super::super::*;
|
||||
use super::ip::IpAddr;
|
||||
|
||||
pub struct UdpStream;
|
||||
|
||||
impl UdpStream {
|
||||
pub fn connect(_addr: IpAddr) -> Result<UdpStream, IoError> {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Reader for UdpStream {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
impl Writer for UdpStream {
|
||||
fn write(&mut self, _buf: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl Close for UdpStream {
|
||||
fn close(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
pub struct UdpListener;
|
||||
|
||||
impl UdpListener {
|
||||
pub fn new(_addr: IpAddr) -> UdpListener {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Listener<UdpStream> for UdpListener {
|
||||
fn accept(&mut self) -> Option<UdpStream> { fail!() }
|
||||
}
|
||||
|
||||
51
src/libcore/rt/io/net/unix.rs
Normal file
51
src/libcore/rt/io/net/unix.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::*;
|
||||
use super::*;
|
||||
use super::super::*;
|
||||
use super::super::misc::PathLike;
|
||||
|
||||
pub struct UnixStream;
|
||||
|
||||
impl UnixStream {
|
||||
pub fn connect<P: PathLike>(_path: &P) -> Result<UnixStream, IoError> {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Reader for UnixStream {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
impl Writer for UnixStream {
|
||||
fn write(&mut self, _v: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl Close for UnixStream {
|
||||
fn close(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
pub struct UnixListener;
|
||||
|
||||
impl UnixListener {
|
||||
pub fn new<P: PathLike>(_path: &P) -> UnixListener {
|
||||
fail!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Listener<UnixStream> for UnixListener {
|
||||
fn accept(&mut self) -> Option<UnixStream> { fail!() }
|
||||
}
|
||||
|
||||
60
src/libcore/rt/io/stdio.rs
Normal file
60
src/libcore/rt/io/stdio.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use prelude::*;
|
||||
use super::{Reader, Writer, Close};
|
||||
|
||||
pub fn stdin() -> StdReader { fail!() }
|
||||
|
||||
pub fn stdout() -> StdWriter { fail!() }
|
||||
|
||||
pub fn stderr() -> StdReader { fail!() }
|
||||
|
||||
pub fn print(s: &str) { fail!() }
|
||||
|
||||
pub fn println(s: &str) { fail!() }
|
||||
|
||||
pub enum StdStream {
|
||||
StdIn,
|
||||
StdOut,
|
||||
StdErr
|
||||
}
|
||||
|
||||
pub struct StdReader;
|
||||
|
||||
impl StdReader {
|
||||
pub fn new(_stream: StdStream) -> StdReader { fail!() }
|
||||
}
|
||||
|
||||
impl Reader for StdReader {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
|
||||
|
||||
fn eof(&mut self) -> bool { fail!() }
|
||||
}
|
||||
|
||||
impl Close for StdReader {
|
||||
fn close(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
pub struct StdWriter;
|
||||
|
||||
impl StdWriter {
|
||||
pub fn new(_stream: StdStream) -> StdWriter { fail!() }
|
||||
}
|
||||
|
||||
impl Writer for StdWriter {
|
||||
fn write(&mut self, _buf: &[u8]) { fail!() }
|
||||
|
||||
fn flush(&mut self) { fail!() }
|
||||
}
|
||||
|
||||
impl Close for StdWriter {
|
||||
fn close(&mut self) { fail!() }
|
||||
}
|
||||
469
src/libcore/rt/io/util.rs
Normal file
469
src/libcore/rt/io/util.rs
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Utility mixins that apply to all Readers and Writers
|
||||
|
||||
// XXX: Not sure how this should be structured
|
||||
// XXX: Iteration should probably be considered seperately
|
||||
|
||||
pub trait ReaderUtil {
|
||||
|
||||
/// Reads `len` bytes and gives you back a new vector
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns an empty
|
||||
/// vector if the condition is handled.
|
||||
fn read_bytes(&mut self, len: uint) -> ~[u8];
|
||||
|
||||
/// Reads all remaining bytes from the stream.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns an empty
|
||||
/// vector if the condition is handled.
|
||||
fn read_to_end(&mut self) -> ~[u8];
|
||||
|
||||
}
|
||||
|
||||
pub trait ReaderByteConversions {
|
||||
/// Reads `n` little-endian unsigned integer bytes.
|
||||
///
|
||||
/// `n` must be between 1 and 8, inclusive.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_uint_n(&mut self, nbytes: uint) -> u64;
|
||||
|
||||
/// Reads `n` little-endian signed integer bytes.
|
||||
///
|
||||
/// `n` must be between 1 and 8, inclusive.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_int_n(&mut self, nbytes: uint) -> i64;
|
||||
|
||||
/// Reads `n` big-endian unsigned integer bytes.
|
||||
///
|
||||
/// `n` must be between 1 and 8, inclusive.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_uint_n(&mut self, nbytes: uint) -> u64;
|
||||
|
||||
/// Reads `n` big-endian signed integer bytes.
|
||||
///
|
||||
/// `n` must be between 1 and 8, inclusive.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_int_n(&mut self, nbytes: uint) -> i64;
|
||||
|
||||
/// Reads a little-endian unsigned integer.
|
||||
///
|
||||
/// The number of bytes returned is system-dependant.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_uint(&mut self) -> uint;
|
||||
|
||||
/// Reads a little-endian integer.
|
||||
///
|
||||
/// The number of bytes returned is system-dependant.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_int(&mut self) -> int;
|
||||
|
||||
/// Reads a big-endian unsigned integer.
|
||||
///
|
||||
/// The number of bytes returned is system-dependant.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_uint(&mut self) -> uint;
|
||||
|
||||
/// Reads a big-endian integer.
|
||||
///
|
||||
/// The number of bytes returned is system-dependant.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_int(&mut self) -> int;
|
||||
|
||||
/// Reads a big-endian `u64`.
|
||||
///
|
||||
/// `u64`s are 8 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_u64(&mut self) -> u64;
|
||||
|
||||
/// Reads a big-endian `u32`.
|
||||
///
|
||||
/// `u32`s are 4 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_u32(&mut self) -> u32;
|
||||
|
||||
/// Reads a big-endian `u16`.
|
||||
///
|
||||
/// `u16`s are 2 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_u16(&mut self) -> u16;
|
||||
|
||||
/// Reads a big-endian `i64`.
|
||||
///
|
||||
/// `i64`s are 8 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_i64(&mut self) -> i64;
|
||||
|
||||
/// Reads a big-endian `i32`.
|
||||
///
|
||||
/// `i32`s are 4 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_i32(&mut self) -> i32;
|
||||
|
||||
/// Reads a big-endian `i16`.
|
||||
///
|
||||
/// `i16`s are 2 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_i16(&mut self) -> i16;
|
||||
|
||||
/// Reads a big-endian `f64`.
|
||||
///
|
||||
/// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_f64(&mut self) -> f64;
|
||||
|
||||
/// Reads a big-endian `f32`.
|
||||
///
|
||||
/// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_be_f32(&mut self) -> f32;
|
||||
|
||||
/// Reads a little-endian `u64`.
|
||||
///
|
||||
/// `u64`s are 8 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_u64(&mut self) -> u64;
|
||||
|
||||
/// Reads a little-endian `u32`.
|
||||
///
|
||||
/// `u32`s are 4 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_u32(&mut self) -> u32;
|
||||
|
||||
/// Reads a little-endian `u16`.
|
||||
///
|
||||
/// `u16`s are 2 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_u16(&mut self) -> u16;
|
||||
|
||||
/// Reads a little-endian `i64`.
|
||||
///
|
||||
/// `i64`s are 8 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_i64(&mut self) -> i64;
|
||||
|
||||
/// Reads a little-endian `i32`.
|
||||
///
|
||||
/// `i32`s are 4 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_i32(&mut self) -> i32;
|
||||
|
||||
/// Reads a little-endian `i16`.
|
||||
///
|
||||
/// `i16`s are 2 bytes long.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_i16(&mut self) -> i16;
|
||||
|
||||
/// Reads a little-endian `f64`.
|
||||
///
|
||||
/// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_f64(&mut self) -> f64;
|
||||
|
||||
/// Reads a little-endian `f32`.
|
||||
///
|
||||
/// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_le_f32(&mut self) -> f32;
|
||||
|
||||
/// Read a u8.
|
||||
///
|
||||
/// `u8`s are 1 byte.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_u8(&mut self) -> u8;
|
||||
|
||||
/// Read an i8.
|
||||
///
|
||||
/// `i8`s are 1 byte.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error. Returns `0` if
|
||||
/// the condition is handled.
|
||||
fn read_i8(&mut self) -> i8;
|
||||
|
||||
}
|
||||
|
||||
pub trait WriterByteConversions {
|
||||
/// Write the result of passing n through `int::to_str_bytes`.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_int(&mut self, n: int);
|
||||
|
||||
/// Write the result of passing n through `uint::to_str_bytes`.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_uint(&mut self, n: uint);
|
||||
|
||||
/// Write a little-endian uint (number of bytes depends on system).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_uint(&mut self, n: uint);
|
||||
|
||||
/// Write a little-endian int (number of bytes depends on system).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_int(&mut self, n: int);
|
||||
|
||||
/// Write a big-endian uint (number of bytes depends on system).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_uint(&mut self, n: uint);
|
||||
|
||||
/// Write a big-endian int (number of bytes depends on system).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_int(&mut self, n: int);
|
||||
|
||||
/// Write a big-endian u64 (8 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_u64(&mut self, n: u64);
|
||||
|
||||
/// Write a big-endian u32 (4 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_u32(&mut self, n: u32);
|
||||
|
||||
/// Write a big-endian u16 (2 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_u16(&mut self, n: u16);
|
||||
|
||||
/// Write a big-endian i64 (8 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_i64(&mut self, n: i64);
|
||||
|
||||
/// Write a big-endian i32 (4 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_i32(&mut self, n: i32);
|
||||
|
||||
/// Write a big-endian i16 (2 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_i16(&mut self, n: i16);
|
||||
|
||||
/// Write a big-endian IEEE754 double-precision floating-point (8 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_f64(&mut self, f: f64);
|
||||
|
||||
/// Write a big-endian IEEE754 single-precision floating-point (4 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_be_f32(&mut self, f: f32);
|
||||
|
||||
/// Write a little-endian u64 (8 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_u64(&mut self, n: u64);
|
||||
|
||||
/// Write a little-endian u32 (4 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_u32(&mut self, n: u32);
|
||||
|
||||
/// Write a little-endian u16 (2 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_u16(&mut self, n: u16);
|
||||
|
||||
/// Write a little-endian i64 (8 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_i64(&mut self, n: i64);
|
||||
|
||||
/// Write a little-endian i32 (4 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_i32(&mut self, n: i32);
|
||||
|
||||
/// Write a little-endian i16 (2 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_i16(&mut self, n: i16);
|
||||
|
||||
/// Write a little-endian IEEE754 double-precision floating-point
|
||||
/// (8 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_f64(&mut self, f: f64);
|
||||
|
||||
/// Write a litten-endian IEEE754 single-precision floating-point
|
||||
/// (4 bytes).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_le_f32(&mut self, f: f32);
|
||||
|
||||
/// Write a u8 (1 byte).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_u8(&mut self, n: u8);
|
||||
|
||||
/// Write a i8 (1 byte).
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the `io_error` condition on error.
|
||||
fn write_i8(&mut self, n: i8);
|
||||
}
|
||||
|
|
@ -88,3 +88,96 @@ pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int {
|
|||
fn rust_call_nullary_fn(f: *u8);
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible contexts in which Rust code may be executing.
|
||||
/// Different runtime services are available depending on context.
|
||||
#[deriving(Eq)]
|
||||
pub enum RuntimeContext {
|
||||
// Only default services, e.g. exchange heap
|
||||
GlobalContext,
|
||||
// The scheduler may be accessed
|
||||
SchedulerContext,
|
||||
// Full task services, e.g. local heap, unwinding
|
||||
TaskContext,
|
||||
// Running in an old-style task
|
||||
OldTaskContext
|
||||
}
|
||||
|
||||
pub fn context() -> RuntimeContext {
|
||||
|
||||
use task::rt::rust_task;
|
||||
use self::sched::local_sched;
|
||||
|
||||
// XXX: Hitting TLS twice to check if the scheduler exists
|
||||
// then to check for the task is not good for perf
|
||||
if unsafe { rust_try_get_task().is_not_null() } {
|
||||
return OldTaskContext;
|
||||
} else {
|
||||
if local_sched::exists() {
|
||||
let context = ::cell::empty_cell();
|
||||
do local_sched::borrow |sched| {
|
||||
if sched.in_task_context() {
|
||||
context.put_back(TaskContext);
|
||||
} else {
|
||||
context.put_back(SchedulerContext);
|
||||
}
|
||||
}
|
||||
return context.take();
|
||||
} else {
|
||||
return GlobalContext;
|
||||
}
|
||||
}
|
||||
|
||||
pub extern {
|
||||
#[rust_stack]
|
||||
fn rust_try_get_task() -> *rust_task;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_context() {
|
||||
use unstable::run_in_bare_thread;
|
||||
use self::sched::{local_sched, Task};
|
||||
use self::uvio::UvEventLoop;
|
||||
use cell::Cell;
|
||||
|
||||
assert!(context() == OldTaskContext);
|
||||
do run_in_bare_thread {
|
||||
assert!(context() == GlobalContext);
|
||||
let mut sched = ~UvEventLoop::new_scheduler();
|
||||
let task = ~do Task::new(&mut sched.stack_pool) {
|
||||
assert!(context() == TaskContext);
|
||||
let sched = local_sched::take();
|
||||
do sched.deschedule_running_task_and_then() |task| {
|
||||
assert!(context() == SchedulerContext);
|
||||
let task = Cell(task);
|
||||
do local_sched::borrow |sched| {
|
||||
sched.task_queue.push_back(task.take());
|
||||
}
|
||||
}
|
||||
};
|
||||
sched.task_queue.push_back(task);
|
||||
sched.run();
|
||||
}
|
||||
}
|
||||
|
||||
// For setting up tests of the new scheduler
|
||||
#[cfg(test)]
|
||||
pub fn run_in_newsched_task(f: ~fn()) {
|
||||
use cell::Cell;
|
||||
use unstable::run_in_bare_thread;
|
||||
use self::sched::Task;
|
||||
use self::uvio::UvEventLoop;
|
||||
|
||||
let f = Cell(Cell(f));
|
||||
|
||||
do run_in_bare_thread {
|
||||
let mut sched = ~UvEventLoop::new_scheduler();
|
||||
let f = f.take();
|
||||
let task = ~do Task::new(&mut sched.stack_pool) {
|
||||
(f.take())();
|
||||
};
|
||||
sched.task_queue.push_back(task);
|
||||
sched.run();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
use option::*;
|
||||
use result::*;
|
||||
|
||||
use super::io::net::ip::IpAddr;
|
||||
|
||||
// XXX: ~object doesn't work currently so these are some placeholder
|
||||
// types to use instead
|
||||
pub type EventLoopObject = super::uvio::UvEventLoop;
|
||||
|
|
@ -43,8 +45,3 @@ pub trait Stream {
|
|||
fn read(&mut self, buf: &mut [u8]) -> Result<uint, ()>;
|
||||
fn write(&mut self, buf: &[u8]) -> Result<(), ()>;
|
||||
}
|
||||
|
||||
pub enum IpAddr {
|
||||
Ipv4(u8, u8, u8, u8, u16),
|
||||
Ipv6
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@
|
|||
|
||||
//! Access to the thread-local Scheduler
|
||||
|
||||
use prelude::*;
|
||||
use ptr::mut_null;
|
||||
use libc::c_void;
|
||||
use cast::transmute;
|
||||
|
||||
use super::Scheduler;
|
||||
use super::super::rtio::IoFactoryObject;
|
||||
use tls = super::super::thread_local_storage;
|
||||
#[cfg(test)] use super::super::uvio::UvEventLoop;
|
||||
|
||||
|
|
@ -39,11 +41,31 @@ pub fn take() -> ~Scheduler {
|
|||
}
|
||||
}
|
||||
|
||||
/// Check whether there is a thread-local Scheduler attached to the running thread
|
||||
pub fn exists() -> bool {
|
||||
unsafe {
|
||||
match maybe_tls_key() {
|
||||
Some(key) => tls::get(key).is_not_null(),
|
||||
None => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrow the thread-local scheduler from thread-local storage.
|
||||
/// While the scheduler is borrowed it is not available in TLS.
|
||||
pub fn borrow(f: &fn(&mut Scheduler)) {
|
||||
let mut sched = take();
|
||||
f(sched);
|
||||
put(sched);
|
||||
}
|
||||
|
||||
/// Borrow a mutable reference to the thread-local Scheduler
|
||||
///
|
||||
/// # Safety Note
|
||||
///
|
||||
/// Because this leaves the Scheduler in thread-local storage it is possible
|
||||
/// For the Scheduler pointer to be aliased
|
||||
pub unsafe fn borrow() -> &mut Scheduler {
|
||||
pub unsafe fn unsafe_borrow() -> &mut Scheduler {
|
||||
unsafe {
|
||||
let key = tls_key();
|
||||
let mut void_sched: *mut c_void = tls::get(key);
|
||||
|
|
@ -59,11 +81,39 @@ pub unsafe fn borrow() -> &mut Scheduler {
|
|||
}
|
||||
}
|
||||
|
||||
pub unsafe fn unsafe_borrow_io() -> &mut IoFactoryObject {
|
||||
unsafe {
|
||||
let sched = unsafe_borrow();
|
||||
return sched.event_loop.io().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn tls_key() -> tls::Key {
|
||||
maybe_tls_key().get()
|
||||
}
|
||||
|
||||
fn maybe_tls_key() -> Option<tls::Key> {
|
||||
unsafe {
|
||||
let key: *mut c_void = rust_get_sched_tls_key();
|
||||
let key: &mut tls::Key = transmute(key);
|
||||
return *key;
|
||||
let key = *key;
|
||||
// Check that the key has been initialized.
|
||||
|
||||
// NB: This is a little racy because, while the key is
|
||||
// initalized under a mutex and it's assumed to be initalized
|
||||
// in the Scheduler ctor by any thread that needs to use it,
|
||||
// we are not accessing the key under a mutex. Threads that
|
||||
// are not using the new Scheduler but still *want to check*
|
||||
// whether they are running under a new Scheduler may see a 0
|
||||
// value here that is in the process of being initialized in
|
||||
// another thread. I think this is fine since the only action
|
||||
// they could take if it was initialized would be to check the
|
||||
// thread-local value and see that it's not set.
|
||||
if key != 0 {
|
||||
return Some(key);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +143,7 @@ fn borrow_smoke_test() {
|
|||
let scheduler = ~UvEventLoop::new_scheduler();
|
||||
put(scheduler);
|
||||
unsafe {
|
||||
let _scheduler = borrow();
|
||||
let _scheduler = unsafe_borrow();
|
||||
}
|
||||
let _scheduler = take();
|
||||
}
|
||||
|
|
@ -14,15 +14,16 @@ use cast::transmute;
|
|||
|
||||
use super::work_queue::WorkQueue;
|
||||
use super::stack::{StackPool, StackSegment};
|
||||
use super::rtio::{EventLoop, EventLoopObject, IoFactoryObject};
|
||||
use super::rtio::{EventLoop, EventLoopObject};
|
||||
use super::context::Context;
|
||||
use cell::Cell;
|
||||
|
||||
#[cfg(test)] use super::uvio::UvEventLoop;
|
||||
#[cfg(test)] use unstable::run_in_bare_thread;
|
||||
#[cfg(test)] use int;
|
||||
#[cfg(test)] use cell::Cell;
|
||||
|
||||
mod local;
|
||||
// A more convenient name for external callers, e.g. `local_sched::take()`
|
||||
pub mod local_sched;
|
||||
|
||||
/// The Scheduler is responsible for coordinating execution of Tasks
|
||||
/// on a single thread. When the scheduler is running it is owned by
|
||||
|
|
@ -57,13 +58,13 @@ impl ClosureConverter for UnsafeTaskReceiver {
|
|||
|
||||
enum CleanupJob {
|
||||
DoNothing,
|
||||
RescheduleTask(~Task),
|
||||
RecycleTask(~Task),
|
||||
GiveTask(~Task, UnsafeTaskReceiver)
|
||||
}
|
||||
|
||||
pub impl Scheduler {
|
||||
|
||||
fn in_task_context(&self) -> bool { self.current_task.is_some() }
|
||||
|
||||
fn new(event_loop: ~EventLoopObject) -> Scheduler {
|
||||
|
||||
// Lazily initialize the global state, currently the scheduler TLS key
|
||||
|
|
@ -90,47 +91,25 @@ pub impl Scheduler {
|
|||
assert!(!self.in_task_context());
|
||||
|
||||
// Give ownership of the scheduler (self) to the thread
|
||||
local::put(self);
|
||||
local_sched::put(self);
|
||||
|
||||
let scheduler = unsafe { local::borrow() };
|
||||
fn run_scheduler_once() {
|
||||
let scheduler = Scheduler::take_local();
|
||||
if scheduler.resume_task_from_queue() {
|
||||
// Ok, a task ran. Nice! We'll do it again later
|
||||
do Scheduler::borrow_local |scheduler| {
|
||||
scheduler.event_loop.callback(run_scheduler_once);
|
||||
unsafe {
|
||||
let scheduler = local_sched::unsafe_borrow();
|
||||
fn run_scheduler_once() {
|
||||
let scheduler = local_sched::take();
|
||||
if scheduler.resume_task_from_queue() {
|
||||
// Ok, a task ran. Nice! We'll do it again later
|
||||
do local_sched::borrow |scheduler| {
|
||||
scheduler.event_loop.callback(run_scheduler_once);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scheduler.event_loop.callback(run_scheduler_once);
|
||||
scheduler.event_loop.run();
|
||||
}
|
||||
|
||||
scheduler.event_loop.callback(run_scheduler_once);
|
||||
scheduler.event_loop.run();
|
||||
|
||||
return local::take();
|
||||
}
|
||||
|
||||
/// Get a mutable pointer to the thread-local I/O
|
||||
/// # Safety Note
|
||||
/// This allows other mutable aliases to the scheduler, both in the current
|
||||
/// execution context and other execution contexts.
|
||||
unsafe fn borrow_local_io() -> &mut IoFactoryObject {
|
||||
unsafe {
|
||||
let io = local::borrow().event_loop.io().unwrap();
|
||||
transmute::<&mut IoFactoryObject, &mut IoFactoryObject>(io)
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrow the thread-local scheduler from thread-local storage.
|
||||
/// While the scheduler is borrowed it is not available in TLS.
|
||||
fn borrow_local(f: &fn(&mut Scheduler)) {
|
||||
let mut sched = local::take();
|
||||
f(sched);
|
||||
local::put(sched);
|
||||
}
|
||||
|
||||
/// Take ownership of the scheduler from thread local storage
|
||||
fn take_local() -> ~Scheduler {
|
||||
local::take()
|
||||
return local_sched::take();
|
||||
}
|
||||
|
||||
// * Scheduler-context operations
|
||||
|
|
@ -146,41 +125,12 @@ pub impl Scheduler {
|
|||
}
|
||||
None => {
|
||||
rtdebug!("no tasks in queue");
|
||||
local::put(self);
|
||||
local_sched::put(self);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resume_task_immediately(~self, task: ~Task) {
|
||||
let mut self = self;
|
||||
assert!(!self.in_task_context());
|
||||
|
||||
rtdebug!("scheduling a task");
|
||||
|
||||
// Store the task in the scheduler so it can be grabbed later
|
||||
self.current_task = Some(task);
|
||||
self.enqueue_cleanup_job(DoNothing);
|
||||
|
||||
local::put(self);
|
||||
|
||||
// Take pointers to both the task and scheduler's saved registers.
|
||||
let sched = unsafe { local::borrow() };
|
||||
let (sched_context, _, next_task_context) = sched.get_contexts();
|
||||
let next_task_context = next_task_context.unwrap();
|
||||
// Context switch to the task, restoring it's registers
|
||||
// and saving the scheduler's
|
||||
Context::swap(sched_context, next_task_context);
|
||||
|
||||
let sched = unsafe { local::borrow() };
|
||||
// The running task should have passed ownership elsewhere
|
||||
assert!(sched.current_task.is_none());
|
||||
|
||||
// Running tasks may have asked us to do some cleanup
|
||||
sched.run_cleanup_job();
|
||||
}
|
||||
|
||||
|
||||
// * Task-context operations
|
||||
|
||||
/// Called by a running task to end execution, after which it will
|
||||
|
|
@ -191,19 +141,60 @@ pub impl Scheduler {
|
|||
|
||||
rtdebug!("ending running task");
|
||||
|
||||
let dead_task = self.current_task.swap_unwrap();
|
||||
self.enqueue_cleanup_job(RecycleTask(dead_task));
|
||||
|
||||
local::put(self);
|
||||
|
||||
let sched = unsafe { local::borrow() };
|
||||
let (sched_context, last_task_context, _) = sched.get_contexts();
|
||||
let last_task_context = last_task_context.unwrap();
|
||||
Context::swap(last_task_context, sched_context);
|
||||
do self.deschedule_running_task_and_then |dead_task| {
|
||||
let dead_task = Cell(dead_task);
|
||||
do local_sched::borrow |sched| {
|
||||
dead_task.take().recycle(&mut sched.stack_pool);
|
||||
}
|
||||
}
|
||||
|
||||
// Control never reaches here
|
||||
}
|
||||
|
||||
fn schedule_new_task(~self, task: ~Task) {
|
||||
let mut self = self;
|
||||
assert!(self.in_task_context());
|
||||
|
||||
do self.switch_running_tasks_and_then(task) |last_task| {
|
||||
let last_task = Cell(last_task);
|
||||
do local_sched::borrow |sched| {
|
||||
sched.task_queue.push_front(last_task.take());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Core scheduling ops
|
||||
|
||||
fn resume_task_immediately(~self, task: ~Task) {
|
||||
let mut self = self;
|
||||
assert!(!self.in_task_context());
|
||||
|
||||
rtdebug!("scheduling a task");
|
||||
|
||||
// Store the task in the scheduler so it can be grabbed later
|
||||
self.current_task = Some(task);
|
||||
self.enqueue_cleanup_job(DoNothing);
|
||||
|
||||
local_sched::put(self);
|
||||
|
||||
// Take pointers to both the task and scheduler's saved registers.
|
||||
unsafe {
|
||||
let sched = local_sched::unsafe_borrow();
|
||||
let (sched_context, _, next_task_context) = sched.get_contexts();
|
||||
let next_task_context = next_task_context.unwrap();
|
||||
// Context switch to the task, restoring it's registers
|
||||
// and saving the scheduler's
|
||||
Context::swap(sched_context, next_task_context);
|
||||
|
||||
let sched = local_sched::unsafe_borrow();
|
||||
// The running task should have passed ownership elsewhere
|
||||
assert!(sched.current_task.is_none());
|
||||
|
||||
// Running tasks may have asked us to do some cleanup
|
||||
sched.run_cleanup_job();
|
||||
}
|
||||
}
|
||||
|
||||
/// Block a running task, context switch to the scheduler, then pass the
|
||||
/// blocked task to a closure.
|
||||
///
|
||||
|
|
@ -223,47 +214,51 @@ pub impl Scheduler {
|
|||
let f_opaque = ClosureConverter::from_fn(f_fake_region);
|
||||
self.enqueue_cleanup_job(GiveTask(blocked_task, f_opaque));
|
||||
|
||||
local::put(self);
|
||||
local_sched::put(self);
|
||||
|
||||
let sched = unsafe { local::borrow() };
|
||||
let sched = unsafe { local_sched::unsafe_borrow() };
|
||||
let (sched_context, last_task_context, _) = sched.get_contexts();
|
||||
let last_task_context = last_task_context.unwrap();
|
||||
Context::swap(last_task_context, sched_context);
|
||||
|
||||
// We could be executing in a different thread now
|
||||
let sched = unsafe { local::borrow() };
|
||||
let sched = unsafe { local_sched::unsafe_borrow() };
|
||||
sched.run_cleanup_job();
|
||||
}
|
||||
|
||||
/// Switch directly to another task, without going through the scheduler.
|
||||
/// You would want to think hard about doing this, e.g. if there are
|
||||
/// pending I/O events it would be a bad idea.
|
||||
fn resume_task_from_running_task_direct(~self, next_task: ~Task) {
|
||||
fn switch_running_tasks_and_then(~self, next_task: ~Task, f: &fn(~Task)) {
|
||||
let mut self = self;
|
||||
assert!(self.in_task_context());
|
||||
|
||||
rtdebug!("switching tasks");
|
||||
|
||||
let old_running_task = self.current_task.swap_unwrap();
|
||||
self.enqueue_cleanup_job(RescheduleTask(old_running_task));
|
||||
let f_fake_region = unsafe { transmute::<&fn(~Task), &fn(~Task)>(f) };
|
||||
let f_opaque = ClosureConverter::from_fn(f_fake_region);
|
||||
self.enqueue_cleanup_job(GiveTask(old_running_task, f_opaque));
|
||||
self.current_task = Some(next_task);
|
||||
|
||||
local::put(self);
|
||||
local_sched::put(self);
|
||||
|
||||
let sched = unsafe { local::borrow() };
|
||||
let (_, last_task_context, next_task_context) = sched.get_contexts();
|
||||
let last_task_context = last_task_context.unwrap();
|
||||
let next_task_context = next_task_context.unwrap();
|
||||
Context::swap(last_task_context, next_task_context);
|
||||
unsafe {
|
||||
let sched = local_sched::unsafe_borrow();
|
||||
let (_, last_task_context, next_task_context) = sched.get_contexts();
|
||||
let last_task_context = last_task_context.unwrap();
|
||||
let next_task_context = next_task_context.unwrap();
|
||||
Context::swap(last_task_context, next_task_context);
|
||||
|
||||
// We could be executing in a different thread now
|
||||
let sched = unsafe { local::borrow() };
|
||||
sched.run_cleanup_job();
|
||||
// We could be executing in a different thread now
|
||||
let sched = local_sched::unsafe_borrow();
|
||||
sched.run_cleanup_job();
|
||||
}
|
||||
}
|
||||
|
||||
// * Other stuff
|
||||
|
||||
fn in_task_context(&self) -> bool { self.current_task.is_some() }
|
||||
|
||||
// * Other stuff
|
||||
|
||||
fn enqueue_cleanup_job(&mut self, job: CleanupJob) {
|
||||
assert!(self.cleanup_job.is_none());
|
||||
|
|
@ -278,11 +273,6 @@ pub impl Scheduler {
|
|||
let cleanup_job = self.cleanup_job.swap_unwrap();
|
||||
match cleanup_job {
|
||||
DoNothing => { }
|
||||
RescheduleTask(task) => {
|
||||
// NB: Pushing to the *front* of the queue
|
||||
self.task_queue.push_front(task);
|
||||
}
|
||||
RecycleTask(task) => task.recycle(&mut self.stack_pool),
|
||||
GiveTask(task, f) => (f.to_fn())(task)
|
||||
}
|
||||
}
|
||||
|
|
@ -300,8 +290,6 @@ pub impl Scheduler {
|
|||
Option<&'a mut Context>,
|
||||
Option<&'a mut Context>) {
|
||||
let last_task = match self.cleanup_job {
|
||||
Some(RescheduleTask(~ref task)) |
|
||||
Some(RecycleTask(~ref task)) |
|
||||
Some(GiveTask(~ref task, _)) => {
|
||||
Some(task)
|
||||
}
|
||||
|
|
@ -358,12 +346,14 @@ pub impl Task {
|
|||
// This is the first code to execute after the initial
|
||||
// context switch to the task. The previous context may
|
||||
// have asked us to do some cleanup.
|
||||
let sched = unsafe { local::borrow() };
|
||||
sched.run_cleanup_job();
|
||||
unsafe {
|
||||
let sched = local_sched::unsafe_borrow();
|
||||
sched.run_cleanup_job();
|
||||
}
|
||||
|
||||
start();
|
||||
|
||||
let sched = Scheduler::take_local();
|
||||
let sched = local_sched::take();
|
||||
sched.terminate_current_task();
|
||||
};
|
||||
return wrapper;
|
||||
|
|
@ -415,7 +405,7 @@ fn test_several_tasks() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_swap_tasks() {
|
||||
fn test_swap_tasks_then() {
|
||||
do run_in_bare_thread {
|
||||
let mut count = 0;
|
||||
let count_ptr: *mut int = &mut count;
|
||||
|
|
@ -423,12 +413,17 @@ fn test_swap_tasks() {
|
|||
let mut sched = ~UvEventLoop::new_scheduler();
|
||||
let task1 = ~do Task::new(&mut sched.stack_pool) {
|
||||
unsafe { *count_ptr = *count_ptr + 1; }
|
||||
let mut sched = Scheduler::take_local();
|
||||
let mut sched = local_sched::take();
|
||||
let task2 = ~do Task::new(&mut sched.stack_pool) {
|
||||
unsafe { *count_ptr = *count_ptr + 1; }
|
||||
};
|
||||
// Context switch directly to the new task
|
||||
sched.resume_task_from_running_task_direct(task2);
|
||||
do sched.switch_running_tasks_and_then(task2) |task1| {
|
||||
let task1 = Cell(task1);
|
||||
do local_sched::borrow |sched| {
|
||||
sched.task_queue.push_front(task1.take());
|
||||
}
|
||||
}
|
||||
unsafe { *count_ptr = *count_ptr + 1; }
|
||||
};
|
||||
sched.task_queue.push_back(task1);
|
||||
|
|
@ -455,7 +450,7 @@ fn test_run_a_lot_of_tasks_queued() {
|
|||
assert!(count == MAX);
|
||||
|
||||
fn run_task(count_ptr: *mut int) {
|
||||
do Scheduler::borrow_local |sched| {
|
||||
do local_sched::borrow |sched| {
|
||||
let task = ~do Task::new(&mut sched.stack_pool) {
|
||||
unsafe {
|
||||
*count_ptr = *count_ptr + 1;
|
||||
|
|
@ -470,49 +465,16 @@ fn test_run_a_lot_of_tasks_queued() {
|
|||
}
|
||||
}
|
||||
|
||||
#[bench] #[test] #[ignore(reason = "too much stack allocation")]
|
||||
fn test_run_a_lot_of_tasks_direct() {
|
||||
do run_in_bare_thread {
|
||||
static MAX: int = 100000;
|
||||
let mut count = 0;
|
||||
let count_ptr: *mut int = &mut count;
|
||||
|
||||
let mut sched = ~UvEventLoop::new_scheduler();
|
||||
|
||||
let start_task = ~do Task::new(&mut sched.stack_pool) {
|
||||
run_task(count_ptr);
|
||||
};
|
||||
sched.task_queue.push_back(start_task);
|
||||
sched.run();
|
||||
|
||||
assert!(count == MAX);
|
||||
|
||||
fn run_task(count_ptr: *mut int) {
|
||||
let mut sched = Scheduler::take_local();
|
||||
let task = ~do Task::new(&mut sched.stack_pool) {
|
||||
unsafe {
|
||||
*count_ptr = *count_ptr + 1;
|
||||
if *count_ptr != MAX {
|
||||
run_task(count_ptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Context switch directly to the new task
|
||||
sched.resume_task_from_running_task_direct(task);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_task() {
|
||||
do run_in_bare_thread {
|
||||
let mut sched = ~UvEventLoop::new_scheduler();
|
||||
let task = ~do Task::new(&mut sched.stack_pool) {
|
||||
let sched = Scheduler::take_local();
|
||||
let sched = local_sched::take();
|
||||
assert!(sched.in_task_context());
|
||||
do sched.deschedule_running_task_and_then() |task| {
|
||||
let task = Cell(task);
|
||||
do Scheduler::borrow_local |sched| {
|
||||
do local_sched::borrow |sched| {
|
||||
assert!(!sched.in_task_context());
|
||||
sched.task_queue.push_back(task.take());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use super::{Loop, Watcher, Request, UvError, Buf, Callback, NativeHandle, NullCa
|
|||
loop_from_watcher, status_to_maybe_uv_error,
|
||||
install_watcher_data, get_watcher_data, drop_watcher_data,
|
||||
vec_to_uv_buf, vec_from_uv_buf};
|
||||
use super::super::rtio::{IpAddr, Ipv4, Ipv6};
|
||||
use super::super::io::net::ip::{IpAddr, Ipv4, Ipv6};
|
||||
|
||||
#[cfg(test)]
|
||||
use unstable::run_in_bare_thread;
|
||||
|
|
|
|||
|
|
@ -11,12 +11,13 @@
|
|||
use option::*;
|
||||
use result::*;
|
||||
|
||||
use super::io::net::ip::{IpAddr, Ipv4};
|
||||
use super::uv::*;
|
||||
use super::rtio::*;
|
||||
use ops::Drop;
|
||||
use cell::{Cell, empty_cell};
|
||||
use cast::transmute;
|
||||
use super::sched::Scheduler;
|
||||
use super::sched::{Scheduler, local_sched};
|
||||
|
||||
#[cfg(test)] use super::sched::Task;
|
||||
#[cfg(test)] use unstable::run_in_bare_thread;
|
||||
|
|
@ -120,14 +121,14 @@ impl IoFactory for UvIoFactory {
|
|||
let result_cell = empty_cell();
|
||||
let result_cell_ptr: *Cell<Option<~StreamObject>> = &result_cell;
|
||||
|
||||
let scheduler = Scheduler::take_local();
|
||||
let scheduler = local_sched::take();
|
||||
assert!(scheduler.in_task_context());
|
||||
|
||||
// Block this task and take ownership, switch to scheduler context
|
||||
do scheduler.deschedule_running_task_and_then |task| {
|
||||
|
||||
rtdebug!("connect: entered scheduler context");
|
||||
do Scheduler::borrow_local |scheduler| {
|
||||
do local_sched::borrow |scheduler| {
|
||||
assert!(!scheduler.in_task_context());
|
||||
}
|
||||
let mut tcp_watcher = TcpWatcher::new(self.uv_loop());
|
||||
|
|
@ -149,7 +150,7 @@ impl IoFactory for UvIoFactory {
|
|||
unsafe { (*result_cell_ptr).put_back(maybe_stream); }
|
||||
|
||||
// Context switch
|
||||
let scheduler = Scheduler::take_local();
|
||||
let scheduler = local_sched::take();
|
||||
scheduler.resume_task_immediately(task_cell.take());
|
||||
}
|
||||
}
|
||||
|
|
@ -194,7 +195,7 @@ impl TcpListener for UvTcpListener {
|
|||
|
||||
let server_tcp_watcher = self.watcher();
|
||||
|
||||
let scheduler = Scheduler::take_local();
|
||||
let scheduler = local_sched::take();
|
||||
assert!(scheduler.in_task_context());
|
||||
|
||||
do scheduler.deschedule_running_task_and_then |task| {
|
||||
|
|
@ -217,7 +218,7 @@ impl TcpListener for UvTcpListener {
|
|||
|
||||
rtdebug!("resuming task from listen");
|
||||
// Context switch
|
||||
let scheduler = Scheduler::take_local();
|
||||
let scheduler = local_sched::take();
|
||||
scheduler.resume_task_immediately(task_cell.take());
|
||||
}
|
||||
}
|
||||
|
|
@ -257,13 +258,13 @@ impl Stream for UvStream {
|
|||
let result_cell = empty_cell();
|
||||
let result_cell_ptr: *Cell<Result<uint, ()>> = &result_cell;
|
||||
|
||||
let scheduler = Scheduler::take_local();
|
||||
let scheduler = local_sched::take();
|
||||
assert!(scheduler.in_task_context());
|
||||
let watcher = self.watcher();
|
||||
let buf_ptr: *&mut [u8] = &buf;
|
||||
do scheduler.deschedule_running_task_and_then |task| {
|
||||
rtdebug!("read: entered scheduler context");
|
||||
do Scheduler::borrow_local |scheduler| {
|
||||
do local_sched::borrow |scheduler| {
|
||||
assert!(!scheduler.in_task_context());
|
||||
}
|
||||
let mut watcher = watcher;
|
||||
|
|
@ -291,7 +292,7 @@ impl Stream for UvStream {
|
|||
|
||||
unsafe { (*result_cell_ptr).put_back(result); }
|
||||
|
||||
let scheduler = Scheduler::take_local();
|
||||
let scheduler = local_sched::take();
|
||||
scheduler.resume_task_immediately(task_cell.take());
|
||||
}
|
||||
}
|
||||
|
|
@ -303,7 +304,7 @@ impl Stream for UvStream {
|
|||
fn write(&mut self, buf: &[u8]) -> Result<(), ()> {
|
||||
let result_cell = empty_cell();
|
||||
let result_cell_ptr: *Cell<Result<(), ()>> = &result_cell;
|
||||
let scheduler = Scheduler::take_local();
|
||||
let scheduler = local_sched::take();
|
||||
assert!(scheduler.in_task_context());
|
||||
let watcher = self.watcher();
|
||||
let buf_ptr: *&[u8] = &buf;
|
||||
|
|
@ -322,7 +323,7 @@ impl Stream for UvStream {
|
|||
|
||||
unsafe { (*result_cell_ptr).put_back(result); }
|
||||
|
||||
let scheduler = Scheduler::take_local();
|
||||
let scheduler = local_sched::take();
|
||||
scheduler.resume_task_immediately(task_cell.take());
|
||||
}
|
||||
}
|
||||
|
|
@ -338,7 +339,7 @@ fn test_simple_io_no_connect() {
|
|||
do run_in_bare_thread {
|
||||
let mut sched = ~UvEventLoop::new_scheduler();
|
||||
let task = ~do Task::new(&mut sched.stack_pool) {
|
||||
let io = unsafe { Scheduler::borrow_local_io() };
|
||||
let io = unsafe { local_sched::unsafe_borrow_io() };
|
||||
let addr = Ipv4(127, 0, 0, 1, 2926);
|
||||
let maybe_chan = io.connect(addr);
|
||||
assert!(maybe_chan.is_none());
|
||||
|
|
@ -356,25 +357,29 @@ fn test_simple_tcp_server_and_client() {
|
|||
let addr = Ipv4(127, 0, 0, 1, 2929);
|
||||
|
||||
let client_task = ~do Task::new(&mut sched.stack_pool) {
|
||||
let io = unsafe { Scheduler::borrow_local_io() };
|
||||
let mut stream = io.connect(addr).unwrap();
|
||||
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
stream.close();
|
||||
unsafe {
|
||||
let io = local_sched::unsafe_borrow_io();
|
||||
let mut stream = io.connect(addr).unwrap();
|
||||
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
stream.close();
|
||||
}
|
||||
};
|
||||
|
||||
let server_task = ~do Task::new(&mut sched.stack_pool) {
|
||||
let io = unsafe { Scheduler::borrow_local_io() };
|
||||
let mut listener = io.bind(addr).unwrap();
|
||||
let mut stream = listener.listen().unwrap();
|
||||
let mut buf = [0, .. 2048];
|
||||
let nread = stream.read(buf).unwrap();
|
||||
assert!(nread == 8);
|
||||
for uint::range(0, nread) |i| {
|
||||
rtdebug!("%u", buf[i] as uint);
|
||||
assert!(buf[i] == i as u8);
|
||||
unsafe {
|
||||
let io = local_sched::unsafe_borrow_io();
|
||||
let mut listener = io.bind(addr).unwrap();
|
||||
let mut stream = listener.listen().unwrap();
|
||||
let mut buf = [0, .. 2048];
|
||||
let nread = stream.read(buf).unwrap();
|
||||
assert!(nread == 8);
|
||||
for uint::range(0, nread) |i| {
|
||||
rtdebug!("%u", buf[i] as uint);
|
||||
assert!(buf[i] == i as u8);
|
||||
}
|
||||
stream.close();
|
||||
listener.close();
|
||||
}
|
||||
stream.close();
|
||||
listener.close();
|
||||
};
|
||||
|
||||
// Start the server first so it listens before the client connects
|
||||
|
|
@ -391,7 +396,7 @@ fn test_read_and_block() {
|
|||
let addr = Ipv4(127, 0, 0, 1, 2930);
|
||||
|
||||
let client_task = ~do Task::new(&mut sched.stack_pool) {
|
||||
let io = unsafe { Scheduler::borrow_local_io() };
|
||||
let io = unsafe { local_sched::unsafe_borrow_io() };
|
||||
let mut stream = io.connect(addr).unwrap();
|
||||
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
|
|
@ -401,7 +406,7 @@ fn test_read_and_block() {
|
|||
};
|
||||
|
||||
let server_task = ~do Task::new(&mut sched.stack_pool) {
|
||||
let io = unsafe { Scheduler::borrow_local_io() };
|
||||
let io = unsafe { local_sched::unsafe_borrow_io() };
|
||||
let mut listener = io.bind(addr).unwrap();
|
||||
let mut stream = listener.listen().unwrap();
|
||||
let mut buf = [0, .. 2048];
|
||||
|
|
@ -419,13 +424,13 @@ fn test_read_and_block() {
|
|||
}
|
||||
reads += 1;
|
||||
|
||||
let scheduler = Scheduler::take_local();
|
||||
let scheduler = local_sched::take();
|
||||
// Yield to the other task in hopes that it
|
||||
// will trigger a read callback while we are
|
||||
// not ready for it
|
||||
do scheduler.deschedule_running_task_and_then |task| {
|
||||
let task = Cell(task);
|
||||
do Scheduler::borrow_local |scheduler| {
|
||||
do local_sched::borrow |scheduler| {
|
||||
scheduler.task_queue.push_back(task.take());
|
||||
}
|
||||
}
|
||||
|
|
@ -452,7 +457,7 @@ fn test_read_read_read() {
|
|||
let addr = Ipv4(127, 0, 0, 1, 2931);
|
||||
|
||||
let client_task = ~do Task::new(&mut sched.stack_pool) {
|
||||
let io = unsafe { Scheduler::borrow_local_io() };
|
||||
let io = unsafe { local_sched::unsafe_borrow_io() };
|
||||
let mut stream = io.connect(addr).unwrap();
|
||||
let mut buf = [0, .. 2048];
|
||||
let mut total_bytes_read = 0;
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ pub struct TaskOpts {
|
|||
// FIXME (#3724): Replace the 'consumed' bit with move mode on self
|
||||
pub struct TaskBuilder {
|
||||
opts: TaskOpts,
|
||||
gen_body: @fn(v: ~fn()) -> ~fn(),
|
||||
mut gen_body: Option<~fn(v: ~fn()) -> ~fn()>,
|
||||
can_not_copy: Option<util::NonCopyable>,
|
||||
mut consumed: bool,
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ pub struct TaskBuilder {
|
|||
pub fn task() -> TaskBuilder {
|
||||
TaskBuilder {
|
||||
opts: default_task_opts(),
|
||||
gen_body: |body| body, // Identity function
|
||||
gen_body: None,
|
||||
can_not_copy: None,
|
||||
mut consumed: false,
|
||||
}
|
||||
|
|
@ -201,6 +201,7 @@ priv impl TaskBuilder {
|
|||
fail!(~"Cannot copy a task_builder"); // Fake move mode on self
|
||||
}
|
||||
self.consumed = true;
|
||||
let gen_body = replace(&mut self.gen_body, None);
|
||||
let notify_chan = replace(&mut self.opts.notify_chan, None);
|
||||
TaskBuilder {
|
||||
opts: TaskOpts {
|
||||
|
|
@ -209,7 +210,7 @@ priv impl TaskBuilder {
|
|||
notify_chan: notify_chan,
|
||||
sched: self.opts.sched
|
||||
},
|
||||
gen_body: self.gen_body,
|
||||
gen_body: gen_body,
|
||||
can_not_copy: None,
|
||||
consumed: false
|
||||
}
|
||||
|
|
@ -341,8 +342,23 @@ pub impl TaskBuilder {
|
|||
* generator by applying the task body which results from the
|
||||
* existing body generator to the new body generator.
|
||||
*/
|
||||
fn add_wrapper(&self, wrapper: @fn(v: ~fn()) -> ~fn()) -> TaskBuilder {
|
||||
let prev_gen_body = self.gen_body;
|
||||
fn add_wrapper(&self, wrapper: ~fn(v: ~fn()) -> ~fn()) -> TaskBuilder {
|
||||
let prev_gen_body = replace(&mut self.gen_body, None);
|
||||
let prev_gen_body = match prev_gen_body {
|
||||
Some(gen) => gen,
|
||||
None => {
|
||||
let f: ~fn(~fn()) -> ~fn() = |body| body;
|
||||
f
|
||||
}
|
||||
};
|
||||
let prev_gen_body = Cell(prev_gen_body);
|
||||
let next_gen_body = {
|
||||
let f: ~fn(~fn()) -> ~fn() = |body| {
|
||||
let prev_gen_body = prev_gen_body.take();
|
||||
wrapper(prev_gen_body(body))
|
||||
};
|
||||
f
|
||||
};
|
||||
let notify_chan = replace(&mut self.opts.notify_chan, None);
|
||||
TaskBuilder {
|
||||
opts: TaskOpts {
|
||||
|
|
@ -351,7 +367,7 @@ pub impl TaskBuilder {
|
|||
notify_chan: notify_chan,
|
||||
sched: self.opts.sched
|
||||
},
|
||||
gen_body: |body| { wrapper(prev_gen_body(body)) },
|
||||
gen_body: Some(next_gen_body),
|
||||
can_not_copy: None,
|
||||
.. self.consume()
|
||||
}
|
||||
|
|
@ -370,6 +386,7 @@ pub impl TaskBuilder {
|
|||
* must be greater than zero.
|
||||
*/
|
||||
fn spawn(&self, f: ~fn()) {
|
||||
let gen_body = replace(&mut self.gen_body, None);
|
||||
let notify_chan = replace(&mut self.opts.notify_chan, None);
|
||||
let x = self.consume();
|
||||
let opts = TaskOpts {
|
||||
|
|
@ -378,7 +395,15 @@ pub impl TaskBuilder {
|
|||
notify_chan: notify_chan,
|
||||
sched: x.opts.sched
|
||||
};
|
||||
spawn::spawn_raw(opts, (x.gen_body)(f));
|
||||
let f = match gen_body {
|
||||
Some(gen) => {
|
||||
gen(f)
|
||||
}
|
||||
None => {
|
||||
f
|
||||
}
|
||||
};
|
||||
spawn::spawn_raw(opts, f);
|
||||
}
|
||||
/// Runs a task, while transfering ownership of one argument to the child.
|
||||
fn spawn_with<A:Owned>(&self, arg: A, f: ~fn(v: A)) {
|
||||
|
|
@ -1201,3 +1226,12 @@ fn test_spawn_thread_on_demand() {
|
|||
|
||||
port.recv();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_newsched_spawn() {
|
||||
use rt::run_in_newsched_task;
|
||||
|
||||
do run_in_newsched_task {
|
||||
spawn(||())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -531,6 +531,34 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
|
|||
}
|
||||
|
||||
pub fn spawn_raw(opts: TaskOpts, f: ~fn()) {
|
||||
use rt::*;
|
||||
|
||||
match context() {
|
||||
OldTaskContext => {
|
||||
spawn_raw_oldsched(opts, f)
|
||||
}
|
||||
TaskContext => {
|
||||
spawn_raw_newsched(opts, f)
|
||||
}
|
||||
SchedulerContext => {
|
||||
fail!(~"can't spawn from scheduler context")
|
||||
}
|
||||
GlobalContext => {
|
||||
fail!(~"can't spawn from global context")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_raw_newsched(opts: TaskOpts, f: ~fn()) {
|
||||
use rt::sched::*;
|
||||
|
||||
let mut sched = local_sched::take();
|
||||
let task = ~Task::new(&mut sched.stack_pool, f);
|
||||
sched.schedule_new_task(task);
|
||||
}
|
||||
|
||||
fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) {
|
||||
|
||||
let (child_tg, ancestors, is_main) =
|
||||
gen_child_taskgroup(opts.linked, opts.supervised);
|
||||
|
||||
|
|
|
|||
|
|
@ -539,6 +539,11 @@ rust_get_task() {
|
|||
return rust_get_current_task();
|
||||
}
|
||||
|
||||
extern "C" rust_task *
|
||||
rust_try_get_task() {
|
||||
return rust_try_get_current_task();
|
||||
}
|
||||
|
||||
extern "C" CDECL stk_seg *
|
||||
rust_get_stack_segment() {
|
||||
return rust_get_current_task()->stk;
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ rust_env_pairs
|
|||
rust_task_yield
|
||||
rust_task_is_unwinding
|
||||
rust_get_task
|
||||
rust_try_get_task
|
||||
rust_get_stack_segment
|
||||
rust_log_str
|
||||
start_task
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue