about summary refs log tree commit diff
path: root/src/rt/rust.cpp
blob: 1e708be0a49ff6cab2d6b4678282b6ae14485e94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "rust_internal.h"

struct
command_line_args : public dom_owned<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", wargv != 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
    }
};

/**
 * Main entry point into the Rust runtime. Here we create a Rust service,
 * initialize the kernel, create the root domain and run it.
 */

extern "C" CDECL int
rust_start(uintptr_t main_fn, rust_crate const *crate, int argc,
           char **argv, void* crate_map) {

    update_log_settings(crate_map, getenv("RUST_LOG"));
    rust_srv *srv = new rust_srv();
    rust_kernel *kernel = new rust_kernel(srv);
    kernel->start();
    rust_handle<rust_dom> *handle = kernel->create_domain(crate, "main");
    rust_dom *dom = handle->referent();
    command_line_args *args = new (dom) command_line_args(dom, argc, argv);

    DLOG(dom, dom, "startup: %d args in 0x%" PRIxPTR,
             args->argc, (uintptr_t)args->args);
    for (int i = 0; i < args->argc; i++) {
        DLOG(dom, dom, "startup: arg[%d] = '%s'", i, args->argv[i]);
    }

    if (log_rt_dwarf) {
        rust_crate_reader create_reader(dom, crate);
    }

    uintptr_t main_args[4] = {0, 0, 0, (uintptr_t)args->args};
    dom->root_task->start((uintptr_t)rust_new_exit_task_glue,
                          main_fn,
                          (uintptr_t)&main_args, sizeof(main_args));

    int ret = dom->start_main_loop();
    delete args;
    kernel->destroy_domain(dom);
    kernel->join_all_domains();
    delete kernel;
    delete srv;

#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:
//