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

core: Add rt mod and add the new scheduler code #5303

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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