Skip to content

Commit

Permalink
auto merge of rust-lang#5303 : brson/rust/newsched4, r=brson
Browse files Browse the repository at this point in the history
r?

Followup to rust-lang#5022. This is the same, but everything is in `core::rt` now. `std::uv_ll` is moved to `core::unstable::uvll`, with the intent that it eventually move into its own crate (blocked on rust-lang#5192 at least). I've had to disable the uv tests because of rust-lang#2064. All of `core::rt` is disabled on platforms that aren't mac or linux until I complete the windows thread local storage bindings and ARM context switching.

My immediate next priorities will be to fix rust-lang#2064 and clean up the uv bindings, get everything building on all platforms.
  • Loading branch information
bors committed Mar 12, 2013
2 parents a6bb4a0 + 676e029 commit 48cb9a8
Show file tree
Hide file tree
Showing 26 changed files with 2,789 additions and 253 deletions.
3 changes: 2 additions & 1 deletion src/libcore/core.rc
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ pub mod unicode;
#[path = "num/cmath.rs"]
pub mod cmath;
pub mod stackwalk;

#[path = "rt/mod.rs"]
pub mod rt;

// A curious inner-module that's not exported that contains the binding
// 'core' so that macro-expanded references to core::error and such
Expand Down
38 changes: 38 additions & 0 deletions src/libcore/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,27 @@ pub pure fn get_ref<T>(opt: &r/Option<T>) -> &r/T {
}
}
pub pure fn get_mut_ref<T>(opt: &r/mut Option<T>) -> &r/mut T {
/*!
Gets a mutable reference to the value inside an option.
# Failure
Fails if the value equals `None`
# Safety note
In general, because this function may fail, its use is discouraged
(calling `get` on `None` is akin to dereferencing a null pointer).
Instead, prefer to use pattern matching and handle the `None`
case explicitly.
*/
match *opt {
Some(ref mut x) => x,
None => fail!(~"option::get_mut_ref none")
}
}
#[inline(always)]
pub pure fn map<T, U>(opt: &r/Option<T>, f: &fn(x: &r/T) -> U) -> Option<U> {
//! Maps a `some` value by reference from one type to another
Expand Down Expand Up @@ -364,6 +385,23 @@ pub impl<T> Option<T> {
#[inline(always)]
pure fn get_ref(&self) -> &self/T { get_ref(self) }
/**
Gets a mutable reference to the value inside an option.
# Failure
Fails if the value equals `None`
# Safety note
In general, because this function may fail, its use is discouraged
(calling `get` on `None` is akin to dereferencing a null pointer).
Instead, prefer to use pattern matching and handle the `None`
case explicitly.
*/
#[inline(always)]
pure fn get_mut_ref(&mut self) -> &self/mut T { get_mut_ref(self) }
/**
* Gets the value out of an option without copying.
*
Expand Down
156 changes: 156 additions & 0 deletions src/libcore/rt/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// 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 super::stack::StackSegment;
use libc::c_void;
use cast::{transmute, transmute_mut_unsafe,
transmute_region, transmute_mut_region};

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

pub impl Context {
static fn empty() -> Context {
Context(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
static fn new(start: &~fn(), stack: &mut StackSegment) -> Context {

// The C-ABI function that is the task entry point
extern fn task_start_wrapper(f: &~fn()) { (*f)() }

let fp: *c_void = task_start_wrapper as *c_void;
let argp: *c_void = unsafe { transmute::<&~fn(), *c_void>(&*start) };
let sp: *uint = stack.end();
let sp: *mut uint = unsafe { transmute_mut_unsafe(sp) };

// Save and then immediately load the current 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))
};

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

return Context(regs);
}

static fn swap(out_context: &mut Context, in_context: &Context) {
let out_regs: &mut Registers = match out_context {
&Context(~ref mut r) => r
};
let in_regs: &Registers = match in_context {
&Context(~ref r) => r
};

unsafe { swap_registers(out_regs, in_regs) };
}
}

extern {
fn swap_registers(out_regs: *mut Registers, in_regs: *Registers);
}

// Definitions of these registers are in rt/arch/x86_64/regs.h
#[cfg(target_arch = "x86_64")]
type Registers = [uint * 22];

#[cfg(target_arch = "x86_64")]
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) {

// Redefinitions from regs.h
const RUSTRT_ARG0: uint = 3;
const RUSTRT_RSP: uint = 1;
const RUSTRT_IP: uint = 8;
const RUSTRT_RBP: uint = 2;

let sp = align_down(sp);
let sp = mut_offset(sp, -1);

// The final return address. 0 indicates the bottom of the stack
unsafe { *sp = 0; }

rtdebug!("creating call frame");
rtdebug!("fptr %x", fptr as uint);
rtdebug!("arg %x", arg as uint);
rtdebug!("sp %x", sp as uint);

regs[RUSTRT_ARG0] = arg as uint;
regs[RUSTRT_RSP] = sp as uint;
regs[RUSTRT_IP] = fptr as uint;

// Last base pointer on the stack should be 0
regs[RUSTRT_RBP] = 0;
}

#[cfg(target_arch = "x86")]
struct Registers {
eax: u32, ebx: u32, ecx: u32, edx: u32,
ebp: u32, esi: u32, edi: u32, esp: u32,
cs: u16, ds: u16, ss: u16, es: u16, fs: u16, gs: u16,
eflags: u32, eip: u32
}

#[cfg(target_arch = "x86")]
fn new_regs() -> ~Registers {
~Registers {
eax: 0, ebx: 0, ecx: 0, edx: 0,
ebp: 0, esi: 0, edi: 0, esp: 0,
cs: 0, ds: 0, ss: 0, es: 0, fs: 0, gs: 0,
eflags: 0, eip: 0
}
}

#[cfg(target_arch = "x86")]
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?

unsafe { *sp = arg as uint; }
let sp = mut_offset(sp, -1);
unsafe { *sp = 0; } // The final return address

regs.esp = sp as u32;
regs.eip = fptr as u32;

// Last base pointer on the stack is 0
regs.ebp = 0;
}

fn align_down(sp: *mut uint) -> *mut uint {
unsafe {
let sp = transmute::<*mut uint, uint>(sp);
let sp = sp & !(16 - 1);
transmute::<uint, *mut uint>(sp)
}
}

// XXX: ptr::offset is positive ints only
#[inline(always)]
pub pure fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
use core::sys::size_of;
unsafe {
(ptr as int + count * (size_of::<T>() as int)) as *mut T
}
}

45 changes: 45 additions & 0 deletions src/libcore/rt/io.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 result::*;

// XXX: ~object doesn't work currently so these are some placeholder
// types to use instead
pub type EventLoopObject = super::uvio::UvEventLoop;
pub type IoFactoryObject = super::uvio::UvIoFactory;
pub type StreamObject = super::uvio::UvStream;
pub type TcpListenerObject = super::uvio::UvTcpListener;

pub trait EventLoop {
fn run(&mut self);
fn callback(&mut self, ~fn());
/// The asynchronous I/O services. Not all event loops may provide one
fn io(&mut self) -> Option<&self/mut IoFactoryObject>;
}

pub trait IoFactory {
fn connect(&mut self, addr: IpAddr) -> Option<~StreamObject>;
fn bind(&mut self, addr: IpAddr) -> Option<~TcpListenerObject>;
}

pub trait TcpListener {
fn listen(&mut self) -> Option<~StreamObject>;
}

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
}
51 changes: 51 additions & 0 deletions src/libcore/rt/mod.rs
Original file line number Diff line number Diff line change
@@ -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.

// XXX: Missing some implementation for other architectures
#[cfg(target_os = "linux")];
#[cfg(target_os = "mac")];
#[cfg(target_os = "win32")];

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

} )
)

// An alternate version with no output, for turning off logging
macro_rules! rtdebug_ (
($( $arg:expr),+) => ( $(let _ = $arg)*; )
)

mod sched;
mod io;
mod uvio;
mod uv;
// 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;
Loading

0 comments on commit 48cb9a8

Please sign in to comment.