about summary refs log tree commit diff
path: root/src/rt/rust_task.h
blob: 6ae663d2066b0db18c94d8b1b748e3e4b314331e (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*
 *
 */

#ifndef RUST_TASK_H
#define RUST_TASK_H

#include <map>

#include "util/array_list.h"

#include "context.h"
#include "rust_debug.h"
#include "rust_internal.h"
#include "rust_kernel.h"
#include "rust_obstack.h"

// Corresponds to the rust chan (currently _chan) type.
struct chan_handle {
    rust_task_id task;
    rust_port_id port;
};

struct rust_box;

struct stk_seg {
    stk_seg *prev;
    stk_seg *next;
    uintptr_t end;
    unsigned int valgrind_id;
#ifndef _LP64
    uint32_t pad;
#endif

    uint8_t data[];
};

struct frame_glue_fns {
    uintptr_t mark_glue_off;
    uintptr_t drop_glue_off;
    uintptr_t reloc_glue_off;
};

// portions of the task structure that are accessible from the standard
// library. This struct must agree with the std::task::rust_task record.
struct rust_task_user {
    rust_task_id id;
    intptr_t notify_enabled;   // this is way more bits than necessary, but it
                               // simplifies the alignment.
    chan_handle notify_chan;
    uintptr_t rust_sp;         // Saved sp when not running.
};

// std::lib::task::task_result
typedef unsigned long task_result;
#define tr_success 0
#define tr_failure 1

// std::lib::task::task_notification
//
// since it's currently a unary tag, we only add the fields.
struct task_notification {
    rust_task_id id;
    task_result result; // task_result
};

struct
rust_task : public kernel_owned<rust_task>, rust_cond
{
    rust_task_user user;

    RUST_ATOMIC_REFCOUNT();

    // Fields known to the compiler.
    context ctx;
    stk_seg *stk;
    uintptr_t runtime_sp;      // Runtime sp while task running.
    rust_scheduler *sched;
    rust_crate_cache *cache;

    // Fields known only to the runtime.
    rust_kernel *kernel;
    const char *const name;
    rust_task_list *state;
    rust_cond *cond;
    const char *cond_name;
    rust_task *supervisor;     // Parent-link for failure propagation.
    int32_t list_index;

    rust_port_id next_port_id;

    // Keeps track of the last time this task yielded.
    timer yield_timer;

    // Rendezvous pointer for receiving data when blocked on a port. If we're
    // trying to read data and no data is available on any incoming channel,
    // we block on the port, and yield control to the scheduler. Since, we
    // were not able to read anything, we remember the location where the
    // result should go in the rendezvous_ptr, and let the sender write to
    // that location before waking us up.
    uintptr_t* rendezvous_ptr;

    // This flag indicates that a worker is either currently running the task
    // or is about to run this task.
    int running_on;
    int pinned_on;

    memory_region local_region;

    // Indicates that fail() has been called and we are cleaning up.
    // We use this to suppress the "killed" flag during calls to yield.
    bool unwinding;

    // Indicates that the task was killed and needs to unwind
    bool killed;
    bool propagate_failure;

    lock_and_signal lock;

    hash_map<rust_port_id, rust_port *> port_table;

    rust_obstack dynastack;

    std::map<void *,const type_desc *> local_allocs;
    uint32_t cc_counter;

    debug::task_debug_info debug;

    // The amount of stack we're using, excluding red zones
    size_t total_stack_sz;

    // Only a pointer to 'name' is kept, so it must live as long as this task.
    rust_task(rust_scheduler *sched,
              rust_task_list *state,
              rust_task *spawner,
              const char *name);

    ~rust_task();

    void start(spawn_fn spawnee_fn,
               rust_opaque_closure *env,
               void *args);
    void start();
    bool running();
    bool blocked();
    bool blocked_on(rust_cond *cond);
    bool dead();

    void *malloc(size_t sz, const char *tag, type_desc *td=0);
    void *realloc(void *data, size_t sz, bool gc_mem=false);
    void free(void *p, bool gc_mem=false);

    void transition(rust_task_list *src, rust_task_list *dst);

    void block(rust_cond *on, const char* name);
    void wakeup(rust_cond *from);
    void die();
    void unblock();

    // Print a backtrace, if the "bt" logging option is on.
    void backtrace();

    // Yields for a specified duration of time.
    void yield(size_t time_in_ms, bool *killed);

    // Fail this task (assuming caller-on-stack is different task).
    void kill();

    // Fail self, assuming caller-on-stack is this task.
    void fail();
    void conclude_failure();
    void fail_parent();

    // Disconnect from our supervisor.
    void unsupervise();

    frame_glue_fns *get_frame_glue_fns(uintptr_t fp);
    rust_crate_cache * get_crate_cache();

    bool can_schedule(int worker);

    void *calloc(size_t size, const char *tag);

    void pin();
    void pin(int id);
    void unpin();

    rust_port_id register_port(rust_port *port);
    void release_port(rust_port_id id);
    rust_port *get_port_by_id(rust_port_id id);

    // Use this function sparingly. Depending on the ref count is generally
    // not at all safe.
    intptr_t get_ref_count() const { return ref_count; }

    // FIXME: These functions only exist to get the tasking system off the
    // ground. We should never be migrating shared boxes between tasks.
    const type_desc *release_alloc(void *alloc);
    void claim_alloc(void *alloc, const type_desc *tydesc);

    void notify(bool success);

    void *new_stack(size_t stk_sz, void *args_addr, size_t args_sz);
    void del_stack();
    void record_stack_limit();
    void reset_stack_limit();
    bool on_rust_stack();
    void check_stack_canary();
};

//
// Local Variables:
// mode: C++
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

#endif /* RUST_TASK_H */