Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More scheduler and I/O work #5409

Closed
wants to merge 13 commits into from
Closed
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! {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A note here, as I've seen a few conditions getting written this way lately: there's seldom a need to have a return value from a condition that tells the raise-site that it should fail; the handler itself can just fail (and indeed, untrapped conditions already fail). There's just as much context (more actually) visible to a backtrace if you let the handler / absence-of-handler itself fail.

Generally the only things that should show up in the return slot of a condition are data to use for recovery-and-continuation: sentinel values or replacement values, things that represent the handler saying "oh, well, use this value instead". If no such data is required or plausible (i.e. if the only reasonable thing one might do to recover is "ignore the error") then just put () in the return slot. If control proceeds past the condition.raise() line, you know a caller trapped the error and wants you to ignore it and continue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I'll make this not return a bool.

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