aboutsummaryrefslogtreecommitdiff
path: root/src/rt/rust.cpp
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2010-06-23 21:03:09 -0700
committerGraydon Hoare <[email protected]>2010-06-23 21:03:09 -0700
commitd6b7c96c3eb29b9244ece0c046d3f372ff432d04 (patch)
treeb425187e232966063ffc2f0d14c04a55d8f004ef /src/rt/rust.cpp
parentInitial git commit. (diff)
downloadrust-d6b7c96c3eb29b9244ece0c046d3f372ff432d04.tar.xz
rust-d6b7c96c3eb29b9244ece0c046d3f372ff432d04.zip
Populate tree.
Diffstat (limited to 'src/rt/rust.cpp')
-rw-r--r--src/rt/rust.cpp267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/rt/rust.cpp b/src/rt/rust.cpp
new file mode 100644
index 00000000..8c725bfb
--- /dev/null
+++ b/src/rt/rust.cpp
@@ -0,0 +1,267 @@
+#include "rust_internal.h"
+#include "util/array_list.h"
+
+
+// #define TRACK_ALLOCATIONS
+// For debugging, keeps track of live allocations, so you can find out
+// exactly what leaked.
+
+#ifdef TRACK_ALLOCATIONS
+array_list<void *> allocation_list;
+#endif
+
+rust_srv::rust_srv() :
+ live_allocs(0)
+{
+}
+
+rust_srv::~rust_srv()
+{
+ if (live_allocs != 0) {
+ char msg[128];
+ snprintf(msg, sizeof(msg),
+ "leaked memory in rust main loop (%" PRIuPTR " objects)",
+ live_allocs);
+#ifdef TRACK_ALLOCATIONS
+ for (size_t i = 0; i < allocation_list.size(); i++) {
+ if (allocation_list[i] != NULL) {
+ printf("allocation 0x%" PRIxPTR " was not freed\n",
+ (uintptr_t) allocation_list[i]);
+ }
+ }
+#endif
+ fatal(msg, __FILE__, __LINE__);
+ }
+}
+
+void
+rust_srv::log(char const *str)
+{
+ printf("rt: %s\n", str);
+}
+
+
+
+void *
+rust_srv::malloc(size_t bytes)
+{
+ ++live_allocs;
+ void * val = ::malloc(bytes);
+#ifdef TRACK_ALLOCATIONS
+ allocation_list.append(val);
+#endif
+ return val;
+}
+
+void *
+rust_srv::realloc(void *p, size_t bytes)
+{
+ if (!p) {
+ live_allocs++;
+ }
+ void * val = ::realloc(p, bytes);
+#ifdef TRACK_ALLOCATIONS
+ if (allocation_list.replace(p, val) == NULL) {
+ fatal("not in allocation_list", __FILE__, __LINE__);
+ }
+#endif
+ return val;
+}
+
+void
+rust_srv::free(void *p)
+{
+ if (live_allocs < 1) {
+ fatal("live_allocs < 1", __FILE__, __LINE__);
+ }
+ live_allocs--;
+ ::free(p);
+#ifdef TRACK_ALLOCATIONS
+ if (allocation_list.replace(p, NULL) == NULL) {
+ fatal("not in allocation_list", __FILE__, __LINE__);
+ }
+#endif
+}
+
+void
+rust_srv::fatal(char const *expr, char const *file, size_t line)
+{
+ char buf[1024];
+ snprintf(buf, sizeof(buf),
+ "fatal, '%s' failed, %s:%d",
+ expr, file, (int)line);
+ log(buf);
+ exit(1);
+}
+
+rust_srv *
+rust_srv::clone()
+{
+ return new rust_srv();
+}
+
+
+int
+rust_main_loop(rust_dom *dom)
+{
+ // Make sure someone is watching, to pull us out of infinite loops.
+ rust_timer timer(*dom);
+
+ int rval;
+ rust_task *task;
+
+ dom->log(rust_log::DOM,
+ "running main-loop on domain 0x%" PRIxPTR, dom);
+ dom->logptr("exit-task glue",
+ dom->root_crate->get_exit_task_glue());
+
+ while ((task = dom->sched()) != NULL) {
+ I(dom, task->running());
+
+ dom->log(rust_log::TASK,
+ "activating task 0x%" PRIxPTR ", sp=0x%" PRIxPTR,
+ (uintptr_t)task, task->rust_sp);
+
+ dom->interrupt_flag = 0;
+
+ dom->activate(task);
+
+ dom->log(rust_log::TASK,
+ "returned from task 0x%" PRIxPTR
+ " in state '%s', sp=0x%" PRIxPTR,
+ (uintptr_t)task,
+ dom->state_vec_name(task->state),
+ task->rust_sp);
+
+ I(dom, task->rust_sp >= (uintptr_t) &task->stk->data[0]);
+ I(dom, task->rust_sp < task->stk->limit);
+
+ dom->reap_dead_tasks();
+ }
+
+ dom->log(rust_log::DOM, "finished main-loop (dom.rval = %d)", dom->rval);
+ rval = dom->rval;
+
+ return rval;
+}
+
+
+struct
+command_line_args
+{
+ rust_dom &dom;
+ int argc;
+ char **argv;
+
+ // vec[str] passed to rust_task::start.
+ rust_vec *args;
+
+ command_line_args(rust_dom &dom,
+ int sys_argc,
+ char **sys_argv)
+ : dom(dom),
+ argc(sys_argc),
+ argv(sys_argv),
+ args(NULL)
+ {
+#if defined(__WIN32__)
+ LPCWSTR cmdline = GetCommandLineW();
+ LPWSTR *wargv = CommandLineToArgvW(cmdline, &argc);
+ dom.win32_require("CommandLineToArgvW", argv != NULL);
+ argv = (char **) dom.malloc(sizeof(char*) * argc);
+ for (int i = 0; i < argc; ++i) {
+ int n_chars = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1,
+ NULL, 0, NULL, NULL);
+ dom.win32_require("WideCharToMultiByte(0)", n_chars != 0);
+ argv[i] = (char *) dom.malloc(n_chars);
+ n_chars = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1,
+ argv[i], n_chars, NULL, NULL);
+ dom.win32_require("WideCharToMultiByte(1)", n_chars != 0);
+ }
+ LocalFree(wargv);
+#endif
+ size_t vec_fill = sizeof(rust_str *) * argc;
+ size_t vec_alloc = next_power_of_two(sizeof(rust_vec) + vec_fill);
+ void *mem = dom.malloc(vec_alloc);
+ args = new (mem) rust_vec(&dom, vec_alloc, 0, NULL);
+ rust_str **strs = (rust_str**) &args->data[0];
+ for (int i = 0; i < argc; ++i) {
+ size_t str_fill = strlen(argv[i]) + 1;
+ size_t str_alloc = next_power_of_two(sizeof(rust_str) + str_fill);
+ mem = dom.malloc(str_alloc);
+ strs[i] = new (mem) rust_str(&dom, str_alloc, str_fill,
+ (uint8_t const *)argv[i]);
+ }
+ args->fill = vec_fill;
+ // If the caller has a declared args array, they may drop; but
+ // we don't know if they have such an array. So we pin the args
+ // array here to ensure it survives to program-shutdown.
+ args->ref();
+ }
+
+ ~command_line_args() {
+ if (args) {
+ // Drop the args we've had pinned here.
+ rust_str **strs = (rust_str**) &args->data[0];
+ for (int i = 0; i < argc; ++i)
+ dom.free(strs[i]);
+ dom.free(args);
+ }
+
+#ifdef __WIN32__
+ for (int i = 0; i < argc; ++i) {
+ dom.free(argv[i]);
+ }
+ dom.free(argv);
+#endif
+ }
+};
+
+
+extern "C" CDECL int
+rust_start(uintptr_t main_fn, rust_crate const *crate, int argc, char **argv)
+{
+ int ret;
+ {
+ rust_srv srv;
+ rust_dom dom(&srv, crate);
+ command_line_args args(dom, argc, argv);
+
+ dom.log(rust_log::DOM, "startup: %d args", args.argc);
+ for (int i = 0; i < args.argc; ++i)
+ dom.log(rust_log::DOM,
+ "startup: arg[%d] = '%s'", i, args.argv[i]);
+
+ if (dom._log.is_tracing(rust_log::DWARF)) {
+ rust_crate_reader rdr(&dom, crate);
+ }
+
+ uintptr_t main_args[3] = { 0, 0, (uintptr_t)args.args };
+
+ dom.root_task->start(crate->get_exit_task_glue(),
+ main_fn,
+ (uintptr_t)&main_args,
+ sizeof(main_args));
+
+ ret = rust_main_loop(&dom);
+ }
+
+#if !defined(__WIN32__)
+ // Don't take down the process if the main thread exits without an
+ // error.
+ if (!ret)
+ pthread_exit(NULL);
+#endif
+ return ret;
+}
+
+//
+// Local Variables:
+// mode: C++
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
+//