libcore: Add sys::set_exit_status

Sets the process exit code
This commit is contained in:
Brian Anderson 2012-01-12 22:17:21 -08:00
parent dcac427795
commit 0616cba62b
10 changed files with 68 additions and 5 deletions

View File

@ -20,6 +20,7 @@ native mod rustrt {
fn do_gc(); fn do_gc();
fn unsupervise(); fn unsupervise();
fn shape_log_str<T>(t: *sys::type_desc, data: T) -> str; fn shape_log_str<T>(t: *sys::type_desc, data: T) -> str;
fn rust_set_exit_status(code: int);
} }
#[abi = "rust-intrinsic"] #[abi = "rust-intrinsic"]
@ -92,6 +93,18 @@ fn log_str<T>(t: T) -> str {
rustrt::shape_log_str(get_type_desc::<T>(), t) rustrt::shape_log_str(get_type_desc::<T>(), t)
} }
#[doc(
brief = "Sets the process exit code",
desc = "Sets the exit code returned by the process if all supervised \
tasks terminate successfully (without failing). If the current \
root task fails and is supervised by the scheduler then any \
user-specified exit status is ignored and the process exits \
with the default failure status."
)]
fn set_exit_status(code: int) {
rustrt::rust_set_exit_status(code);
}
// Local Variables: // Local Variables:
// mode: rust; // mode: rust;
// fill-column: 78; // fill-column: 78;

View File

@ -561,6 +561,12 @@ port_recv(uintptr_t *dptr, rust_port *port,
return; return;
} }
extern "C" CDECL void
rust_set_exit_status(intptr_t code) {
rust_task *task = rust_scheduler::get_task();
task->kernel->set_exit_status((int)code);
}
// //
// Local Variables: // Local Variables:
// mode: C++ // mode: C++

View File

@ -92,7 +92,7 @@ static size_t const TIME_SLICE_IN_MS = 10;
static size_t const BUF_BYTES = 2048; static size_t const BUF_BYTES = 2048;
// The error status to use when the process fails // The error status to use when the process fails
#define PROC_FAIL_CODE 101; #define PROC_FAIL_CODE 101
// Every reference counted object should use this macro and initialize // Every reference counted object should use this macro and initialize
// ref_count. // ref_count.

View File

@ -11,8 +11,8 @@ rust_kernel::rust_kernel(rust_srv *srv, size_t num_threads) :
_log(srv, NULL), _log(srv, NULL),
srv(srv), srv(srv),
max_id(0), max_id(0),
num_threads(num_threads),
rval(0), rval(0),
num_threads(num_threads),
live_tasks(0), live_tasks(0),
env(srv->env) env(srv->env)
{ {
@ -140,6 +140,7 @@ rust_kernel::fail() {
// FIXME: On windows we're getting "Application has requested the // FIXME: On windows we're getting "Application has requested the
// Runtime to terminate it in an unusual way" when trying to shutdown // Runtime to terminate it in an unusual way" when trying to shutdown
// cleanly. // cleanly.
set_exit_status(PROC_FAIL_CODE);
#if defined(__WIN32__) #if defined(__WIN32__)
exit(rval); exit(rval);
#endif #endif
@ -210,6 +211,15 @@ rust_kernel::win32_require(LPCTSTR fn, BOOL ok) {
} }
#endif #endif
void
rust_kernel::set_exit_status(int code) {
scoped_lock with(_kernel_lock);
// If we've already failed then that's the code we're going to use
if (rval != PROC_FAIL_CODE) {
rval = code;
}
}
// //
// Local Variables: // Local Variables:
// mode: C++ // mode: C++

View File

@ -34,9 +34,10 @@ private:
rust_task_id max_id; rust_task_id max_id;
hash_map<rust_task_id, rust_task *> task_table; hash_map<rust_task_id, rust_task *> task_table;
int rval;
public: public:
const size_t num_threads; const size_t num_threads;
int rval;
volatile int live_tasks; volatile int live_tasks;
struct rust_env *env; struct rust_env *env;
@ -68,6 +69,7 @@ public:
rust_task_id create_task(rust_task *spawner, const char *name); rust_task_id create_task(rust_task *spawner, const char *name);
rust_task *get_task_by_id(rust_task_id id); rust_task *get_task_by_id(rust_task_id id);
void release_task_id(rust_task_id tid); void release_task_id(rust_task_id tid);
void set_exit_status(int code);
}; };
#endif /* RUST_KERNEL_H */ #endif /* RUST_KERNEL_H */

View File

@ -82,8 +82,6 @@ void
rust_scheduler::fail() { rust_scheduler::fail() {
log(NULL, log_err, "domain %s @0x%" PRIxPTR " root task failed", log(NULL, log_err, "domain %s @0x%" PRIxPTR " root task failed",
name, this); name, this);
I(this, kernel->rval == 0);
kernel->rval = PROC_FAIL_CODE;
kernel->fail(); kernel->fail();
} }

View File

@ -41,6 +41,7 @@ rust_port_size
rust_process_wait rust_process_wait
rust_ptr_eq rust_ptr_eq
rust_run_program rust_run_program
rust_set_exit_status
rust_start rust_start
rust_getcwd rust_getcwd
rust_task_is_unwinding rust_task_is_unwinding

View File

@ -0,0 +1,10 @@
// error-pattern:whatever
fn main() {
log(error, "whatever");
// Setting the exit status only works when the scheduler terminates
// normally. In this case we're going to fail, so instead of of
// returning 50 the process will return the typical rt failure code.
sys::set_exit_status(50);
fail;
}

View File

@ -0,0 +1,15 @@
// error-pattern:whatever
fn main() {
log(error, "whatever");
task::spawn {||
resource r(_i: ()) {
// Setting the exit status after the runtime has already
// failed has no effect and the process exits with the
// runtime's exit code
sys::set_exit_status(50);
}
let i = r(());
};
fail;
}

View File

@ -0,0 +1,8 @@
// error-pattern:whatever
fn main() {
log(error, "whatever");
// 101 is the code the runtime uses on task failure and the value
// compiletest expects run-fail tests to return.
sys::set_exit_status(101);
}