rt: Implement obstacks, untested as of yet
This commit is contained in:
parent
ca82a690cf
commit
d8c5bd6195
1
mk/rt.mk
1
mk/rt.mk
@ -25,6 +25,7 @@ RUNTIME_CS := rt/sync/timer.cpp \
|
||||
rt/rust_srv.cpp \
|
||||
rt/rust_kernel.cpp \
|
||||
rt/rust_shape.cpp \
|
||||
rt/rust_obstack.cpp \
|
||||
rt/memory_region.cpp \
|
||||
rt/test/rust_test_harness.cpp \
|
||||
rt/test/rust_test_runtime.cpp \
|
||||
|
82
src/rt/rust_obstack.cpp
Normal file
82
src/rt/rust_obstack.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
// Object stacks, used in lieu of dynamically-sized frames.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rust_internal.h"
|
||||
#include "rust_obstack.h"
|
||||
#include "rust_task.h"
|
||||
|
||||
// ISAAC, let go of max()!
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
const size_t DEFAULT_CHUNK_SIZE = 4096;
|
||||
|
||||
struct rust_obstack_chunk {
|
||||
rust_obstack_chunk *prev;
|
||||
size_t size;
|
||||
size_t alen;
|
||||
size_t pad;
|
||||
uint8_t data[];
|
||||
|
||||
rust_obstack_chunk(rust_obstack_chunk *in_prev, size_t in_size)
|
||||
: prev(in_prev), size(in_size), alen(0) {}
|
||||
|
||||
void *alloc(size_t len);
|
||||
bool free(void *ptr);
|
||||
};
|
||||
|
||||
void *
|
||||
rust_obstack_chunk::alloc(size_t len) {
|
||||
if (len > size - alen)
|
||||
return NULL; // Not enough space.
|
||||
void *result = data + alen;
|
||||
alen += len;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
rust_obstack_chunk::free(void *ptr) {
|
||||
uint8_t *p = (uint8_t *)ptr;
|
||||
if (p < data || p >= data + size)
|
||||
return false;
|
||||
assert(p < data + alen);
|
||||
alen = (size_t)(p - data);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allocates the given number of bytes in a new chunk.
|
||||
void *
|
||||
rust_obstack::alloc_new(size_t len) {
|
||||
size_t chunk_size = std::max(len, DEFAULT_CHUNK_SIZE);
|
||||
void *ptr = task->malloc(sizeof(chunk) + chunk_size, "obstack");
|
||||
chunk = new(ptr) rust_obstack_chunk(chunk, chunk_size);
|
||||
return chunk->alloc(len);
|
||||
}
|
||||
|
||||
void *
|
||||
rust_obstack::alloc(size_t len) {
|
||||
if (!chunk)
|
||||
return alloc_new(len);
|
||||
void *ptr = chunk->alloc(len);
|
||||
return ptr ? ptr : alloc_new(len);
|
||||
}
|
||||
|
||||
void
|
||||
rust_obstack::free(void *ptr) {
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
assert(chunk);
|
||||
while (!chunk->free(ptr)) {
|
||||
rust_obstack_chunk *prev = chunk->prev;
|
||||
task->free(chunk);
|
||||
chunk = prev;
|
||||
assert(chunk);
|
||||
}
|
||||
}
|
||||
|
24
src/rt/rust_obstack.h
Normal file
24
src/rt/rust_obstack.h
Normal file
@ -0,0 +1,24 @@
|
||||
// Object stacks, used in lieu of dynamically-sized frames.
|
||||
|
||||
#ifndef RUST_OBSTACK_H
|
||||
#define RUST_OBSTACK_H
|
||||
|
||||
struct rust_obstack_chunk;
|
||||
struct rust_task;
|
||||
|
||||
class rust_obstack {
|
||||
rust_obstack_chunk *chunk;
|
||||
rust_task *task;
|
||||
|
||||
// Allocates the given number of bytes in a new chunk.
|
||||
void *alloc_new(size_t len);
|
||||
|
||||
public:
|
||||
rust_obstack(rust_task *in_task) : chunk(NULL), task(in_task) {}
|
||||
|
||||
void *alloc(size_t len);
|
||||
void free(void *ptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -75,7 +75,8 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
|
||||
local_region(&sched->srv->local_region),
|
||||
_on_wakeup(NULL),
|
||||
failed(false),
|
||||
propagate_failure(true)
|
||||
propagate_failure(true),
|
||||
dynastack(this)
|
||||
{
|
||||
LOGPTR(sched, "new task", (uintptr_t)this);
|
||||
DLOG(sched, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "util/array_list.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "rust_obstack.h"
|
||||
|
||||
struct stk_seg {
|
||||
unsigned int valgrind_id;
|
||||
@ -122,6 +123,8 @@ rust_task : public kernel_owned<rust_task>, rust_cond
|
||||
|
||||
hash_map<rust_port_id, rust_port *> port_table;
|
||||
|
||||
rust_obstack dynastack;
|
||||
|
||||
// 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,
|
||||
|
@ -417,6 +417,28 @@ upcall_ivec_spill_shared(rust_task *task,
|
||||
v->alloc = new_alloc;
|
||||
v->payload.ptr = heap_part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a token that can be used to deallocate all of the allocated space
|
||||
* space in the dynamic stack.
|
||||
*/
|
||||
extern "C" CDECL void *
|
||||
upcall_dynastack_mark(rust_task *task) {
|
||||
return task->dynastack.alloc(0);
|
||||
}
|
||||
|
||||
/** Allocates space in the dynamic stack and returns it. */
|
||||
extern "C" CDECL void *
|
||||
upcall_dynastack_alloc(rust_task *task, size_t sz) {
|
||||
return task->dynastack.alloc(sz);
|
||||
}
|
||||
|
||||
/** Frees space in the dynamic stack. */
|
||||
extern "C" CDECL void
|
||||
upcall_dynastack_free(rust_task *task, void *ptr) {
|
||||
return task->dynastack.free(ptr);
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: C++
|
||||
|
@ -83,6 +83,9 @@ task_yield
|
||||
task_join
|
||||
unsupervise
|
||||
upcall_cmp_type
|
||||
upcall_dynastack_alloc
|
||||
upcall_dynastack_free
|
||||
upcall_dynastack_mark
|
||||
upcall_exit
|
||||
upcall_fail
|
||||
upcall_free
|
||||
|
Loading…
Reference in New Issue
Block a user