Skip to content

Commit

Permalink
auto merge of #5409 : brson/rust/rt, r=brson
Browse files Browse the repository at this point in the history
r?

There are a lot of commits here, but not all that much substance. Mostly just refactoring.

I started sketching out the beginnings of a very simple I/O API in `core::rt::io` that represents I/O streams as a single `Stream` trait instead of `Reader` / `Writer` pairs. This seems to be the more common pattern (at least this is how the .NET BCL does it) and it seems to me that separate readers and writers would make duplex streams very awkward. Regardless, I don't intend to go very far down the I/O API design road without some mailing list discussion.

I've also started on the uv bindings for file I/O but haven't gotten very far.

Also hooked up the new scheduler to `rust_start` and the compiletest driver. 70% of run-pass test cases already pass, but I wouldn't read too much into that.

I also split the direct, low-level uv bindings in two so that the scheduler can have its own set, leaving `std::net` on its own.
  • Loading branch information
bors committed Mar 25, 2013
2 parents 6d4499c + 30d4124 commit ef282db
Show file tree
Hide file tree
Showing 29 changed files with 1,815 additions and 1,086 deletions.
2 changes: 1 addition & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ $(foreach target,$(CFG_TARGET_TRIPLES),\

CORELIB_CRATE := $(S)src/libcore/core.rc
CORELIB_INPUTS := $(wildcard $(addprefix $(S)src/libcore/, \
core.rc *.rs */*.rs))
core.rc *.rs */*.rs */*/*rs))

######################################################################
# Standard library variables
Expand Down
14 changes: 11 additions & 3 deletions mk/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -244,21 +244,29 @@ $(foreach host,$(CFG_HOST_TRIPLES), \

define TEST_RUNNER

# If NO_REBUILD is set then break the dependencies on std so we can
# test crates without rebuilding core and std first
ifeq ($(NO_REBUILD),)
STDTESTDEP_$(1)_$(2)_$(3) = $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_STDLIB_$(2))
else
STDTESTDEP_$(1)_$(2)_$(3) =
endif

$(3)/test/coretest.stage$(1)-$(2)$$(X_$(2)): \
$$(CORELIB_CRATE) $$(CORELIB_INPUTS) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_STDLIB_$(2))
$$(STDTESTDEP_$(1)_$(2)_$(3))
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test

$(3)/test/stdtest.stage$(1)-$(2)$$(X_$(2)): \
$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_STDLIB_$(2))
$$(STDTESTDEP_$(1)_$(2)_$(3))
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test

$(3)/test/syntaxtest.stage$(1)-$(2)$$(X_$(2)): \
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_STDLIB_$(2))
$$(STDTESTDEP_$(1)_$(2)_$(3))
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test

Expand Down
3 changes: 3 additions & 0 deletions src/compiletest/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ pub struct config {
// Run tests using the JIT
jit: bool,

// Run tests using the new runtime
newrt: bool,

// Explain what's going on
verbose: bool

Expand Down
5 changes: 4 additions & 1 deletion src/compiletest/compiletest.rc
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ pub fn parse_config(args: ~[~str]) -> config {
getopts::optopt(~"runtool"), getopts::optopt(~"rustcflags"),
getopts::optflag(~"verbose"),
getopts::optopt(~"logfile"),
getopts::optflag(~"jit")];
getopts::optflag(~"jit"),
getopts::optflag(~"newrt")];

fail_unless!(!args.is_empty());
let args_ = vec::tail(args);
Expand Down Expand Up @@ -95,6 +96,7 @@ pub fn parse_config(args: ~[~str]) -> config {
runtool: getopts::opt_maybe_str(matches, ~"runtool"),
rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"),
jit: getopts::opt_present(matches, ~"jit"),
newrt: getopts::opt_present(matches, ~"newrt"),
verbose: getopts::opt_present(matches, ~"verbose")
}
}
Expand All @@ -114,6 +116,7 @@ pub fn log_config(config: config) {
logv(c, fmt!("runtool: %s", opt_str(config.runtool)));
logv(c, fmt!("rustcflags: %s", opt_str(config.rustcflags)));
logv(c, fmt!("jit: %b", config.jit));
logv(c, fmt!("newrt: %b", config.newrt));
logv(c, fmt!("verbose: %b", config.verbose));
logv(c, fmt!("\n"));
}
Expand Down
10 changes: 9 additions & 1 deletion src/compiletest/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,17 @@ fn compile_test_(config: config, props: TestProps,

fn exec_compiled_test(config: config, props: TestProps,
testfile: &Path) -> ProcRes {

// If testing the new runtime then set the RUST_NEWRT env var
let env = if config.newrt {
props.exec_env + ~[(~"RUST_NEWRT", ~"1")]
} else {
props.exec_env
};

compose_and_run(config, testfile,
make_run_args(config, props, testfile),
props.exec_env,
env,
config.run_lib_path, None)
}

Expand Down
56 changes: 37 additions & 19 deletions src/libcore/rt/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use option::*;
use super::stack::StackSegment;
use libc::c_void;
use cast::{transmute, transmute_mut_unsafe,
Expand All @@ -16,17 +17,30 @@ use cast::{transmute, transmute_mut_unsafe,
// XXX: Registers is boxed so that it is 16-byte aligned, for storing
// SSE regs. It would be marginally better not to do this. In C++ we
// use an attribute on a struct.
pub struct Context(~Registers);
// XXX: It would be nice to define regs as `~Option<Registers>` since
// the registers are sometimes empty, but the discriminant would
// then misalign the regs again.
pub struct Context {
/// The context entry point, saved here for later destruction
start: Option<~~fn()>,
/// Hold the registers while the task or scheduler is suspended
regs: ~Registers
}

pub impl Context {
fn empty() -> Context {
Context(new_regs())
Context {
start: None,
regs: new_regs()
}
}

/// Create a new context that will resume execution by running ~fn()
/// # Safety Note
/// The `start` closure must remain valid for the life of the Task
fn new(start: &~fn(), stack: &mut StackSegment) -> Context {
fn new(start: ~fn(), stack: &mut StackSegment) -> Context {
// XXX: Putting main into a ~ so it's a thin pointer and can
// be passed to the spawn function. Another unfortunate
// allocation
let start = ~start;

// The C-ABI function that is the task entry point
extern fn task_start_wrapper(f: &~fn()) { (*f)() }
Expand All @@ -40,21 +54,29 @@ pub impl Context {
// which we will then modify to call the given function when restored
let mut regs = new_regs();
unsafe {
swap_registers(transmute_mut_region(&mut *regs),
transmute_region(&*regs))
swap_registers(transmute_mut_region(&mut *regs), transmute_region(&*regs))
};

initialize_call_frame(&mut *regs, fp, argp, sp);

return Context(regs);
return Context {
start: Some(start),
regs: regs
}
}

/* Switch contexts
Suspend the current execution context and resume another by
saving the registers values of the executing thread to a Context
then loading the registers from a previously saved Context.
*/
fn swap(out_context: &mut Context, in_context: &Context) {
let out_regs: &mut Registers = match out_context {
&Context(~ref mut r) => r
&Context { regs: ~ref mut r, _ } => r
};
let in_regs: &Registers = match in_context {
&Context(~ref r) => r
&Context { regs: ~ref r, _ } => r
};

unsafe { swap_registers(out_regs, in_regs) };
Expand Down Expand Up @@ -84,11 +106,10 @@ fn new_regs() -> ~Registers {
}

#[cfg(target_arch = "x86")]
fn initialize_call_frame(regs: &mut Registers,
fptr: *c_void, arg: *c_void, sp: *mut uint) {
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {

let sp = align_down(sp);
let sp = mut_offset(sp, -4); // XXX: -4 words? Needs this be done at all?
let sp = mut_offset(sp, -4);

unsafe { *sp = arg as uint; }
let sp = mut_offset(sp, -1);
Expand All @@ -108,8 +129,7 @@ type Registers = [uint * 22];
fn new_regs() -> ~Registers { ~[0, .. 22] }

#[cfg(target_arch = "x86_64")]
fn initialize_call_frame(regs: &mut Registers,
fptr: *c_void, arg: *c_void, sp: *mut uint) {
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {

// Redefinitions from regs.h
static RUSTRT_ARG0: uint = 3;
Expand Down Expand Up @@ -143,8 +163,7 @@ type Registers = [uint * 32];
fn new_regs() -> ~Registers { ~[0, .. 32] }

#[cfg(target_arch = "arm")]
fn initialize_call_frame(regs: &mut Registers,
fptr: *c_void, arg: *c_void, sp: *mut uint) {
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
let sp = mut_offset(sp, -1);

// The final return address. 0 indicates the bottom of the stack
Expand All @@ -162,8 +181,7 @@ type Registers = [uint * 32];
fn new_regs() -> ~Registers { ~[0, .. 32] }

#[cfg(target_arch = "mips")]
fn initialize_call_frame(regs: &mut Registers,
fptr: *c_void, arg: *c_void, sp: *mut uint) {
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) {
let sp = mut_offset(sp, -1);

// The final return address. 0 indicates the bottom of the stack
Expand Down
45 changes: 45 additions & 0 deletions src/libcore/rt/io/file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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::super::sched::*;
use super::super::rtio::*;
use super::Stream;

pub struct FileStream;

pub impl FileStream {
fn new(_path: Path) -> FileStream {
fail!()
}
}

impl Stream for FileStream {
fn read(&mut self, _buf: &mut [u8]) -> uint {
fail!()
}

fn eof(&mut self) -> bool {
fail!()
}

fn write(&mut self, _v: &const [u8]) {
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);
outstream.write(message.to_bytes());
}
45 changes: 45 additions & 0 deletions src/libcore/rt/io/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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 option::*;
use comm::{GenericPort, GenericChan};

pub mod file;

// FIXME #5370 Strongly want this to be StreamError(&mut Stream)
pub struct StreamError;

// 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;
}

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.
///
/// # Failure
///
/// Raises the `reader_error` condition on error
fn read(&mut self, buf: &mut [u8]) -> uint;

/// Return whether the Reader has reached the end of the stream
fn eof(&mut self) -> bool;

/// Write the given buffer
///
/// # Failure
///
/// Raises the `writer_error` condition on error
fn write(&mut self, v: &const [u8]);
}
41 changes: 30 additions & 11 deletions src/libcore/rt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc::c_char;

// Some basic logging
macro_rules! rtdebug_ (
($( $arg:expr),+) => ( {
dumb_println(fmt!( $($arg),+ ));

fn dumb_println(s: &str) {
use str::as_c_str;
use libc::c_char;

extern {
fn printf(s: *c_char);
}

do as_c_str(s.to_str() + "\n") |s| {
unsafe { printf(s); }
}
use io::WriterUtil;
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
dbg.write_str(s);
dbg.write_str("\n");
}

} )
Expand All @@ -36,13 +31,37 @@ macro_rules! rtdebug (
)

mod sched;
mod io;
mod rtio;
pub mod uvll;
mod uvio;
#[path = "uv/mod.rs"]
mod uv;
#[path = "io/mod.rs"]
mod io;
// FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
pub mod thread_local_storage;
mod work_queue;
mod stack;
mod context;
mod thread;
pub mod env;

pub fn start(main: *u8, _argc: int, _argv: *c_char, _crate_map: *u8) -> int {
use self::sched::{Scheduler, Task};
use self::uvio::UvEventLoop;

let loop_ = ~UvEventLoop::new();
let mut sched = ~Scheduler::new(loop_);
let main_task = ~do Task::new(&mut sched.stack_pool) {
// XXX: Can't call a C function pointer from Rust yet
unsafe { rust_call_nullary_fn(main) };
};
sched.task_queue.push_back(main_task);
sched.run();
return 0;

extern {
fn rust_call_nullary_fn(f: *u8);
}
}

File renamed without changes.
Loading

0 comments on commit ef282db

Please sign in to comment.