Skip to content

Commit d8c5bd6

Browse files
committed
rt: Implement obstacks, untested as of yet
1 parent ca82a69 commit d8c5bd6

File tree

7 files changed

+137
-1
lines changed

7 files changed

+137
-1
lines changed

mk/rt.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ RUNTIME_CS := rt/sync/timer.cpp \
2525
rt/rust_srv.cpp \
2626
rt/rust_kernel.cpp \
2727
rt/rust_shape.cpp \
28+
rt/rust_obstack.cpp \
2829
rt/memory_region.cpp \
2930
rt/test/rust_test_harness.cpp \
3031
rt/test/rust_test_runtime.cpp \

src/rt/rust_obstack.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Object stacks, used in lieu of dynamically-sized frames.
2+
3+
#include <algorithm>
4+
#include <cassert>
5+
#include <cstdlib>
6+
#include <stdint.h>
7+
8+
#include "rust_internal.h"
9+
#include "rust_obstack.h"
10+
#include "rust_task.h"
11+
12+
// ISAAC, let go of max()!
13+
#ifdef max
14+
#undef max
15+
#endif
16+
17+
const size_t DEFAULT_CHUNK_SIZE = 4096;
18+
19+
struct rust_obstack_chunk {
20+
rust_obstack_chunk *prev;
21+
size_t size;
22+
size_t alen;
23+
size_t pad;
24+
uint8_t data[];
25+
26+
rust_obstack_chunk(rust_obstack_chunk *in_prev, size_t in_size)
27+
: prev(in_prev), size(in_size), alen(0) {}
28+
29+
void *alloc(size_t len);
30+
bool free(void *ptr);
31+
};
32+
33+
void *
34+
rust_obstack_chunk::alloc(size_t len) {
35+
if (len > size - alen)
36+
return NULL; // Not enough space.
37+
void *result = data + alen;
38+
alen += len;
39+
return result;
40+
}
41+
42+
bool
43+
rust_obstack_chunk::free(void *ptr) {
44+
uint8_t *p = (uint8_t *)ptr;
45+
if (p < data || p >= data + size)
46+
return false;
47+
assert(p < data + alen);
48+
alen = (size_t)(p - data);
49+
return true;
50+
}
51+
52+
// Allocates the given number of bytes in a new chunk.
53+
void *
54+
rust_obstack::alloc_new(size_t len) {
55+
size_t chunk_size = std::max(len, DEFAULT_CHUNK_SIZE);
56+
void *ptr = task->malloc(sizeof(chunk) + chunk_size, "obstack");
57+
chunk = new(ptr) rust_obstack_chunk(chunk, chunk_size);
58+
return chunk->alloc(len);
59+
}
60+
61+
void *
62+
rust_obstack::alloc(size_t len) {
63+
if (!chunk)
64+
return alloc_new(len);
65+
void *ptr = chunk->alloc(len);
66+
return ptr ? ptr : alloc_new(len);
67+
}
68+
69+
void
70+
rust_obstack::free(void *ptr) {
71+
if (!ptr)
72+
return;
73+
74+
assert(chunk);
75+
while (!chunk->free(ptr)) {
76+
rust_obstack_chunk *prev = chunk->prev;
77+
task->free(chunk);
78+
chunk = prev;
79+
assert(chunk);
80+
}
81+
}
82+

src/rt/rust_obstack.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Object stacks, used in lieu of dynamically-sized frames.
2+
3+
#ifndef RUST_OBSTACK_H
4+
#define RUST_OBSTACK_H
5+
6+
struct rust_obstack_chunk;
7+
struct rust_task;
8+
9+
class rust_obstack {
10+
rust_obstack_chunk *chunk;
11+
rust_task *task;
12+
13+
// Allocates the given number of bytes in a new chunk.
14+
void *alloc_new(size_t len);
15+
16+
public:
17+
rust_obstack(rust_task *in_task) : chunk(NULL), task(in_task) {}
18+
19+
void *alloc(size_t len);
20+
void free(void *ptr);
21+
};
22+
23+
#endif
24+

src/rt/rust_task.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
7575
local_region(&sched->srv->local_region),
7676
_on_wakeup(NULL),
7777
failed(false),
78-
propagate_failure(true)
78+
propagate_failure(true),
79+
dynastack(this)
7980
{
8081
LOGPTR(sched, "new task", (uintptr_t)this);
8182
DLOG(sched, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this);

src/rt/rust_task.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "util/array_list.h"
99

1010
#include "context.h"
11+
#include "rust_obstack.h"
1112

1213
struct stk_seg {
1314
unsigned int valgrind_id;
@@ -122,6 +123,8 @@ rust_task : public kernel_owned<rust_task>, rust_cond
122123

123124
hash_map<rust_port_id, rust_port *> port_table;
124125

126+
rust_obstack dynastack;
127+
125128
// Only a pointer to 'name' is kept, so it must live as long as this task.
126129
rust_task(rust_scheduler *sched,
127130
rust_task_list *state,

src/rt/rust_upcall.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,28 @@ upcall_ivec_spill_shared(rust_task *task,
417417
v->alloc = new_alloc;
418418
v->payload.ptr = heap_part;
419419
}
420+
421+
/**
422+
* Returns a token that can be used to deallocate all of the allocated space
423+
* space in the dynamic stack.
424+
*/
425+
extern "C" CDECL void *
426+
upcall_dynastack_mark(rust_task *task) {
427+
return task->dynastack.alloc(0);
428+
}
429+
430+
/** Allocates space in the dynamic stack and returns it. */
431+
extern "C" CDECL void *
432+
upcall_dynastack_alloc(rust_task *task, size_t sz) {
433+
return task->dynastack.alloc(sz);
434+
}
435+
436+
/** Frees space in the dynamic stack. */
437+
extern "C" CDECL void
438+
upcall_dynastack_free(rust_task *task, void *ptr) {
439+
return task->dynastack.free(ptr);
440+
}
441+
420442
//
421443
// Local Variables:
422444
// mode: C++

src/rt/rustrt.def.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ task_yield
8383
task_join
8484
unsupervise
8585
upcall_cmp_type
86+
upcall_dynastack_alloc
87+
upcall_dynastack_free
88+
upcall_dynastack_mark
8689
upcall_exit
8790
upcall_fail
8891
upcall_free

0 commit comments

Comments
 (0)