Test fixes and rebase conflicts
* vec::raw::to_ptr is gone * Pausible => Pausable * Removing @ * Calling the main task "<main>" * Removing unused imports * Removing unused mut * Bringing some libextra tests up to date * Allowing compiletest to work at stage0 * Fixing the bootstrap-from-c rmake tests * assert => rtassert in a few cases * printing to stderr instead of stdout in fail!()
This commit is contained in:
parent
b47ff23673
commit
6cad8f4f14
@ -13,6 +13,7 @@
|
||||
#[allow(non_camel_case_types)];
|
||||
#[deny(warnings)];
|
||||
|
||||
#[cfg(stage0)] extern mod green;
|
||||
extern mod extra;
|
||||
|
||||
use std::os;
|
||||
|
@ -96,7 +96,6 @@ pub fn rendezvous<T: Send>() -> (SyncPort<T>, SyncChan<T>) {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use comm::{DuplexStream, rendezvous};
|
||||
use std::rt::test::run_in_uv_task;
|
||||
|
||||
|
||||
#[test]
|
||||
@ -124,13 +123,11 @@ mod test {
|
||||
#[test]
|
||||
fn recv_a_lot() {
|
||||
// Rendezvous streams should be able to handle any number of messages being sent
|
||||
do run_in_uv_task {
|
||||
let (port, chan) = rendezvous();
|
||||
do spawn {
|
||||
1000000.times(|| { chan.send(()) })
|
||||
}
|
||||
1000000.times(|| { port.recv() })
|
||||
let (port, chan) = rendezvous();
|
||||
do spawn {
|
||||
1000000.times(|| { chan.send(()) })
|
||||
}
|
||||
1000000.times(|| { port.recv() })
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -761,23 +761,21 @@ mod tests {
|
||||
fn test_sem_runtime_friendly_blocking() {
|
||||
// Force the runtime to schedule two threads on the same sched_loop.
|
||||
// When one blocks, it should schedule the other one.
|
||||
do task::spawn_sched(task::SingleThreaded) {
|
||||
let s = Semaphore::new(1);
|
||||
let s2 = s.clone();
|
||||
let (p, c) = Chan::new();
|
||||
let mut child_data = Some((s2, c));
|
||||
s.access(|| {
|
||||
let (s2, c) = child_data.take_unwrap();
|
||||
do task::spawn {
|
||||
c.send(());
|
||||
s2.access(|| { });
|
||||
c.send(());
|
||||
}
|
||||
let _ = p.recv(); // wait for child to come alive
|
||||
5.times(|| { task::deschedule(); }); // let the child contend
|
||||
});
|
||||
let _ = p.recv(); // wait for child to be done
|
||||
}
|
||||
let s = Semaphore::new(1);
|
||||
let s2 = s.clone();
|
||||
let (p, c) = Chan::new();
|
||||
let mut child_data = Some((s2, c));
|
||||
s.access(|| {
|
||||
let (s2, c) = child_data.take_unwrap();
|
||||
do task::spawn {
|
||||
c.send(());
|
||||
s2.access(|| { });
|
||||
c.send(());
|
||||
}
|
||||
let _ = p.recv(); // wait for child to come alive
|
||||
5.times(|| { task::deschedule(); }); // let the child contend
|
||||
});
|
||||
let _ = p.recv(); // wait for child to be done
|
||||
}
|
||||
/************************************************************************
|
||||
* Mutex tests
|
||||
|
@ -17,8 +17,6 @@
|
||||
use std::task;
|
||||
use std::vec;
|
||||
|
||||
#[cfg(test)] use std::task::SingleThreaded;
|
||||
|
||||
enum Msg<T> {
|
||||
Execute(proc(&T)),
|
||||
Quit
|
||||
|
@ -16,7 +16,7 @@
|
||||
//! loop if no other one is provided (and M:N scheduling is desired).
|
||||
|
||||
use std::cast;
|
||||
use std::rt::rtio::{EventLoop, IoFactory, RemoteCallback, PausibleIdleCallback,
|
||||
use std::rt::rtio::{EventLoop, IoFactory, RemoteCallback, PausableIdleCallback,
|
||||
Callback};
|
||||
use std::unstable::sync::Exclusive;
|
||||
use std::util;
|
||||
|
@ -18,12 +18,7 @@
|
||||
//! functionality inside of 1:1 programs.
|
||||
|
||||
#[pkgid = "green#0.9-pre"];
|
||||
#[link(name = "green",
|
||||
package_id = "green",
|
||||
vers = "0.9-pre",
|
||||
uuid = "20c38f8c-bfea-83ed-a068-9dc05277be26",
|
||||
url = "https://github.com/mozilla/rust/tree/master/src/libgreen")];
|
||||
|
||||
#[crate_id = "green#0.9-pre"];
|
||||
#[license = "MIT/ASL2"];
|
||||
#[crate_type = "rlib"];
|
||||
#[crate_type = "dylib"];
|
||||
@ -61,16 +56,13 @@ pub mod stack;
|
||||
pub mod task;
|
||||
|
||||
#[lang = "start"]
|
||||
#[cfg(not(test))]
|
||||
pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int {
|
||||
use std::cast;
|
||||
let mut ret = None;
|
||||
simple::task().run(|| {
|
||||
ret = Some(do start(argc, argv) {
|
||||
let main: extern "Rust" fn() = unsafe { cast::transmute(main) };
|
||||
main();
|
||||
})
|
||||
});
|
||||
ret.unwrap()
|
||||
do start(argc, argv) {
|
||||
let main: extern "Rust" fn() = unsafe { cast::transmute(main) };
|
||||
main();
|
||||
}
|
||||
}
|
||||
|
||||
/// Set up a default runtime configuration, given compiler-supplied arguments.
|
||||
@ -93,10 +85,14 @@ pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int {
|
||||
/// error.
|
||||
pub fn start(argc: int, argv: **u8, main: proc()) -> int {
|
||||
rt::init(argc, argv);
|
||||
let exit_code = run(main);
|
||||
let mut main = Some(main);
|
||||
let mut ret = None;
|
||||
simple::task().run(|| {
|
||||
ret = Some(run(main.take_unwrap()));
|
||||
});
|
||||
// unsafe is ok b/c we're sure that the runtime is gone
|
||||
unsafe { rt::cleanup() }
|
||||
exit_code
|
||||
ret.unwrap()
|
||||
}
|
||||
|
||||
/// Execute the main function in a pool of M:N schedulers.
|
||||
@ -114,6 +110,7 @@ pub fn run(main: proc()) -> int {
|
||||
let (port, chan) = Chan::new();
|
||||
let mut opts = TaskOpts::new();
|
||||
opts.notify_chan = Some(chan);
|
||||
opts.name = Some(SendStrStatic("<main>"));
|
||||
pool.spawn(opts, main);
|
||||
|
||||
// Wait for the main task to return, and set the process error code
|
||||
|
@ -54,14 +54,13 @@ macro_rules! rtabort (
|
||||
pub fn dumb_println(args: &fmt::Arguments) {
|
||||
use std::io;
|
||||
use std::libc;
|
||||
use std::vec;
|
||||
|
||||
struct Stderr;
|
||||
impl io::Writer for Stderr {
|
||||
fn write(&mut self, data: &[u8]) {
|
||||
unsafe {
|
||||
libc::write(libc::STDERR_FILENO,
|
||||
vec::raw::to_ptr(data) as *libc::c_void,
|
||||
data.as_ptr() as *libc::c_void,
|
||||
data.len() as libc::size_t);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
use std::cast;
|
||||
use std::rand::{XorShiftRng, Rng, Rand};
|
||||
use std::rt::local::Local;
|
||||
use std::rt::rtio::{RemoteCallback, PausibleIdleCallback, Callback, EventLoop};
|
||||
use std::rt::rtio::{RemoteCallback, PausableIdleCallback, Callback, EventLoop};
|
||||
use std::rt::task::BlockedTask;
|
||||
use std::rt::task::Task;
|
||||
use std::sync::deque;
|
||||
@ -779,6 +779,9 @@ impl Scheduler {
|
||||
/// randomness is a result of performing a round of work stealing (which
|
||||
/// may end up stealing from the current scheduler).
|
||||
pub fn yield_now(mut ~self, cur: ~GreenTask) {
|
||||
// Async handles trigger the scheduler by calling yield_now on the local
|
||||
// task, which eventually gets us to here. See comments in SchedRunner
|
||||
// for more info on this.
|
||||
if cur.is_sched() {
|
||||
assert!(self.sched_task.is_none());
|
||||
self.run_sched_once(cur);
|
||||
@ -1345,7 +1348,7 @@ mod test {
|
||||
|
||||
impl Drop for S {
|
||||
fn drop(&mut self) {
|
||||
let _foo = @0;
|
||||
let _foo = ~0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cast;
|
||||
use std::io;
|
||||
use std::libc::{pid_t, c_void, c_int};
|
||||
use std::libc;
|
||||
@ -17,6 +16,8 @@ use std::ptr;
|
||||
use std::rt::rtio;
|
||||
use p = std::io::process;
|
||||
|
||||
#[cfg(windows)] use std::cast;
|
||||
|
||||
use super::file;
|
||||
|
||||
/**
|
||||
|
@ -15,12 +15,7 @@
|
||||
//! version of I/O.
|
||||
|
||||
#[pkgid = "native#0.9-pre"];
|
||||
#[link(name = "native",
|
||||
package_id = "native",
|
||||
vers = "0.9-pre",
|
||||
uuid = "535344a7-890f-5a23-e1f3-e0d118805141",
|
||||
url = "https://github.com/mozilla/rust/tree/master/src/native")];
|
||||
|
||||
#[crate_id = "native#0.9-pre"];
|
||||
#[license = "MIT/ASL2"];
|
||||
#[crate_type = "rlib"];
|
||||
#[crate_type = "dylib"];
|
||||
@ -46,7 +41,7 @@ pub mod task;
|
||||
#[lang = "start"]
|
||||
pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int {
|
||||
use std::cast;
|
||||
use std::task::try;
|
||||
use std::task;
|
||||
|
||||
do start(argc, argv) {
|
||||
// Instead of invoking main directly on this thread, invoke it on
|
||||
@ -55,7 +50,9 @@ pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int {
|
||||
// of the main thread's stack, so for stack overflow detection to work
|
||||
// we must spawn the task in a subtask which we know the stack size of.
|
||||
let main: extern "Rust" fn() = unsafe { cast::transmute(main) };
|
||||
match do try { main() } {
|
||||
let mut task = task::task();
|
||||
task.name("<main>");
|
||||
match do task.try { main() } {
|
||||
Ok(()) => { os::set_exit_status(0); }
|
||||
Err(..) => { os::set_exit_status(rt::DEFAULT_ERROR_CODE); }
|
||||
}
|
||||
|
@ -333,6 +333,10 @@ pub mod write {
|
||||
}
|
||||
|
||||
unsafe fn configure_llvm(sess: Session) {
|
||||
use std::unstable::mutex::{MUTEX_INIT, Mutex};
|
||||
static mut LOCK: Mutex = MUTEX_INIT;
|
||||
static mut CONFIGURED: bool = false;
|
||||
|
||||
// Copy what clan does by turning on loop vectorization at O2 and
|
||||
// slp vectorization at O3
|
||||
let vectorize_loop = !sess.no_vectorize_loops() &&
|
||||
@ -360,7 +364,13 @@ pub mod write {
|
||||
add(*arg);
|
||||
}
|
||||
|
||||
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
|
||||
LOCK.lock();
|
||||
if !CONFIGURED {
|
||||
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
|
||||
llvm_args.as_ptr());
|
||||
CONFIGURED = true;
|
||||
}
|
||||
LOCK.unlock();
|
||||
}
|
||||
|
||||
unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
|
||||
|
@ -487,8 +487,9 @@ fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path {
|
||||
}
|
||||
|
||||
fn output_file_name(workspace: &Path, short_name: ~str) -> Path {
|
||||
target_build_dir(workspace).join(short_name.as_slice()).join(format!("{}{}", short_name,
|
||||
os::EXE_SUFFIX))
|
||||
target_build_dir(workspace).join(short_name.as_slice())
|
||||
.join(format!("{}{}", short_name,
|
||||
os::consts::EXE_SUFFIX))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
@ -1353,7 +1354,7 @@ fn test_import_rustpkg() {
|
||||
command_line_test([~"build", ~"foo"], workspace);
|
||||
debug!("workspace = {}", workspace.display());
|
||||
assert!(target_build_dir(workspace).join("foo").join(format!("pkg{}",
|
||||
os::EXE_SUFFIX)).exists());
|
||||
os::consts::EXE_SUFFIX)).exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1366,7 +1367,7 @@ fn test_macro_pkg_script() {
|
||||
command_line_test([~"build", ~"foo"], workspace);
|
||||
debug!("workspace = {}", workspace.display());
|
||||
assert!(target_build_dir(workspace).join("foo").join(format!("pkg{}",
|
||||
os::EXE_SUFFIX)).exists());
|
||||
os::consts::EXE_SUFFIX)).exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -18,7 +18,6 @@ use std::rt::task::BlockedTask;
|
||||
use std::io::{FileStat, IoError};
|
||||
use std::io;
|
||||
use std::rt::rtio;
|
||||
use std::vec;
|
||||
|
||||
use homing::{HomingIO, HomeHandle};
|
||||
use super::{Loop, UvError, uv_error_to_io_error, wait_until_woken_after, wakeup};
|
||||
|
@ -100,7 +100,7 @@ mod test {
|
||||
use std::cast;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::rt::rtio::{Callback, PausibleIdleCallback};
|
||||
use std::rt::rtio::{Callback, PausableIdleCallback};
|
||||
use std::rt::task::{BlockedTask, Task};
|
||||
use std::rt::local::Local;
|
||||
use super::IdleWatcher;
|
||||
|
@ -30,14 +30,13 @@ macro_rules! uvdebug (
|
||||
pub fn dumb_println(args: &fmt::Arguments) {
|
||||
use std::io;
|
||||
use std::libc;
|
||||
use std::vec;
|
||||
|
||||
struct Stderr;
|
||||
impl io::Writer for Stderr {
|
||||
fn write(&mut self, data: &[u8]) {
|
||||
unsafe {
|
||||
libc::write(libc::STDERR_FILENO,
|
||||
vec::raw::to_ptr(data) as *libc::c_void,
|
||||
data.as_ptr() as *libc::c_void,
|
||||
data.len() as libc::size_t);
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ impl RtioSignal for SignalWatcher {}
|
||||
impl Drop for SignalWatcher {
|
||||
fn drop(&mut self) {
|
||||
let _m = self.fire_homing_missile();
|
||||
self.close_async_();
|
||||
self.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ impl Drop for TimerWatcher {
|
||||
let _action = {
|
||||
let _m = self.fire_homing_missile();
|
||||
self.stop();
|
||||
self.close_async_();
|
||||
self.close();
|
||||
self.action.take()
|
||||
};
|
||||
}
|
||||
|
@ -86,10 +86,10 @@ impl rtio::EventLoop for UvEventLoop {
|
||||
IdleWatcher::onetime(&mut self.uvio.loop_, f);
|
||||
}
|
||||
|
||||
fn pausible_idle_callback(&mut self, cb: ~rtio::Callback)
|
||||
-> ~rtio::PausibleIdleCallback
|
||||
fn pausable_idle_callback(&mut self, cb: ~rtio::Callback)
|
||||
-> ~rtio::PausableIdleCallback
|
||||
{
|
||||
IdleWatcher::new(&mut self.uvio.loop_, cb) as ~rtio::PausibleIdleCallback
|
||||
IdleWatcher::new(&mut self.uvio.loop_, cb) as ~rtio::PausableIdleCallback
|
||||
}
|
||||
|
||||
fn remote_callback(&mut self, f: ~rtio::Callback) -> ~rtio::RemoteCallback {
|
||||
|
@ -175,7 +175,8 @@ mod tests {
|
||||
fn connect_error() {
|
||||
let mut called = false;
|
||||
io_error::cond.trap(|e| {
|
||||
assert_eq!(e.kind, OtherIoError);
|
||||
assert_eq!(e.kind,
|
||||
if cfg!(windows) {OtherIoError} else {FileNotFound});
|
||||
called = true;
|
||||
}).inside(|| {
|
||||
let stream = UnixStream::connect(&("path/to/nowhere"));
|
||||
|
@ -34,7 +34,6 @@ use libc;
|
||||
use option::{Option, Some, None};
|
||||
use result::{Ok, Err};
|
||||
use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
|
||||
use vec;
|
||||
|
||||
// And so begins the tale of acquiring a uv handle to a stdio stream on all
|
||||
// platforms in all situations. Our story begins by splitting the world into two
|
||||
@ -137,7 +136,7 @@ fn with_task_stdout(f: |&mut Writer|) {
|
||||
fn write(&mut self, data: &[u8]) {
|
||||
unsafe {
|
||||
libc::write(libc::STDOUT_FILENO,
|
||||
vec::raw::to_ptr(data) as *libc::c_void,
|
||||
data.as_ptr() as *libc::c_void,
|
||||
data.len() as libc::size_t);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ macro_rules! iotest (
|
||||
use io::net::tcp::*;
|
||||
use io::net::ip::*;
|
||||
use io::net::udp::*;
|
||||
#[cfg(unix)]
|
||||
use io::net::unix::*;
|
||||
use str;
|
||||
use util;
|
||||
|
@ -42,7 +42,7 @@ impl<T> Drop for Borrowed<T> {
|
||||
}
|
||||
let val: ~T = cast::transmute(self.val);
|
||||
put::<T>(val);
|
||||
assert!(exists());
|
||||
rtassert!(exists());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,7 +110,7 @@ pub mod compiled {
|
||||
#[inline]
|
||||
pub unsafe fn take<T>() -> ~T {
|
||||
let ptr = RT_TLS_PTR;
|
||||
assert!(!ptr.is_null());
|
||||
rtassert!(!ptr.is_null());
|
||||
let ptr: ~T = cast::transmute(ptr);
|
||||
// can't use `as`, due to type not matching with `cfg(test)`
|
||||
RT_TLS_PTR = cast::transmute(0);
|
||||
@ -180,7 +180,7 @@ pub mod native {
|
||||
}
|
||||
|
||||
pub unsafe fn cleanup() {
|
||||
assert!(INITIALIZED);
|
||||
rtassert!(INITIALIZED);
|
||||
tls::destroy(RT_TLS_KEY);
|
||||
LOCK.destroy();
|
||||
INITIALIZED = false;
|
||||
|
@ -176,6 +176,7 @@ pub fn init(argc: int, argv: **u8) {
|
||||
args::init(argc, argv);
|
||||
env::init();
|
||||
logging::init();
|
||||
local_ptr::init();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,14 +95,16 @@ impl<'a> LocalIo<'a> {
|
||||
/// Returns the local I/O: either the local scheduler's I/O services or
|
||||
/// the native I/O services.
|
||||
pub fn borrow() -> Option<LocalIo> {
|
||||
// XXX: This is currently very unsafely implemented. We don't actually
|
||||
// *take* the local I/O so there's a very real possibility that we
|
||||
// can have two borrows at once. Currently there is not a clear way
|
||||
// to actually borrow the local I/O factory safely because even if
|
||||
// ownership were transferred down to the functions that the I/O
|
||||
// factory implements it's just too much of a pain to know when to
|
||||
// relinquish ownership back into the local task (but that would be
|
||||
// the safe way of implementing this function).
|
||||
// FIXME(#11053): bad
|
||||
//
|
||||
// This is currently very unsafely implemented. We don't actually
|
||||
// *take* the local I/O so there's a very real possibility that we
|
||||
// can have two borrows at once. Currently there is not a clear way
|
||||
// to actually borrow the local I/O factory safely because even if
|
||||
// ownership were transferred down to the functions that the I/O
|
||||
// factory implements it's just too much of a pain to know when to
|
||||
// relinquish ownership back into the local task (but that would be
|
||||
// the safe way of implementing this function).
|
||||
//
|
||||
// In order to get around this, we just transmute a copy out of the task
|
||||
// in order to have what is likely a static lifetime (bad).
|
||||
|
@ -15,9 +15,10 @@
|
||||
|
||||
use any::AnyOwnExt;
|
||||
use borrow;
|
||||
use cast;
|
||||
use cleanup;
|
||||
use io::Writer;
|
||||
use libc::{c_char, size_t};
|
||||
use iter::{Iterator, Take};
|
||||
use local_data;
|
||||
use ops::Drop;
|
||||
use option::{Option, Some, None};
|
||||
@ -488,7 +489,10 @@ mod test {
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_begin_unwind() { begin_unwind("cause", file!(), line!()) }
|
||||
fn test_begin_unwind() {
|
||||
use rt::unwind::begin_unwind;
|
||||
begin_unwind("cause", file!(), line!())
|
||||
}
|
||||
|
||||
// Task blocking tests
|
||||
|
||||
|
@ -144,15 +144,11 @@ impl<T: Send> Drop for Thread<T> {
|
||||
|
||||
#[cfg(windows)]
|
||||
mod imp {
|
||||
use super::DEFAULT_STACK_SIZE;
|
||||
|
||||
use cast;
|
||||
use libc;
|
||||
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL,
|
||||
LPVOID, DWORD, LPDWORD, HANDLE};
|
||||
use ptr;
|
||||
use libc;
|
||||
use cast;
|
||||
|
||||
pub type rust_thread = HANDLE;
|
||||
pub type rust_thread_return = DWORD;
|
||||
|
@ -10,8 +10,9 @@
|
||||
|
||||
// Implementation of Rust stack unwinding
|
||||
//
|
||||
// For background on exception handling and stack unwinding please see "Exception Handling in LLVM"
|
||||
// (llvm.org/docs/ExceptionHandling.html) and documents linked from it.
|
||||
// For background on exception handling and stack unwinding please see
|
||||
// "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
|
||||
// documents linked from it.
|
||||
// These are also good reads:
|
||||
// http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
|
||||
// http://monoinfinito.wordpress.com/series/exception-handling-in-c/
|
||||
@ -20,41 +21,55 @@
|
||||
// ~~~ A brief summary ~~~
|
||||
// Exception handling happens in two phases: a search phase and a cleanup phase.
|
||||
//
|
||||
// In both phases the unwinder walks stack frames from top to bottom using information from
|
||||
// the stack frame unwind sections of the current process's modules ("module" here refers to
|
||||
// an OS module, i.e. an executable or a dynamic library).
|
||||
// In both phases the unwinder walks stack frames from top to bottom using
|
||||
// information from the stack frame unwind sections of the current process's
|
||||
// modules ("module" here refers to an OS module, i.e. an executable or a
|
||||
// dynamic library).
|
||||
//
|
||||
// For each stack frame, it invokes the associated "personality routine", whose address is also
|
||||
// stored in the unwind info section.
|
||||
// For each stack frame, it invokes the associated "personality routine", whose
|
||||
// address is also stored in the unwind info section.
|
||||
//
|
||||
// In the search phase, the job of a personality routine is to examine exception object being
|
||||
// thrown, and to decide whether it should be caught at that stack frame. Once the handler frame
|
||||
// has been identified, cleanup phase begins.
|
||||
// In the search phase, the job of a personality routine is to examine exception
|
||||
// object being thrown, and to decide whether it should be caught at that stack
|
||||
// frame. Once the handler frame has been identified, cleanup phase begins.
|
||||
//
|
||||
// In the cleanup phase, personality routines invoke cleanup code associated with their
|
||||
// stack frames (i.e. destructors). Once stack has been unwound down to the handler frame level,
|
||||
// unwinding stops and the last personality routine transfers control to its' catch block.
|
||||
// In the cleanup phase, personality routines invoke cleanup code associated
|
||||
// with their stack frames (i.e. destructors). Once stack has been unwound down
|
||||
// to the handler frame level, unwinding stops and the last personality routine
|
||||
// transfers control to its' catch block.
|
||||
//
|
||||
// ~~~ Frame unwind info registration ~~~
|
||||
// Each module has its' own frame unwind info section (usually ".eh_frame"), and unwinder needs
|
||||
// to know about all of them in order for unwinding to be able to cross module boundaries.
|
||||
// Each module has its' own frame unwind info section (usually ".eh_frame"), and
|
||||
// unwinder needs to know about all of them in order for unwinding to be able to
|
||||
// cross module boundaries.
|
||||
//
|
||||
// On some platforms, like Linux, this is achieved by dynamically enumerating currently loaded
|
||||
// modules via the dl_iterate_phdr() API and finding all .eh_frame sections.
|
||||
// On some platforms, like Linux, this is achieved by dynamically enumerating
|
||||
// currently loaded modules via the dl_iterate_phdr() API and finding all
|
||||
// .eh_frame sections.
|
||||
//
|
||||
// Others, like Windows, require modules to actively register their unwind info sections by calling
|
||||
// __register_frame_info() API at startup.
|
||||
// In the latter case it is essential that there is only one copy of the unwinder runtime
|
||||
// in the process. This is usually achieved by linking to the dynamic version of the unwind
|
||||
// runtime.
|
||||
// Others, like Windows, require modules to actively register their unwind info
|
||||
// sections by calling __register_frame_info() API at startup. In the latter
|
||||
// case it is essential that there is only one copy of the unwinder runtime in
|
||||
// the process. This is usually achieved by linking to the dynamic version of
|
||||
// the unwind runtime.
|
||||
//
|
||||
// Currently Rust uses unwind runtime provided by libgcc.
|
||||
|
||||
use prelude::*;
|
||||
use cast::transmute;
|
||||
use task::TaskResult;
|
||||
use any::{Any, AnyRefExt};
|
||||
use c_str::CString;
|
||||
use cast;
|
||||
use kinds::Send;
|
||||
use libc::{c_char, size_t};
|
||||
use libc::{c_void, c_int};
|
||||
use self::libunwind::*;
|
||||
use option::{Some, None, Option};
|
||||
use result::{Err, Ok};
|
||||
use rt::local::Local;
|
||||
use rt::task::Task;
|
||||
use str::Str;
|
||||
use task::TaskResult;
|
||||
use unstable::intrinsics;
|
||||
|
||||
use uw = self::libunwind;
|
||||
|
||||
mod libunwind {
|
||||
//! Unwind library interface
|
||||
@ -109,34 +124,41 @@ mod libunwind {
|
||||
}
|
||||
|
||||
pub struct Unwinder {
|
||||
unwinding: bool,
|
||||
cause: Option<~Any>
|
||||
priv unwinding: bool,
|
||||
priv cause: Option<~Any>
|
||||
}
|
||||
|
||||
impl Unwinder {
|
||||
pub fn new() -> Unwinder {
|
||||
Unwinder {
|
||||
unwinding: false,
|
||||
cause: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwinding(&self) -> bool {
|
||||
self.unwinding
|
||||
}
|
||||
|
||||
pub fn try(&mut self, f: ||) {
|
||||
use unstable::raw::Closure;
|
||||
|
||||
unsafe {
|
||||
let closure: Closure = transmute(f);
|
||||
let code = transmute(closure.code);
|
||||
let env = transmute(closure.env);
|
||||
|
||||
let ep = rust_try(try_fn, code, env);
|
||||
let closure: Closure = cast::transmute(f);
|
||||
let ep = rust_try(try_fn, closure.code as *c_void,
|
||||
closure.env as *c_void);
|
||||
if !ep.is_null() {
|
||||
rtdebug!("Caught {}", (*ep).exception_class);
|
||||
_Unwind_DeleteException(ep);
|
||||
uw::_Unwind_DeleteException(ep);
|
||||
}
|
||||
}
|
||||
|
||||
extern fn try_fn(code: *c_void, env: *c_void) {
|
||||
unsafe {
|
||||
let closure: Closure = Closure {
|
||||
code: transmute(code),
|
||||
env: transmute(env),
|
||||
};
|
||||
let closure: || = transmute(closure);
|
||||
let closure: || = cast::transmute(Closure {
|
||||
code: code as *(),
|
||||
env: env as *(),
|
||||
});
|
||||
closure();
|
||||
}
|
||||
}
|
||||
@ -144,10 +166,11 @@ impl Unwinder {
|
||||
extern {
|
||||
// Rust's try-catch
|
||||
// When f(...) returns normally, the return value is null.
|
||||
// When f(...) throws, the return value is a pointer to the caught exception object.
|
||||
// When f(...) throws, the return value is a pointer to the caught
|
||||
// exception object.
|
||||
fn rust_try(f: extern "C" fn(*c_void, *c_void),
|
||||
code: *c_void,
|
||||
data: *c_void) -> *_Unwind_Exception;
|
||||
data: *c_void) -> *uw::_Unwind_Exception;
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,21 +181,21 @@ impl Unwinder {
|
||||
self.cause = Some(cause);
|
||||
|
||||
unsafe {
|
||||
let exception = ~_Unwind_Exception {
|
||||
let exception = ~uw::_Unwind_Exception {
|
||||
exception_class: rust_exception_class(),
|
||||
exception_cleanup: exception_cleanup,
|
||||
private_1: 0,
|
||||
private_2: 0
|
||||
};
|
||||
let error = _Unwind_RaiseException(transmute(exception));
|
||||
let error = uw::_Unwind_RaiseException(cast::transmute(exception));
|
||||
rtabort!("Could not unwind stack, error = {}", error as int)
|
||||
}
|
||||
|
||||
extern "C" fn exception_cleanup(_unwind_code: _Unwind_Reason_Code,
|
||||
exception: *_Unwind_Exception) {
|
||||
extern "C" fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
||||
exception: *uw::_Unwind_Exception) {
|
||||
rtdebug!("exception_cleanup()");
|
||||
unsafe {
|
||||
let _: ~_Unwind_Exception = transmute(exception);
|
||||
let _: ~uw::_Unwind_Exception = cast::transmute(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,68 +211,75 @@ impl Unwinder {
|
||||
|
||||
// Rust's exception class identifier. This is used by personality routines to
|
||||
// determine whether the exception was thrown by their own runtime.
|
||||
fn rust_exception_class() -> _Unwind_Exception_Class {
|
||||
let bytes = bytes!("MOZ\0RUST"); // vendor, language
|
||||
unsafe {
|
||||
let ptr: *_Unwind_Exception_Class = transmute(bytes.as_ptr());
|
||||
*ptr
|
||||
}
|
||||
fn rust_exception_class() -> uw::_Unwind_Exception_Class {
|
||||
// M O Z \0 R U S T -- vendor, language
|
||||
0x4d4f5a_00_52555354
|
||||
}
|
||||
|
||||
|
||||
// We could implement our personality routine in pure Rust, however exception info decoding
|
||||
// is tedious. More importantly, personality routines have to handle various platform
|
||||
// quirks, which are not fun to maintain. For this reason, we attempt to reuse personality
|
||||
// routine of the C language: __gcc_personality_v0.
|
||||
// We could implement our personality routine in pure Rust, however exception
|
||||
// info decoding is tedious. More importantly, personality routines have to
|
||||
// handle various platform quirks, which are not fun to maintain. For this
|
||||
// reason, we attempt to reuse personality routine of the C language:
|
||||
// __gcc_personality_v0.
|
||||
//
|
||||
// Since C does not support exception catching, __gcc_personality_v0 simply always
|
||||
// returns _URC_CONTINUE_UNWIND in search phase, and always returns _URC_INSTALL_CONTEXT
|
||||
// (i.e. "invoke cleanup code") in cleanup phase.
|
||||
// Since C does not support exception catching, __gcc_personality_v0 simply
|
||||
// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
|
||||
// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
|
||||
//
|
||||
// This is pretty close to Rust's exception handling approach, except that Rust does have
|
||||
// a single "catch-all" handler at the bottom of each task's stack.
|
||||
// This is pretty close to Rust's exception handling approach, except that Rust
|
||||
// does have a single "catch-all" handler at the bottom of each task's stack.
|
||||
// So we have two versions:
|
||||
// - rust_eh_personality, used by all cleanup landing pads, which never catches, so
|
||||
// the behavior of __gcc_personality_v0 is perfectly adequate there, and
|
||||
// - rust_eh_personality_catch, used only by rust_try(), which always catches. This is
|
||||
// achieved by overriding the return value in search phase to always say "catch!".
|
||||
// - rust_eh_personality, used by all cleanup landing pads, which never catches,
|
||||
// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
|
||||
// - rust_eh_personality_catch, used only by rust_try(), which always catches.
|
||||
// This is achieved by overriding the return value in search phase to always
|
||||
// say "catch!".
|
||||
|
||||
extern "C" {
|
||||
fn __gcc_personality_v0(version: c_int,
|
||||
actions: _Unwind_Action,
|
||||
exception_class: _Unwind_Exception_Class,
|
||||
ue_header: *_Unwind_Exception,
|
||||
context: *_Unwind_Context) -> _Unwind_Reason_Code;
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *uw::_Unwind_Exception,
|
||||
context: *uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code;
|
||||
}
|
||||
|
||||
#[lang="eh_personality"]
|
||||
#[no_mangle] // so we can reference it by name from middle/trans/base.rs
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(test))]
|
||||
pub extern "C" fn rust_eh_personality(version: c_int,
|
||||
actions: _Unwind_Action,
|
||||
exception_class: _Unwind_Exception_Class,
|
||||
ue_header: *_Unwind_Exception,
|
||||
context: *_Unwind_Context) -> _Unwind_Reason_Code {
|
||||
pub extern "C" fn rust_eh_personality(
|
||||
version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *uw::_Unwind_Exception,
|
||||
context: *uw::_Unwind_Context
|
||||
) -> uw::_Unwind_Reason_Code
|
||||
{
|
||||
unsafe {
|
||||
__gcc_personality_v0(version, actions, exception_class, ue_header, context)
|
||||
__gcc_personality_v0(version, actions, exception_class, ue_header,
|
||||
context)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle] // referenced from rust_try.ll
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(test))]
|
||||
pub extern "C" fn rust_eh_personality_catch(version: c_int,
|
||||
actions: _Unwind_Action,
|
||||
exception_class: _Unwind_Exception_Class,
|
||||
ue_header: *_Unwind_Exception,
|
||||
context: *_Unwind_Context) -> _Unwind_Reason_Code {
|
||||
if (actions as c_int & _UA_SEARCH_PHASE as c_int) != 0 { // search phase
|
||||
_URC_HANDLER_FOUND // catch!
|
||||
pub extern "C" fn rust_eh_personality_catch(
|
||||
version: c_int,
|
||||
actions: uw::_Unwind_Action,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
ue_header: *uw::_Unwind_Exception,
|
||||
context: *uw::_Unwind_Context
|
||||
) -> uw::_Unwind_Reason_Code
|
||||
{
|
||||
if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
|
||||
uw::_URC_HANDLER_FOUND // catch!
|
||||
}
|
||||
else { // cleanup phase
|
||||
unsafe {
|
||||
__gcc_personality_v0(version, actions, exception_class, ue_header, context)
|
||||
__gcc_personality_v0(version, actions, exception_class, ue_header,
|
||||
context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -307,11 +337,11 @@ pub fn begin_unwind<M: Any + Send>(msg: M, file: &'static str, line: uint) -> !
|
||||
let n = (*task).name.as_ref()
|
||||
.map(|n| n.as_slice()).unwrap_or("<unnamed>");
|
||||
|
||||
println!("task '{}' failed at '{}', {}:{}", n, msg_s,
|
||||
rterrln!("task '{}' failed at '{}', {}:{}", n, msg_s,
|
||||
file, line);
|
||||
}
|
||||
None => {
|
||||
println!("failed at '{}', {}:{}", msg_s, file, line);
|
||||
rterrln!("failed at '{}', {}:{}", msg_s, file, line);
|
||||
intrinsics::abort();
|
||||
}
|
||||
}
|
||||
|
@ -69,14 +69,13 @@ pub fn default_sched_threads() -> uint {
|
||||
pub fn dumb_println(args: &fmt::Arguments) {
|
||||
use io;
|
||||
use libc;
|
||||
use vec;
|
||||
|
||||
struct Stderr;
|
||||
impl io::Writer for Stderr {
|
||||
fn write(&mut self, data: &[u8]) {
|
||||
unsafe {
|
||||
libc::write(libc::STDERR_FILENO,
|
||||
vec::raw::to_ptr(data) as *libc::c_void,
|
||||
data.as_ptr() as *libc::c_void,
|
||||
data.len() as libc::size_t);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ use vec;
|
||||
/// An atomically reference counted pointer.
|
||||
///
|
||||
/// Enforces no shared-memory safety.
|
||||
//#[unsafe_no_drop_flag] FIXME: #9758
|
||||
#[unsafe_no_drop_flag]
|
||||
pub struct UnsafeArc<T> {
|
||||
priv data: *mut ArcData<T>,
|
||||
}
|
||||
|
@ -192,6 +192,7 @@ pub unsafe fn record_sp_limit(limit: uint) {
|
||||
#[cfg(target_arch = "mips")]
|
||||
#[cfg(target_arch = "arm")] #[inline(always)]
|
||||
unsafe fn target_record_sp_limit(limit: uint) {
|
||||
use libc::c_void;
|
||||
return record_sp_limit(limit as *c_void);
|
||||
extern {
|
||||
fn record_sp_limit(limit: *c_void);
|
||||
@ -265,6 +266,7 @@ pub unsafe fn get_sp_limit() -> uint {
|
||||
#[cfg(target_arch = "mips")]
|
||||
#[cfg(target_arch = "arm")] #[inline(always)]
|
||||
unsafe fn target_get_sp_limit() -> uint {
|
||||
use libc::c_void;
|
||||
return get_sp_limit() as uint;
|
||||
extern {
|
||||
fn get_sp_limit() -> *c_void;
|
||||
|
@ -1,4 +1,3 @@
|
||||
// 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.
|
||||
//
|
||||
@ -12,7 +11,6 @@ extern mod extra;
|
||||
|
||||
use std::os;
|
||||
use std::uint;
|
||||
use std::rt::test::spawntask_later;
|
||||
|
||||
// This is a simple bench that creates M pairs of of tasks. These
|
||||
// tasks ping-pong back and forth over a pair of streams. This is a
|
||||
@ -28,7 +26,7 @@ fn ping_pong_bench(n: uint, m: uint) {
|
||||
// Create a stream B->A
|
||||
let (pb,cb) = Chan::<()>::new();
|
||||
|
||||
do spawntask_later() || {
|
||||
do spawn() || {
|
||||
let chan = ca;
|
||||
let port = pb;
|
||||
n.times(|| {
|
||||
@ -37,7 +35,7 @@ fn ping_pong_bench(n: uint, m: uint) {
|
||||
})
|
||||
}
|
||||
|
||||
do spawntask_later() || {
|
||||
do spawn() || {
|
||||
let chan = cb;
|
||||
let port = pa;
|
||||
n.times(|| {
|
||||
|
@ -12,7 +12,6 @@ extern mod extra;
|
||||
|
||||
use std::os;
|
||||
use std::uint;
|
||||
use std::rt::test::spawntask_later;
|
||||
|
||||
// A simple implementation of parfib. One subtree is found in a new
|
||||
// task and communicated over a oneshot pipe, the other is found
|
||||
@ -24,7 +23,7 @@ fn parfib(n: uint) -> uint {
|
||||
}
|
||||
|
||||
let (port,chan) = Chan::new();
|
||||
do spawntask_later {
|
||||
do spawn {
|
||||
chan.send(parfib(n-1));
|
||||
};
|
||||
let m2 = parfib(n-2);
|
||||
|
@ -8,6 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-test arcs no longer unwrap
|
||||
|
||||
extern mod extra;
|
||||
|
||||
use std::from_str::FromStr;
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#[feature(globs)];
|
||||
|
||||
use std::unstable::atomics::*;
|
||||
use std::sync::atomics::*;
|
||||
use std::ptr;
|
||||
|
||||
fn main() {
|
||||
|
25
src/test/run-make/bootstrap-from-c-with-green/lib.rs
Normal file
25
src/test/run-make/bootstrap-from-c-with-green/lib.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// 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.
|
||||
|
||||
#[crate_id="boot#0.1"];
|
||||
#[crate_type="lib"];
|
||||
#[no_uv];
|
||||
|
||||
extern mod rustuv;
|
||||
extern mod green;
|
||||
|
||||
#[no_mangle] // this needs to get called from C
|
||||
pub extern "C" fn foo(argc: int, argv: **u8) -> int {
|
||||
do green::start(argc, argv) {
|
||||
do spawn {
|
||||
println!("hello");
|
||||
}
|
||||
}
|
||||
}
|
9
src/test/run-make/bootstrap-from-c-with-native/Makefile
Normal file
9
src/test/run-make/bootstrap-from-c-with-native/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all:
|
||||
$(RUSTC) lib.rs -Z gen-crate-map
|
||||
ln -nsf $(call DYLIB,boot-*) $(call DYLIB,boot)
|
||||
$(CC) main.c -o $(call RUN,main) -lboot -Wl,-rpath,$(TMPDIR)
|
||||
$(call RUN,main)
|
||||
rm $(call DYLIB,boot)
|
||||
$(call FAIL,main)
|
@ -10,14 +10,13 @@
|
||||
|
||||
#[crate_id="boot#0.1"];
|
||||
#[crate_type="lib"];
|
||||
#[no_uv];
|
||||
|
||||
extern mod rustuv; // pull in uvio
|
||||
|
||||
use std::rt;
|
||||
extern mod native;
|
||||
|
||||
#[no_mangle] // this needs to get called from C
|
||||
pub extern "C" fn foo(argc: int, argv: **u8) -> int {
|
||||
do rt::start(argc, argv) {
|
||||
do native::start(argc, argv) {
|
||||
do spawn {
|
||||
println!("hello");
|
||||
}
|
16
src/test/run-make/bootstrap-from-c-with-native/main.c
Normal file
16
src/test/run-make/bootstrap-from-c-with-native/main.c
Normal file
@ -0,0 +1,16 @@
|
||||
// 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.
|
||||
|
||||
// this is the rust entry point that we're going to call.
|
||||
int foo(int argc, char *argv[]);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
return foo(argc, argv);
|
||||
}
|
@ -28,4 +28,4 @@ mod baz {
|
||||
}
|
||||
|
||||
#[start]
|
||||
pub fn start(_: int, _: **u8) -> int { 3 }
|
||||
pub fn start(_: int, _: **u8) -> int { 0 }
|
||||
|
Loading…
x
Reference in New Issue
Block a user