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:
Alex Crichton 2013-12-18 09:57:58 -08:00
parent b47ff23673
commit 6cad8f4f14
41 changed files with 274 additions and 191 deletions

View File

@ -13,6 +13,7 @@
#[allow(non_camel_case_types)];
#[deny(warnings)];
#[cfg(stage0)] extern mod green;
extern mod extra;
use std::os;

View File

@ -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]

View File

@ -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

View File

@ -17,8 +17,6 @@
use std::task;
use std::vec;
#[cfg(test)] use std::task::SingleThreaded;
enum Msg<T> {
Execute(proc(&T)),
Quit

View File

@ -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;

View File

@ -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

View File

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

View File

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

View File

@ -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;
/**

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

View File

@ -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,

View File

@ -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]

View File

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

View File

@ -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;

View File

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

View File

@ -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();
}
}

View File

@ -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()
};
}

View File

@ -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 {

View File

@ -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"));

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -176,6 +176,7 @@ pub fn init(argc: int, argv: **u8) {
args::init(argc, argv);
env::init();
logging::init();
local_ptr::init();
}
}

View File

@ -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).

View File

@ -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

View File

@ -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;

View File

@ -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();
}
}

View File

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

View File

@ -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>,
}

View File

@ -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;

View File

@ -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(|| {

View File

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

View File

@ -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;

View File

@ -12,7 +12,7 @@
#[feature(globs)];
use std::unstable::atomics::*;
use std::sync::atomics::*;
use std::ptr;
fn main() {

View 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");
}
}
}

View 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)

View File

@ -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");
}

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

View File

@ -28,4 +28,4 @@ mod baz {
}
#[start]
pub fn start(_: int, _: **u8) -> int { 3 }
pub fn start(_: int, _: **u8) -> int { 0 }