diff --git a/mk/rt.mk b/mk/rt.mk index 72578bcdb40..6d5fb862cf5 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -10,6 +10,7 @@ RUNTIME_CS := rt/sync/timer.cpp \ rt/rust_run_program.cpp \ rt/rust_crate_cache.cpp \ rt/rust_comm.cpp \ + rt/rust_env.cpp \ rt/rust_scheduler.cpp \ rt/rust_task.cpp \ rt/rust_task_list.cpp \ @@ -38,6 +39,7 @@ RUNTIME_HDR := rt/globals.h \ rt/rust_internal.h \ rt/rust_util.h \ rt/rust_chan.h \ + rt/rust_env.h \ rt/rust_port.h \ rt/rust_scheduler.h \ rt/rust_task.h \ diff --git a/src/rt/memory_region.cpp b/src/rt/memory_region.cpp index 44924218e57..7114aa5b324 100644 --- a/src/rt/memory_region.cpp +++ b/src/rt/memory_region.cpp @@ -14,7 +14,7 @@ memory_region::alloc_header *memory_region::get_header(void *mem) { memory_region::memory_region(rust_srv *srv, bool synchronized) : _srv(srv), _parent(NULL), _live_allocations(0), - _detailed_leaks(getenv("RUST_DETAILED_LEAKS") != NULL), + _detailed_leaks(srv->env->detailed_leaks), _synchronized(synchronized), _hack_allow_leaks(false) { } diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp index df1486952eb..0d25d2c3248 100644 --- a/src/rt/rust.cpp +++ b/src/rt/rust.cpp @@ -76,56 +76,6 @@ command_line_args : public kernel_owned }; -#if defined(__WIN32__) -int get_num_cpus() { - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - - return (int) sysinfo.dwNumberOfProcessors; -} -#elif defined(__BSD__) -int get_num_cpus() { - /* swiped from http://stackoverflow.com/questions/150355/ - programmatically-find-the-number-of-cores-on-a-machine */ - - unsigned int numCPU; - int mib[4]; - size_t len = sizeof(numCPU); - - /* set the mib for hw.ncpu */ - mib[0] = CTL_HW; - mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU; - - /* get the number of CPUs from the system */ - sysctl(mib, 2, &numCPU, &len, NULL, 0); - - if( numCPU < 1 ) { - mib[1] = HW_NCPU; - sysctl( mib, 2, &numCPU, &len, NULL, 0 ); - - if( numCPU < 1 ) { - numCPU = 1; - } - } - return numCPU; -} -#elif defined(__GNUC__) -int get_num_cpus() { - return sysconf(_SC_NPROCESSORS_ONLN); -} -#endif - -int get_num_threads() -{ - char *env = getenv("RUST_THREADS"); - if(env) { - int num = atoi(env); - if(num > 0) - return num; - } - return get_num_cpus(); -} - /** * Main entry point into the Rust runtime. Here we create a Rust service, * initialize the kernel, create the root domain and run it. @@ -133,17 +83,16 @@ int get_num_threads() int check_claims = 0; -void enable_claims(void* ck) { check_claims = (ck != 0); } - extern "C" CDECL int rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) { - update_log_settings(crate_map, getenv("RUST_LOG")); - enable_claims(getenv("CHECK_CLAIMS")); - int num_threads = get_num_threads(); + rust_env *env = load_env(); - rust_srv *srv = new rust_srv(); - rust_kernel *kernel = new rust_kernel(srv, num_threads); + update_log_settings(crate_map, env->logspec); + check_claims = env->check_claims; + + rust_srv *srv = new rust_srv(env); + rust_kernel *kernel = new rust_kernel(srv, env->num_sched_threads); kernel->start(); rust_task *root_task = kernel->create_task(NULL, "main"); rust_scheduler *sched = root_task->sched; @@ -159,13 +108,13 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) { root_task->start(main_fn, (uintptr_t)args->args); - DLOG(sched, dom, "Using %d worker threads.", num_threads); - int ret = kernel->start_task_threads(); delete args; delete kernel; delete srv; + free_env(env); + #if !defined(__WIN32__) // Don't take down the process if the main thread exits without an // error. diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 4870c9fe545..6f45227bb8b 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -857,10 +857,10 @@ clone_chan(rust_task *task, rust_chan *chan) { } // defined in rust_task.cpp -extern size_t g_min_stack_size; +extern size_t g_custom_min_stack_size; extern "C" CDECL void set_min_stack(rust_task *task, uintptr_t stack_size) { - g_min_stack_size = stack_size; + g_custom_min_stack_size = stack_size; } // diff --git a/src/rt/rust_env.cpp b/src/rt/rust_env.cpp new file mode 100644 index 00000000000..26fc4dab180 --- /dev/null +++ b/src/rt/rust_env.cpp @@ -0,0 +1,119 @@ +// The runtime wants to pull a number of variables out of the +// environment but calling getenv is not threadsafe, so every value +// that might come from the environment is loaded here, once, during +// init. + +#include "rust_internal.h" + +// The environment variables that the runtime knows about +#define RUST_THREADS "RUST_THREADS" +#define RUST_MIN_STACK "RUST_MIN_STACK" +#define RUST_LOG "RUST_LOG" +#define CHECK_CLAIMS "CHECK_CLAIMS" +#define DETAILED_LEAKS "DETAILED_LEAKS" +#define RUST_SEED "RUST_SEED" + +#if defined(__WIN32__) +static int +get_num_cpus() { + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + + return (int) sysinfo.dwNumberOfProcessors; +} +#elif defined(__BSD__) +static int +get_num_cpus() { + /* swiped from http://stackoverflow.com/questions/150355/ + programmatically-find-the-number-of-cores-on-a-machine */ + + unsigned int numCPU; + int mib[4]; + size_t len = sizeof(numCPU); + + /* set the mib for hw.ncpu */ + mib[0] = CTL_HW; + mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU; + + /* get the number of CPUs from the system */ + sysctl(mib, 2, &numCPU, &len, NULL, 0); + + if( numCPU < 1 ) { + mib[1] = HW_NCPU; + sysctl( mib, 2, &numCPU, &len, NULL, 0 ); + + if( numCPU < 1 ) { + numCPU = 1; + } + } + return numCPU; +} +#elif defined(__GNUC__) +static int +get_num_cpus() { + return sysconf(_SC_NPROCESSORS_ONLN); +} +#endif + +static int +get_num_threads() +{ + char *env = getenv(RUST_THREADS); + if(env) { + int num = atoi(env); + if(num > 0) + return num; + } + return get_num_cpus(); +} + +// FIXME (issue #151): This should be 0x300; the change here is for +// practicality's sake until stack growth is working. + +static size_t +get_min_stk_size() { + char *stack_size = getenv(RUST_MIN_STACK); + if(stack_size) { + return strtol(stack_size, NULL, 0); + } + else { + return 0x300000; + } +} + +static char* +copyenv(const char* name) { + char *envvar = getenv(name); + if (!envvar) { + return NULL; + } else { + const size_t maxlen = 4096; + size_t strlen = strnlen(envvar, maxlen); + size_t buflen = strlen + 1; + char *var = (char*)malloc(buflen); + memset(var, 0, buflen); + strncpy(var, envvar, strlen); + return var; + } +} + +rust_env* +load_env() { + rust_env *env = (rust_env*)malloc(sizeof(rust_env)); + + env->num_sched_threads = (size_t)get_num_threads(); + env->min_stack_size = get_min_stk_size(); + env->logspec = copyenv(RUST_LOG); + env->check_claims = getenv(CHECK_CLAIMS) != NULL; + env->detailed_leaks = getenv(DETAILED_LEAKS) != NULL; + env->rust_seed = copyenv(RUST_SEED); + + return env; +} + +void +free_env(rust_env *env) { + free(env->logspec); + free(env->rust_seed); + free(env); +} diff --git a/src/rt/rust_env.h b/src/rt/rust_env.h new file mode 100644 index 00000000000..6dc9cc120cd --- /dev/null +++ b/src/rt/rust_env.h @@ -0,0 +1,11 @@ +struct rust_env { + size_t num_sched_threads; + size_t min_stack_size; + char* logspec; + bool check_claims; + bool detailed_leaks; + char* rust_seed; +}; + +rust_env* load_env(); +void free_env(rust_env *rust_env); diff --git a/src/rt/rust_internal.h b/src/rt/rust_internal.h index 6fe3e170b79..10822f02395 100644 --- a/src/rt/rust_internal.h +++ b/src/rt/rust_internal.h @@ -24,6 +24,7 @@ #include "rust.h" #include "rand.h" #include "uthash.h" +#include "rust_env.h" #if defined(__WIN32__) extern "C" { diff --git a/src/rt/rust_kernel.cpp b/src/rt/rust_kernel.cpp index 8839f7fe6af..a4f56c10be2 100644 --- a/src/rt/rust_kernel.cpp +++ b/src/rt/rust_kernel.cpp @@ -12,7 +12,8 @@ rust_kernel::rust_kernel(rust_srv *srv, size_t num_threads) : _interrupt_kernel_loop(FALSE), num_threads(num_threads), rval(0), - live_tasks(0) + live_tasks(0), + env(srv->env) { isaac_init(this, &rctx); create_schedulers(); @@ -51,6 +52,8 @@ rust_kernel::destroy_scheduler(rust_scheduler *sched) { } void rust_kernel::create_schedulers() { + KLOG_("Using %d scheduler threads.", num_threads); + for(size_t i = 0; i < num_threads; ++i) { threads.push(create_scheduler(i)); } diff --git a/src/rt/rust_kernel.h b/src/rt/rust_kernel.h index cf9d88e0016..d54c6a65430 100644 --- a/src/rt/rust_kernel.h +++ b/src/rt/rust_kernel.h @@ -98,6 +98,8 @@ public: */ indexed_list message_queues; + struct rust_env *env; + rust_handle *get_task_handle(rust_task *task); rust_handle *get_port_handle(rust_port *port); diff --git a/src/rt/rust_scheduler.cpp b/src/rt/rust_scheduler.cpp index 245ee3d5fce..c4987bbd3f1 100644 --- a/src/rt/rust_scheduler.cpp +++ b/src/rt/rust_scheduler.cpp @@ -20,7 +20,9 @@ rust_scheduler::rust_scheduler(rust_kernel *kernel, cache(this), kernel(kernel), message_queue(message_queue), - id(id) + id(id), + min_stack_size(kernel->env->min_stack_size), + env(kernel->env) { LOGPTR(this, "new dom", (uintptr_t)this); isaac_init(this, &rctx); diff --git a/src/rt/rust_scheduler.h b/src/rt/rust_scheduler.h index 9289883ab1e..561807d44e0 100644 --- a/src/rt/rust_scheduler.h +++ b/src/rt/rust_scheduler.h @@ -60,11 +60,14 @@ struct rust_scheduler : public kernel_owned, const int id; lock_and_signal lock; + size_t min_stack_size; #ifndef __WIN32__ pthread_attr_t attr; #endif + rust_env *env; + // Only a pointer to 'name' is kept, so it must live as long as this // domain. rust_scheduler(rust_kernel *kernel, diff --git a/src/rt/rust_srv.cpp b/src/rt/rust_srv.cpp index 05c9d9d564c..835b283a73f 100644 --- a/src/rt/rust_srv.cpp +++ b/src/rt/rust_srv.cpp @@ -1,7 +1,8 @@ #include "rust_internal.h" #include "rust_srv.h" -rust_srv::rust_srv() : +rust_srv::rust_srv(rust_env *env) : + env(env), local_region(this, false) { } @@ -72,7 +73,7 @@ rust_srv::warning(char const *expression, rust_srv * rust_srv::clone() { - return new rust_srv(); + return new rust_srv(env); } // diff --git a/src/rt/rust_srv.h b/src/rt/rust_srv.h index beec5d70345..7037007e78c 100644 --- a/src/rt/rust_srv.h +++ b/src/rt/rust_srv.h @@ -6,6 +6,7 @@ class rust_srv { public: + rust_env *env; memory_region local_region; virtual void log(char const *msg); virtual void fatal(char const *expression, @@ -21,7 +22,7 @@ public: virtual void free(void *); virtual void *malloc(size_t); virtual void *realloc(void *, size_t); - rust_srv(); + rust_srv(rust_env *); virtual ~rust_srv(); virtual rust_srv *clone(); }; diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index a144879cc04..6f3e0202472 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -10,28 +10,25 @@ #include "globals.h" -// Stacks +// Stack size +size_t g_custom_min_stack_size = 0; -// FIXME (issue #151): This should be 0x300; the change here is for -// practicality's sake until stack growth is working. -size_t g_min_stack_size = 0x300000; - -static size_t get_min_stk_size() { - char *stack_size = getenv("RUST_MIN_STACK"); - if(stack_size) { - return strtol(stack_size, NULL, 0); - } - else { - return g_min_stack_size; +static size_t +get_min_stk_size(size_t default_size) { + if (g_custom_min_stack_size != 0) { + return g_custom_min_stack_size; + } else { + return default_size; } } + // Task stack segments. Heap allocated and chained together. static stk_seg* -new_stk(rust_task *task, size_t minsz) +new_stk(rust_scheduler *sched, rust_task *task, size_t minsz) { - size_t min_stk_bytes = get_min_stk_size(); + size_t min_stk_bytes = get_min_stk_size(sched->min_stack_size); if (minsz < min_stk_bytes) minsz = min_stk_bytes; size_t sz = sizeof(stk_seg) + minsz; @@ -90,7 +87,7 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state, LOGPTR(sched, "new task", (uintptr_t)this); DLOG(sched, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this); - stk = new_stk(this, 0); + stk = new_stk(sched, this, 0); rust_sp = stk->limit; } diff --git a/src/rt/rust_util.h b/src/rt/rust_util.h index c46f1916573..938b4c96cb5 100644 --- a/src/rt/rust_util.h +++ b/src/rt/rust_util.h @@ -148,7 +148,7 @@ isaac_init(sched_or_kernel *sched, randctx *rctx) CryptReleaseContext(hProv, 0)); } #else - char *rust_seed = getenv("RUST_SEED"); + char *rust_seed = sched->env->rust_seed; if (rust_seed != NULL) { ub4 seed = (ub4) atoi(rust_seed); for (size_t i = 0; i < RANDSIZ; i ++) { diff --git a/src/rt/test/rust_test_runtime.cpp b/src/rt/test/rust_test_runtime.cpp index 1e7c10944a7..ad5a018eec8 100644 --- a/src/rt/test/rust_test_runtime.cpp +++ b/src/rt/test/rust_test_runtime.cpp @@ -19,7 +19,8 @@ rust_domain_test::worker::run() { bool rust_domain_test::run() { - rust_srv srv; + rust_env env; + rust_srv srv(&env); rust_kernel kernel(&srv, 1); array_list workers; @@ -51,7 +52,8 @@ rust_task_test::worker::run() { bool rust_task_test::run() { - rust_srv srv; + rust_env env; + rust_srv srv(&env); rust_kernel kernel(&srv, 1); array_list workers; diff --git a/src/rt/test/rust_test_util.h b/src/rt/test/rust_test_util.h index 9ee3ee8bd36..59eff049270 100644 --- a/src/rt/test/rust_test_util.h +++ b/src/rt/test/rust_test_util.h @@ -17,10 +17,13 @@ public: class rust_synchronized_indexed_list_test : public rust_test { public: + rust_env env; rust_srv srv; synchronized_indexed_list > list; - rust_synchronized_indexed_list_test() { + rust_synchronized_indexed_list_test() : + srv(&env) + { } class worker : public rust_thread {