about summary refs log tree commit diff
path: root/src/rt/rust.cpp
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2010-06-23 21:03:09 -0700
committerGraydon Hoare <graydon@mozilla.com>2010-06-23 21:03:09 -0700
commitd6b7c96c3eb29b9244ece0c046d3f372ff432d04 (patch)
treeb425187e232966063ffc2f0d14c04a55d8f004ef /src/rt/rust.cpp
parentc01efc669f09508b55eced32d3c88702578a7c3e (diff)
downloadrust-d6b7c96c3eb29b9244ece0c046d3f372ff432d04.tar.gz
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 00000000000..8c725bfbc07
--- /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:
+//