Lots of work on memory tracking and channels.

We're trying to get closer to doing correct move semantics for channel
operations. This involves a lot of cleanup (such as removing the
unused sched parameter from rust_vec constructor) and making
circular_buffer kernel_owned.

Added tagging for memory allocations. This means we give a string tag
to everything we allocate. If we leak something and TRACK_ALLOCATIONS
is enabled, then it's much easier now to tell exactly what is leaking.
This commit is contained in:
Eric Holk 2011-07-18 12:02:26 -07:00 committed by Brian Anderson
parent a44fb04d57
commit 3ae4dcd41e
24 changed files with 313 additions and 240 deletions

View File

@ -38,6 +38,7 @@ type upcalls =
ValueRef flush_chan, ValueRef flush_chan,
ValueRef del_chan, ValueRef del_chan,
ValueRef clone_chan, ValueRef clone_chan,
ValueRef chan_target_task,
ValueRef _yield, ValueRef _yield,
ValueRef sleep, ValueRef sleep,
ValueRef send, ValueRef send,
@ -95,6 +96,9 @@ fn declare_upcalls(type_names tn, TypeRef tydesc_type, TypeRef taskptr_type,
del_chan=dv("del_chan", ~[T_opaque_chan_ptr()]), del_chan=dv("del_chan", ~[T_opaque_chan_ptr()]),
clone_chan=d("clone_chan", ~[taskptr_type, T_opaque_chan_ptr()], clone_chan=d("clone_chan", ~[taskptr_type, T_opaque_chan_ptr()],
T_opaque_chan_ptr()), T_opaque_chan_ptr()),
chan_target_task=d("chan_target_task",
~[T_opaque_chan_ptr()],
taskptr_type),
_yield=dv("yield", empty_vec), _yield=dv("yield", empty_vec),
sleep=dv("sleep", ~[T_size_t()]), sleep=dv("sleep", ~[T_size_t()]),
send=dv("send", ~[T_opaque_chan_ptr(), T_ptr(T_i8())]), send=dv("send", ~[T_opaque_chan_ptr(), T_ptr(T_i8())]),

View File

@ -22,6 +22,12 @@ import back::link::mangle_internal_name_by_path_and_seq;
import trans_common::*; import trans_common::*;
import trans::*; import trans::*;
export trans_port;
export trans_chan;
export trans_spawn;
export trans_send;
export trans_recv;
fn trans_port(&@block_ctxt cx, ast::node_id id) -> result { fn trans_port(&@block_ctxt cx, ast::node_id id) -> result {
auto t = node_id_type(cx.fcx.lcx.ccx, id); auto t = node_id_type(cx.fcx.lcx.ccx, id);
auto unit_ty; auto unit_ty;
@ -123,13 +129,7 @@ fn trans_spawn(&@block_ctxt cx, &ast::spawn_dom dom, &option::t[str] name,
auto llargs = alloc_ty(bcx, args_ty); auto llargs = alloc_ty(bcx, args_ty);
auto i = 0u; auto i = 0u;
for (ValueRef v in arg_vals) { for (ValueRef v in arg_vals) {
// log_err #fmt("ty(llargs) = %s",
// val_str(bcx.fcx.lcx.ccx.tn, llargs.val));
auto target = bcx.build.GEP(llargs.val, ~[C_int(0), C_int(i as int)]); auto target = bcx.build.GEP(llargs.val, ~[C_int(0), C_int(i as int)]);
// log_err #fmt("ty(v) = %s", val_str(bcx.fcx.lcx.ccx.tn, v));
// log_err #fmt("ty(target) = %s",
// val_str(bcx.fcx.lcx.ccx.tn, target));
bcx.build.Store(v, target); bcx.build.Store(v, target);
i += 1u; i += 1u;
@ -199,55 +199,6 @@ fn mk_spawn_wrapper(&@block_ctxt cx, &@ast::expr func, &ty::t args_ty) ->
ret rslt(cx, llfndecl); ret rslt(cx, llfndecl);
} }
// Does a deep copy of a value. This is needed for passing arguments to child
// tasks, and for sending things through channels. There are probably some
// uniqueness optimizations and things we can do here for tasks in the same
// domain.
fn deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t, ValueRef target_task)
-> result
{
// TODO: make sure all paths add any reference counting that they need to.
// TODO: Teach deep copy to understand everything else it needs to.
auto tcx = bcx.fcx.lcx.ccx.tcx;
if(ty::type_is_scalar(tcx, t)) {
ret rslt(bcx, v);
}
else if(ty::type_is_str(tcx, t)) {
ret rslt(bcx,
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.dup_str,
~[bcx.fcx.lltaskptr, target_task, v]));
}
else if(ty::type_is_chan(tcx, t)) {
// If this is a channel, we need to clone it.
auto chan_ptr = bcx.build.PointerCast(v, T_opaque_chan_ptr());
auto chan_raw_val =
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.clone_chan,
~[bcx.fcx.lltaskptr, target_task, chan_ptr]);
// Cast back to the type the context was expecting.
auto chan_val = bcx.build.PointerCast(chan_raw_val,
val_ty(v));
ret rslt(bcx, chan_val);
}
else if(ty::type_is_structural(tcx, t)) {
fn inner_deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t) -> result {
log_err "Unimplemented type for deep_copy.";
fail;
}
ret iter_structural_ty(bcx, v, t, inner_deep_copy);
}
else {
bcx.fcx.lcx.ccx.sess.bug("unexpected type in " +
"trans::deep_copy: " +
ty_to_str(tcx, t));
}
}
fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs, fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
ast::node_id id) -> result { ast::node_id id) -> result {
auto bcx = cx; auto bcx = cx;
@ -302,3 +253,52 @@ fn recv_val(&@block_ctxt cx, ValueRef to, &@ast::expr from, &ty::t unit_ty,
ret rslt(bcx, to); ret rslt(bcx, to);
} }
// Does a deep copy of a value. This is needed for passing arguments to child
// tasks, and for sending things through channels. There are probably some
// uniqueness optimizations and things we can do here for tasks in the same
// domain.
fn deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t, ValueRef target_task)
-> result
{
// TODO: make sure all paths add any reference counting that they need to.
// TODO: Teach deep copy to understand everything else it needs to.
auto tcx = bcx.fcx.lcx.ccx.tcx;
if(ty::type_is_scalar(tcx, t)) {
ret rslt(bcx, v);
}
else if(ty::type_is_str(tcx, t)) {
ret rslt(bcx,
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.dup_str,
~[bcx.fcx.lltaskptr, target_task, v]));
}
else if(ty::type_is_chan(tcx, t)) {
// If this is a channel, we need to clone it.
auto chan_ptr = bcx.build.PointerCast(v, T_opaque_chan_ptr());
auto chan_raw_val =
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.clone_chan,
~[bcx.fcx.lltaskptr, target_task, chan_ptr]);
// Cast back to the type the context was expecting.
auto chan_val = bcx.build.PointerCast(chan_raw_val,
val_ty(v));
ret rslt(bcx, chan_val);
}
else if(ty::type_is_structural(tcx, t)) {
fn inner_deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t) -> result {
log_err "Unimplemented type for deep_copy.";
fail;
}
ret iter_structural_ty(bcx, v, t, inner_deep_copy);
}
else {
bcx.fcx.lcx.ccx.sess.bug("unexpected type in " +
"trans::deep_copy: " +
ty_to_str(tcx, t));
}
}

View File

@ -4,14 +4,14 @@
#include "rust_internal.h" #include "rust_internal.h"
circular_buffer::circular_buffer(rust_task *task, size_t unit_sz) : circular_buffer::circular_buffer(rust_kernel *kernel, size_t unit_sz) :
sched(task->sched), sched(kernel->sched),
task(task), kernel(kernel),
unit_sz(unit_sz), unit_sz(unit_sz),
_buffer_sz(initial_size()), _buffer_sz(initial_size()),
_next(0), _next(0),
_unread(0), _unread(0),
_buffer((uint8_t *)task->malloc(_buffer_sz)) { _buffer((uint8_t *)kernel->malloc(_buffer_sz, "circular_buffer")) {
A(sched, unit_sz, "Unit size must be larger than zero."); A(sched, unit_sz, "Unit size must be larger than zero.");
@ -20,7 +20,6 @@ circular_buffer::circular_buffer(rust_task *task, size_t unit_sz) :
_buffer_sz, _unread, this); _buffer_sz, _unread, this);
A(sched, _buffer, "Failed to allocate buffer."); A(sched, _buffer, "Failed to allocate buffer.");
task->ref();
} }
circular_buffer::~circular_buffer() { circular_buffer::~circular_buffer() {
@ -28,8 +27,7 @@ circular_buffer::~circular_buffer() {
I(sched, _buffer); I(sched, _buffer);
W(sched, _unread == 0, W(sched, _unread == 0,
"freeing circular_buffer with %d unread bytes", _unread); "freeing circular_buffer with %d unread bytes", _unread);
task->free(_buffer); kernel->free(_buffer);
--task->ref_count;
} }
size_t size_t
@ -144,9 +142,10 @@ circular_buffer::grow() {
size_t new_buffer_sz = _buffer_sz * 2; size_t new_buffer_sz = _buffer_sz * 2;
I(sched, new_buffer_sz <= MAX_CIRCULAR_BUFFER_SIZE); I(sched, new_buffer_sz <= MAX_CIRCULAR_BUFFER_SIZE);
DLOG(sched, mem, "circular_buffer is growing to %d bytes", new_buffer_sz); DLOG(sched, mem, "circular_buffer is growing to %d bytes", new_buffer_sz);
void *new_buffer = task->malloc(new_buffer_sz); void *new_buffer = kernel->malloc(new_buffer_sz,
"new circular_buffer (grow)");
transfer(new_buffer); transfer(new_buffer);
task->free(_buffer); kernel->free(_buffer);
_buffer = (uint8_t *)new_buffer; _buffer = (uint8_t *)new_buffer;
_next = 0; _next = 0;
_buffer_sz = new_buffer_sz; _buffer_sz = new_buffer_sz;
@ -158,9 +157,10 @@ circular_buffer::shrink() {
I(sched, initial_size() <= new_buffer_sz); I(sched, initial_size() <= new_buffer_sz);
DLOG(sched, mem, "circular_buffer is shrinking to %d bytes", DLOG(sched, mem, "circular_buffer is shrinking to %d bytes",
new_buffer_sz); new_buffer_sz);
void *new_buffer = task->malloc(new_buffer_sz); void *new_buffer = kernel->malloc(new_buffer_sz,
"new circular_buffer (shrink)");
transfer(new_buffer); transfer(new_buffer);
task->free(_buffer); kernel->free(_buffer);
_buffer = (uint8_t *)new_buffer; _buffer = (uint8_t *)new_buffer;
_next = 0; _next = 0;
_buffer_sz = new_buffer_sz; _buffer_sz = new_buffer_sz;

View File

@ -6,17 +6,17 @@
#define CIRCULAR_BUFFER_H #define CIRCULAR_BUFFER_H
class class
circular_buffer : public task_owned<circular_buffer> { circular_buffer : public kernel_owned<circular_buffer> {
static const size_t INITIAL_CIRCULAR_BUFFER_SIZE_IN_UNITS = 8; static const size_t INITIAL_CIRCULAR_BUFFER_SIZE_IN_UNITS = 8;
static const size_t MAX_CIRCULAR_BUFFER_SIZE = 1 << 24; static const size_t MAX_CIRCULAR_BUFFER_SIZE = 1 << 24;
rust_scheduler *sched; rust_scheduler *sched;
public: public:
rust_task *task; rust_kernel *kernel;
// Size of the data unit in bytes. // Size of the data unit in bytes.
const size_t unit_sz; const size_t unit_sz;
circular_buffer(rust_task *task, size_t unit_sz); circular_buffer(rust_kernel *kernel, size_t unit_sz);
~circular_buffer(); ~circular_buffer();
void transfer(void *dst); void transfer(void *dst);
void enqueue(void *src); void enqueue(void *src);

View File

@ -3,33 +3,38 @@
#define MEMORY_H #define MEMORY_H
// FIXME: It would be really nice to be able to get rid of this. // FIXME: It would be really nice to be able to get rid of this.
inline void *operator new[](size_t size, rust_task *task) { inline void *operator new[](size_t size, rust_task *task, const char *tag) {
return task->malloc(size); return task->malloc(size, tag);
} }
template <typename T> template <typename T>
inline void *task_owned<T>::operator new(size_t size, rust_task *task) { inline void *task_owned<T>::operator new(size_t size, rust_task *task,
return task->malloc(size); const char *tag) {
return task->malloc(size, tag);
} }
template <typename T> template <typename T>
inline void *task_owned<T>::operator new[](size_t size, rust_task *task) { inline void *task_owned<T>::operator new[](size_t size, rust_task *task,
return task->malloc(size); const char *tag) {
return task->malloc(size, tag);
} }
template <typename T> template <typename T>
inline void *task_owned<T>::operator new(size_t size, rust_task &task) { inline void *task_owned<T>::operator new(size_t size, rust_task &task,
return task.malloc(size); const char *tag) {
return task.malloc(size, tag);
} }
template <typename T> template <typename T>
inline void *task_owned<T>::operator new[](size_t size, rust_task &task) { inline void *task_owned<T>::operator new[](size_t size, rust_task &task,
return task.malloc(size); const char *tag) {
return task.malloc(size, tag);
} }
template <typename T> template <typename T>
inline void *kernel_owned<T>::operator new(size_t size, rust_kernel *kernel) { inline void *kernel_owned<T>::operator new(size_t size, rust_kernel *kernel,
return kernel->malloc(size); const char *tag) {
return kernel->malloc(size, tag);
} }

View File

@ -4,7 +4,13 @@
// NB: please do not commit code with this uncommented. It's // NB: please do not commit code with this uncommented. It's
// hugely expensive and should only be used as a last resort. // hugely expensive and should only be used as a last resort.
// //
// #define TRACK_ALLOCATIONS #define TRACK_ALLOCATIONS
#define MAGIC 0xbadc0ffe
memory_region::alloc_header *memory_region::get_header(void *mem) {
return (alloc_header *)((char *)mem - sizeof(alloc_header));
}
memory_region::memory_region(rust_srv *srv, bool synchronized) : memory_region::memory_region(rust_srv *srv, bool synchronized) :
_srv(srv), _parent(NULL), _live_allocations(0), _srv(srv), _parent(NULL), _live_allocations(0),
@ -19,37 +25,37 @@ memory_region::memory_region(memory_region *parent) :
} }
void memory_region::add_alloc() { void memory_region::add_alloc() {
//_live_allocations++; _live_allocations++;
sync::increment(_live_allocations); //sync::increment(_live_allocations);
} }
void memory_region::dec_alloc() { void memory_region::dec_alloc() {
//_live_allocations--; _live_allocations--;
sync::decrement(_live_allocations); //sync::decrement(_live_allocations);
} }
void memory_region::free(void *mem) { void memory_region::free(void *mem) {
// printf("free: ptr 0x%" PRIxPTR" region=%p\n", (uintptr_t) mem, this); // printf("free: ptr 0x%" PRIxPTR" region=%p\n", (uintptr_t) mem, this);
if (!mem) { return; } if (!mem) { return; }
if (_synchronized) { _lock.lock(); } if (_synchronized) { _lock.lock(); }
alloc_header *alloc = get_header(mem);
assert(alloc->magic == MAGIC);
#ifdef TRACK_ALLOCATIONS #ifdef TRACK_ALLOCATIONS
int index = ((int *)mem)[-1]; if (_allocation_list[alloc->index] != alloc) {
if (_allocation_list[index] != (uint8_t *)mem - sizeof(int)) {
printf("free: ptr 0x%" PRIxPTR " is not in allocation_list\n", printf("free: ptr 0x%" PRIxPTR " is not in allocation_list\n",
(uintptr_t) mem); (uintptr_t) mem);
_srv->fatal("not in allocation_list", __FILE__, __LINE__, ""); _srv->fatal("not in allocation_list", __FILE__, __LINE__, "");
} }
else { else {
// printf("freed index %d\n", index); // printf("freed index %d\n", index);
_allocation_list[index] = NULL; _allocation_list[alloc->index] = NULL;
} }
mem = (void*)((uint8_t*)mem - sizeof(int));
#endif #endif
if (_live_allocations < 1) { if (_live_allocations < 1) {
_srv->fatal("live_allocs < 1", __FILE__, __LINE__, ""); _srv->fatal("live_allocs < 1", __FILE__, __LINE__, "");
} }
dec_alloc(); dec_alloc();
_srv->free(mem); _srv->free(alloc);
if (_synchronized) { _lock.unlock(); } if (_synchronized) { _lock.unlock(); }
} }
@ -59,77 +65,55 @@ memory_region::realloc(void *mem, size_t size) {
if (!mem) { if (!mem) {
add_alloc(); add_alloc();
} }
size += sizeof(alloc_header);
alloc_header *alloc = get_header(mem);
assert(alloc->magic == MAGIC);
alloc_header *newMem = (alloc_header *)_srv->realloc(alloc, size);
#ifdef TRACK_ALLOCATIONS #ifdef TRACK_ALLOCATIONS
size += sizeof(int); if (_allocation_list[newMem->index] != alloc) {
mem = (void*)((uint8_t*)mem - sizeof(int));
int index = *(int *)mem;
#endif
void *newMem = _srv->realloc(mem, size);
#ifdef TRACK_ALLOCATIONS
if (_allocation_list[index] != mem) {
printf("at index %d, found %p, expected %p\n", printf("at index %d, found %p, expected %p\n",
index, _allocation_list[index], mem); alloc->index, _allocation_list[alloc->index], alloc);
printf("realloc: ptr 0x%" PRIxPTR " is not in allocation_list\n", printf("realloc: ptr 0x%" PRIxPTR " is not in allocation_list\n",
(uintptr_t) mem); (uintptr_t) mem);
_srv->fatal("not in allocation_list", __FILE__, __LINE__, ""); _srv->fatal("not in allocation_list", __FILE__, __LINE__, "");
} }
else { else {
_allocation_list[index] = newMem; _allocation_list[newMem->index] = newMem;
(*(int*)newMem) = index;
// printf("realloc: stored %p at index %d, replacing %p\n", // printf("realloc: stored %p at index %d, replacing %p\n",
// newMem, index, mem); // newMem, index, mem);
} }
#endif #endif
if (_synchronized) { _lock.unlock(); } if (_synchronized) { _lock.unlock(); }
#ifdef TRACK_ALLOCATIONS return newMem->data;
newMem = (void *)((uint8_t*)newMem + sizeof(int));
#endif
return newMem;
} }
void * void *
memory_region::malloc(size_t size) { memory_region::malloc(size_t size, const char *tag, bool zero) {
if (_synchronized) { _lock.lock(); } if (_synchronized) { _lock.lock(); }
add_alloc(); add_alloc();
size_t old_size = size;
size += sizeof(alloc_header);
alloc_header *mem = (alloc_header *)_srv->malloc(size);
mem->magic = MAGIC;
mem->tag = tag;
#ifdef TRACK_ALLOCATIONS #ifdef TRACK_ALLOCATIONS
size += sizeof(int); mem->index = _allocation_list.append(mem);
#endif
void *mem = _srv->malloc(size);
#ifdef TRACK_ALLOCATIONS
int index = _allocation_list.append(mem);
int *p = (int *)mem;
*p = index;
// printf("malloc: stored %p at index %d\n", mem, index); // printf("malloc: stored %p at index %d\n", mem, index);
#endif #endif
// printf("malloc: ptr 0x%" PRIxPTR " region=%p\n", // printf("malloc: ptr 0x%" PRIxPTR " region=%p\n",
// (uintptr_t) mem, this); // (uintptr_t) mem, this);
if(zero) {
memset(mem->data, 0, old_size);
}
if (_synchronized) { _lock.unlock(); } if (_synchronized) { _lock.unlock(); }
#ifdef TRACK_ALLOCATIONS return mem->data;
mem = (void*)((uint8_t*)mem + sizeof(int));
#endif
return mem;
} }
void * void *
memory_region::calloc(size_t size) { memory_region::calloc(size_t size, const char *tag) {
if (_synchronized) { _lock.lock(); } return malloc(size, tag, true);
add_alloc();
#ifdef TRACK_ALLOCATIONS
size += sizeof(int);
#endif
void *mem = _srv->malloc(size);
memset(mem, 0, size);
#ifdef TRACK_ALLOCATIONS
int index = _allocation_list.append(mem);
int *p = (int *)mem;
*p = index;
// printf("calloc: stored %p at index %d\n", mem, index);
#endif
if (_synchronized) { _lock.unlock(); }
#ifdef TRACK_ALLOCATIONS
mem = (void*)((uint8_t*)mem + sizeof(int));
#endif
return mem;
} }
memory_region::~memory_region() { memory_region::~memory_region() {

View File

@ -15,10 +15,19 @@ class rust_srv;
class memory_region { class memory_region {
private: private:
struct alloc_header {
uint32_t magic;
int index;
const char *tag;
char data[];
};
alloc_header *get_header(void *mem);
rust_srv *_srv; rust_srv *_srv;
memory_region *_parent; memory_region *_parent;
size_t _live_allocations; size_t _live_allocations;
array_list<void *> _allocation_list; array_list<alloc_header *> _allocation_list;
const bool _detailed_leaks; const bool _detailed_leaks;
const bool _synchronized; const bool _synchronized;
lock_and_signal _lock; lock_and_signal _lock;
@ -29,8 +38,8 @@ private:
public: public:
memory_region(rust_srv *srv, bool synchronized); memory_region(rust_srv *srv, bool synchronized);
memory_region(memory_region *parent); memory_region(memory_region *parent);
void *malloc(size_t size); void *malloc(size_t size, const char *tag, bool zero = true);
void *calloc(size_t size); void *calloc(size_t size, const char *tag);
void *realloc(void *mem, size_t size); void *realloc(void *mem, size_t size);
void free(void *mem); void free(void *mem);
virtual ~memory_region(); virtual ~memory_region();
@ -40,12 +49,14 @@ public:
void hack_allow_leaks(); void hack_allow_leaks();
}; };
inline void *operator new(size_t size, memory_region &region) { inline void *operator new(size_t size, memory_region &region,
return region.malloc(size); const char *tag) {
return region.malloc(size, tag);
} }
inline void *operator new(size_t size, memory_region *region) { inline void *operator new(size_t size, memory_region *region,
return region->malloc(size); const char *tag) {
return region->malloc(size, tag);
} }
// //

View File

@ -24,12 +24,14 @@ command_line_args : public kernel_owned<command_line_args>
LPCWSTR cmdline = GetCommandLineW(); LPCWSTR cmdline = GetCommandLineW();
LPWSTR *wargv = CommandLineToArgvW(cmdline, &argc); LPWSTR *wargv = CommandLineToArgvW(cmdline, &argc);
kernel->win32_require("CommandLineToArgvW", wargv != NULL); kernel->win32_require("CommandLineToArgvW", wargv != NULL);
argv = (char **) kernel->malloc(sizeof(char*) * argc); argv = (char **) kernel->malloc(sizeof(char*) * argc,
"win32 command line");
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
int n_chars = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, int n_chars = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1,
NULL, 0, NULL, NULL); NULL, 0, NULL, NULL);
kernel->win32_require("WideCharToMultiByte(0)", n_chars != 0); kernel->win32_require("WideCharToMultiByte(0)", n_chars != 0);
argv[i] = (char *) kernel->malloc(n_chars); argv[i] = (char *) kernel->malloc(n_chars,
"win32 command line arg");
n_chars = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, n_chars = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1,
argv[i], n_chars, NULL, NULL); argv[i], n_chars, NULL, NULL);
kernel->win32_require("WideCharToMultiByte(1)", n_chars != 0); kernel->win32_require("WideCharToMultiByte(1)", n_chars != 0);
@ -38,14 +40,14 @@ command_line_args : public kernel_owned<command_line_args>
#endif #endif
size_t vec_fill = sizeof(rust_str *) * argc; size_t vec_fill = sizeof(rust_str *) * argc;
size_t vec_alloc = next_power_of_two(sizeof(rust_vec) + vec_fill); size_t vec_alloc = next_power_of_two(sizeof(rust_vec) + vec_fill);
void *mem = kernel->malloc(vec_alloc); void *mem = kernel->malloc(vec_alloc, "command line");
args = new (mem) rust_vec(task->sched, vec_alloc, 0, NULL); args = new (mem) rust_vec(vec_alloc, 0, NULL);
rust_str **strs = (rust_str**) &args->data[0]; rust_str **strs = (rust_str**) &args->data[0];
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
size_t str_fill = strlen(argv[i]) + 1; size_t str_fill = strlen(argv[i]) + 1;
size_t str_alloc = next_power_of_two(sizeof(rust_str) + str_fill); size_t str_alloc = next_power_of_two(sizeof(rust_str) + str_fill);
mem = kernel->malloc(str_alloc); mem = kernel->malloc(str_alloc, "command line arg");
strs[i] = new (mem) rust_str(task->sched, str_alloc, str_fill, strs[i] = new (mem) rust_str(str_alloc, str_fill,
(uint8_t const *)argv[i]); (uint8_t const *)argv[i]);
} }
args->fill = vec_fill; args->fill = vec_fill;
@ -106,7 +108,8 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
kernel->start(); kernel->start();
rust_scheduler *sched = kernel->get_scheduler(); rust_scheduler *sched = kernel->get_scheduler();
command_line_args *args command_line_args *args
= new (kernel) command_line_args(sched->root_task, argc, argv); = new (kernel, "main command line args")
command_line_args(sched->root_task, argc, argv);
DLOG(sched, dom, "startup: %d args in 0x%" PRIxPTR, DLOG(sched, dom, "startup: %d args in 0x%" PRIxPTR,
args->argc, (uintptr_t)args->args); args->argc, (uintptr_t)args->args);

View File

@ -9,7 +9,6 @@
extern "C" CDECL rust_str* extern "C" CDECL rust_str*
last_os_error(rust_task *task) { last_os_error(rust_task *task) {
rust_scheduler *sched = task->sched;
LOG(task, task, "last_os_error()"); LOG(task, task, "last_os_error()");
#if defined(__WIN32__) #if defined(__WIN32__)
@ -42,12 +41,12 @@ last_os_error(rust_task *task) {
#endif #endif
size_t fill = strlen(buf) + 1; size_t fill = strlen(buf) + 1;
size_t alloc = next_power_of_two(sizeof(rust_str) + fill); size_t alloc = next_power_of_two(sizeof(rust_str) + fill);
void *mem = task->malloc(alloc); void *mem = task->malloc(alloc, "rust_str(last_os_error)");
if (!mem) { if (!mem) {
task->fail(); task->fail();
return NULL; return NULL;
} }
rust_str *st = new (mem) rust_str(sched, alloc, fill, rust_str *st = new (mem) rust_str(alloc, fill,
(const uint8_t *)buf); (const uint8_t *)buf);
#ifdef __WIN32__ #ifdef __WIN32__
@ -58,7 +57,6 @@ last_os_error(rust_task *task) {
extern "C" CDECL rust_str * extern "C" CDECL rust_str *
rust_getcwd(rust_task *task) { rust_getcwd(rust_task *task) {
rust_scheduler *sched = task->sched;
LOG(task, task, "rust_getcwd()"); LOG(task, task, "rust_getcwd()");
char cbuf[BUF_BYTES]; char cbuf[BUF_BYTES];
@ -74,14 +72,14 @@ rust_getcwd(rust_task *task) {
size_t fill = strlen(cbuf) + 1; size_t fill = strlen(cbuf) + 1;
size_t alloc = next_power_of_two(sizeof(rust_str) + fill); size_t alloc = next_power_of_two(sizeof(rust_str) + fill);
void *mem = task->malloc(alloc); void *mem = task->malloc(alloc, "rust_str(getcwd)");
if (!mem) { if (!mem) {
task->fail(); task->fail();
return NULL; return NULL;
} }
rust_str *st; rust_str *st;
st = new (mem) rust_str(sched, alloc, fill, (const uint8_t *)cbuf); st = new (mem) rust_str(alloc, fill, (const uint8_t *)cbuf);
return st; return st;
} }
@ -125,17 +123,16 @@ unsupervise(rust_task *task) {
extern "C" CDECL rust_vec* extern "C" CDECL rust_vec*
vec_alloc(rust_task *task, type_desc *t, type_desc *elem_t, size_t n_elts) vec_alloc(rust_task *task, type_desc *t, type_desc *elem_t, size_t n_elts)
{ {
rust_scheduler *sched = task->sched;
LOG(task, mem, "vec_alloc %" PRIdPTR " elements of size %" PRIdPTR, LOG(task, mem, "vec_alloc %" PRIdPTR " elements of size %" PRIdPTR,
n_elts, elem_t->size); n_elts, elem_t->size);
size_t fill = n_elts * elem_t->size; size_t fill = n_elts * elem_t->size;
size_t alloc = next_power_of_two(sizeof(rust_vec) + fill); size_t alloc = next_power_of_two(sizeof(rust_vec) + fill);
void *mem = task->malloc(alloc, t->is_stateful ? t : NULL); void *mem = task->malloc(alloc, "rust_vec", t->is_stateful ? t : NULL);
if (!mem) { if (!mem) {
task->fail(); task->fail();
return NULL; return NULL;
} }
rust_vec *vec = new (mem) rust_vec(sched, alloc, 0, NULL); rust_vec *vec = new (mem) rust_vec(alloc, 0, NULL);
return vec; return vec;
} }
@ -199,11 +196,10 @@ vec_alloc_with_data(rust_task *task,
size_t elt_size, size_t elt_size,
void *d) void *d)
{ {
rust_scheduler *sched = task->sched;
size_t alloc = next_power_of_two(sizeof(rust_vec) + (n_elts * elt_size)); size_t alloc = next_power_of_two(sizeof(rust_vec) + (n_elts * elt_size));
void *mem = task->malloc(alloc); void *mem = task->malloc(alloc, "rust_vec (with data)");
if (!mem) return NULL; if (!mem) return NULL;
return new (mem) rust_vec(sched, alloc, fill * elt_size, (uint8_t*)d); return new (mem) rust_vec(alloc, fill * elt_size, (uint8_t*)d);
} }
extern "C" CDECL rust_vec* extern "C" CDECL rust_vec*
@ -377,7 +373,7 @@ extern "C" CDECL void *
rand_new(rust_task *task) rand_new(rust_task *task)
{ {
rust_scheduler *sched = task->sched; rust_scheduler *sched = task->sched;
randctx *rctx = (randctx *) task->malloc(sizeof(randctx)); randctx *rctx = (randctx *) task->malloc(sizeof(randctx), "randctx");
if (!rctx) { if (!rctx) {
task->fail(); task->fail();
return NULL; return NULL;
@ -619,8 +615,9 @@ rust_list_files_ivec(rust_task *task, rust_str *path) {
sizeof(size_t) // fill sizeof(size_t) // fill
+ sizeof(size_t) // alloc + sizeof(size_t) // alloc
+ sizeof(rust_str *) * 4; // payload + sizeof(rust_str *) * 4; // payload
rust_box *box = (rust_box *)task->malloc(sizeof(rust_box) + rust_box *box = (rust_box *)task->malloc(sizeof(rust_box) + str_ivec_sz,
str_ivec_sz); "rust_box(list_files_ivec)");
box->ref_count = 1; box->ref_count = 1;
rust_ivec *iv = (rust_ivec *)&box->data; rust_ivec *iv = (rust_ivec *)&box->data;
iv->fill = 0; iv->fill = 0;
@ -628,7 +625,7 @@ rust_list_files_ivec(rust_task *task, rust_str *path) {
size_t alloc_sz = sizeof(rust_str *) * strings.size(); size_t alloc_sz = sizeof(rust_str *) * strings.size();
iv->alloc = alloc_sz; iv->alloc = alloc_sz;
iv->payload.ptr = (rust_ivec_heap *) iv->payload.ptr = (rust_ivec_heap *)
task->kernel->malloc(alloc_sz + sizeof(size_t)); task->kernel->malloc(alloc_sz + sizeof(size_t), "files ivec");
iv->payload.ptr->fill = alloc_sz; iv->payload.ptr->fill = alloc_sz;
memcpy(&iv->payload.ptr->data, strings.data(), alloc_sz); memcpy(&iv->payload.ptr->data, strings.data(), alloc_sz);
return box; return box;
@ -706,7 +703,8 @@ ivec_reserve(rust_task *task, type_desc *ty, rust_ivec *v, size_t n_elems)
if (v->fill || !v->payload.ptr) { if (v->fill || !v->payload.ptr) {
// On stack; spill to heap. // On stack; spill to heap.
heap_part = (rust_ivec_heap *)task->malloc(new_alloc + heap_part = (rust_ivec_heap *)task->malloc(new_alloc +
sizeof(size_t)); sizeof(size_t),
"ivec reserve heap part");
heap_part->fill = v->fill; heap_part->fill = v->fill;
memcpy(&heap_part->data, v->payload.data, v->fill); memcpy(&heap_part->data, v->payload.data, v->fill);
@ -737,8 +735,9 @@ ivec_reserve_shared(rust_task *task, type_desc *ty, rust_ivec *v,
rust_ivec_heap *heap_part; rust_ivec_heap *heap_part;
if (v->fill || !v->payload.ptr) { if (v->fill || !v->payload.ptr) {
// On stack; spill to heap. // On stack; spill to heap.
heap_part = (rust_ivec_heap *)task->kernel->malloc(new_alloc + heap_part = (rust_ivec_heap *)
sizeof(size_t)); task->kernel->malloc(new_alloc + sizeof(size_t),
"ivec reserve shared");
heap_part->fill = v->fill; heap_part->fill = v->fill;
memcpy(&heap_part->data, v->payload.data, v->fill); memcpy(&heap_part->data, v->payload.data, v->fill);

View File

@ -11,22 +11,21 @@ rust_chan::rust_chan(rust_task *task,
kernel(task->kernel), kernel(task->kernel),
task(task), task(task),
port(port), port(port),
buffer(task, unit_sz) { buffer(kernel, unit_sz) {
++task->ref_count;
if (port) { if (port) {
associate(port); associate(port);
} }
LOG(task, comm, "new rust_chan(task=0x%" PRIxPTR DLOG(kernel->sched, comm, "new rust_chan(task=0x%" PRIxPTR
", port=0x%" PRIxPTR ") -> chan=0x%" PRIxPTR, ", port=0x%" PRIxPTR ") -> chan=0x%" PRIxPTR,
(uintptr_t) task, (uintptr_t) port, (uintptr_t) this); (uintptr_t) task, (uintptr_t) port, (uintptr_t) this);
} }
rust_chan::~rust_chan() { rust_chan::~rust_chan() {
LOG(task, comm, "del rust_chan(task=0x%" PRIxPTR ")", (uintptr_t) this); DLOG(kernel->sched, comm, "del rust_chan(task=0x%" PRIxPTR ")",
(uintptr_t) this);
A(task->sched, is_associated() == false, A(kernel->sched, is_associated() == false,
"Channel must be disassociated before being freed."); "Channel must be disassociated before being freed.");
--task->ref_count;
} }
/** /**
@ -35,10 +34,11 @@ rust_chan::~rust_chan() {
void rust_chan::associate(maybe_proxy<rust_port> *port) { void rust_chan::associate(maybe_proxy<rust_port> *port) {
this->port = port; this->port = port;
if (port->is_proxy() == false) { if (port->is_proxy() == false) {
LOG(task, task, DLOG(kernel->sched, task,
"associating chan: 0x%" PRIxPTR " with port: 0x%" PRIxPTR, "associating chan: 0x%" PRIxPTR " with port: 0x%" PRIxPTR,
this, port); this, port);
++this->ref_count; ++this->ref_count;
this->task = port->referent()->task;
this->port->referent()->chans.push(this); this->port->referent()->chans.push(this);
} }
} }
@ -51,14 +51,15 @@ bool rust_chan::is_associated() {
* Unlink this channel from its associated port. * Unlink this channel from its associated port.
*/ */
void rust_chan::disassociate() { void rust_chan::disassociate() {
A(task->sched, is_associated(), A(kernel->sched, is_associated(),
"Channel must be associated with a port."); "Channel must be associated with a port.");
if (port->is_proxy() == false) { if (port->is_proxy() == false) {
LOG(task, task, DLOG(kernel->sched, task,
"disassociating chan: 0x%" PRIxPTR " from port: 0x%" PRIxPTR, "disassociating chan: 0x%" PRIxPTR " from port: 0x%" PRIxPTR,
this, port->referent()); this, port->referent());
--this->ref_count; --this->ref_count;
this->task = NULL;
port->referent()->chans.swap_delete(this); port->referent()->chans.swap_delete(this);
} }
@ -72,7 +73,7 @@ void rust_chan::disassociate() {
void rust_chan::send(void *sptr) { void rust_chan::send(void *sptr) {
buffer.enqueue(sptr); buffer.enqueue(sptr);
rust_scheduler *sched = task->sched; rust_scheduler *sched = kernel->sched;
if (!is_associated()) { if (!is_associated()) {
W(sched, is_associated(), W(sched, is_associated(),
"rust_chan::transmit with no associated port."); "rust_chan::transmit with no associated port.");
@ -112,11 +113,12 @@ rust_chan *rust_chan::clone(maybe_proxy<rust_task> *target) {
rust_handle<rust_port> *handle = rust_handle<rust_port> *handle =
task->sched->kernel->get_port_handle(port->as_referent()); task->sched->kernel->get_port_handle(port->as_referent());
maybe_proxy<rust_port> *proxy = new rust_proxy<rust_port> (handle); maybe_proxy<rust_port> *proxy = new rust_proxy<rust_port> (handle);
LOG(task, mem, "new proxy: " PTR, proxy); DLOG(kernel->sched, mem, "new proxy: " PTR, proxy);
port = proxy; port = proxy;
target_task = target->as_proxy()->handle()->referent(); target_task = target->as_proxy()->handle()->referent();
} }
return new (target_task->kernel) rust_chan(target_task, port, unit_sz); return new (target_task->kernel, "cloned chan")
rust_chan(target_task, port, unit_sz);
} }
/** /**
@ -124,7 +126,7 @@ rust_chan *rust_chan::clone(maybe_proxy<rust_task> *target) {
* appear to be live, causing modify-after-free errors. * appear to be live, causing modify-after-free errors.
*/ */
void rust_chan::destroy() { void rust_chan::destroy() {
A(task->sched, ref_count == 0, A(kernel->sched, ref_count == 0,
"Channel's ref count should be zero."); "Channel's ref count should be zero.");
if (is_associated()) { if (is_associated()) {

View File

@ -10,7 +10,7 @@ public:
~rust_chan(); ~rust_chan();
rust_kernel *kernel; rust_kernel *kernel;
rust_task *task; smart_ptr<rust_task> task;
maybe_proxy<rust_port> *port; maybe_proxy<rust_port> *port;
size_t idx; size_t idx;
circular_buffer buffer; circular_buffer buffer;

View File

@ -16,7 +16,8 @@ rust_crate_cache::get_type_desc(size_t size,
return td; return td;
} }
DLOG(sched, cache, "rust_crate_cache::get_type_desc miss"); DLOG(sched, cache, "rust_crate_cache::get_type_desc miss");
td = (type_desc*) sched->kernel->malloc(sizeof(type_desc) + keysz); td = (type_desc*) sched->kernel->malloc(sizeof(type_desc) + keysz,
"crate cache typedesc");
if (!td) if (!td)
return NULL; return NULL;
// By convention, desc 0 is the root descriptor. // By convention, desc 0 is the root descriptor.

View File

@ -115,21 +115,59 @@ template <typename T> struct rc_base {
}; };
template <typename T> struct task_owned { template <typename T> struct task_owned {
inline void *operator new(size_t size, rust_task *task); inline void *operator new(size_t size, rust_task *task, const char *tag);
inline void *operator new[](size_t size, rust_task *task); inline void *operator new[](size_t size, rust_task *task,
const char *tag);
inline void *operator new(size_t size, rust_task &task); inline void *operator new(size_t size, rust_task &task, const char *tag);
inline void *operator new[](size_t size, rust_task &task); inline void *operator new[](size_t size, rust_task &task,
const char *tag);
void operator delete(void *ptr) { void operator delete(void *ptr) {
((T *)ptr)->task->free(ptr); ((T *)ptr)->task->free(ptr);
} }
}; };
template<class T>
class smart_ptr {
T *p;
smart_ptr(const smart_ptr &sp) : p(sp.p) {
if(p) { p->ref(); }
}
public:
smart_ptr() : p(NULL) {};
smart_ptr(T *p) : p(p) { if(p) { p->ref(); } }
~smart_ptr() {
if(p) {
p->deref();
}
}
T *operator=(T* p) {
if(this->p) {
this->p->deref();
}
if(p) {
p->ref();
}
this->p = p;
return p;
}
T *operator->() const { return p; };
operator T*() const { return p; }
};
template <typename T> struct kernel_owned { template <typename T> struct kernel_owned {
inline void *operator new(size_t size, rust_kernel *kernel); inline void *operator new(size_t size, rust_kernel *kernel,
const char *tag);
void operator delete(void *ptr) { void operator delete(void *ptr) {
((T *)ptr)->kernel->free(ptr); ((T *)ptr)->kernel->free(ptr);

View File

@ -8,7 +8,7 @@
} while (0) } while (0)
rust_kernel::rust_kernel(rust_srv *srv) : rust_kernel::rust_kernel(rust_srv *srv) :
_region(&srv->local_region), _region(srv, true),
_log(srv, NULL), _log(srv, NULL),
_srv(srv), _srv(srv),
_interrupt_kernel_loop(FALSE) _interrupt_kernel_loop(FALSE)
@ -20,10 +20,11 @@ rust_scheduler *
rust_kernel::create_scheduler(const char *name) { rust_kernel::create_scheduler(const char *name) {
_kernel_lock.lock(); _kernel_lock.lock();
rust_message_queue *message_queue = rust_message_queue *message_queue =
new (this) rust_message_queue(_srv, this); new (this, "rust_message_queue") rust_message_queue(_srv, this);
rust_srv *srv = _srv->clone(); rust_srv *srv = _srv->clone();
rust_scheduler *sched = rust_scheduler *sched =
new (this) rust_scheduler(this, message_queue, srv, name); new (this, "rust_scheduler")
rust_scheduler(this, message_queue, srv, name);
rust_handle<rust_scheduler> *handle = internal_get_sched_handle(sched); rust_handle<rust_scheduler> *handle = internal_get_sched_handle(sched);
message_queue->associate(handle); message_queue->associate(handle);
message_queues.append(message_queue); message_queues.append(message_queue);
@ -51,10 +52,8 @@ rust_handle<rust_scheduler> *
rust_kernel::internal_get_sched_handle(rust_scheduler *sched) { rust_kernel::internal_get_sched_handle(rust_scheduler *sched) {
rust_handle<rust_scheduler> *handle = NULL; rust_handle<rust_scheduler> *handle = NULL;
if (_sched_handles.get(sched, &handle) == false) { if (_sched_handles.get(sched, &handle) == false) {
handle = handle = new (this, "rust_handle<rust_scheduler")
new (this) rust_handle<rust_scheduler>(this, rust_handle<rust_scheduler>(this, sched->message_queue, sched);
sched->message_queue,
sched);
_sched_handles.put(sched, handle); _sched_handles.put(sched, handle);
} }
return handle; return handle;
@ -74,9 +73,8 @@ rust_kernel::get_task_handle(rust_task *task) {
rust_handle<rust_task> *handle = NULL; rust_handle<rust_task> *handle = NULL;
if (_task_handles.get(task, &handle) == false) { if (_task_handles.get(task, &handle) == false) {
handle = handle =
new (this) rust_handle<rust_task>(this, new (this, "rust_handle<rust_task>")
task->sched->message_queue, rust_handle<rust_task>(this, task->sched->message_queue, task);
task);
_task_handles.put(task, handle); _task_handles.put(task, handle);
} }
_kernel_lock.unlock(); _kernel_lock.unlock();
@ -88,7 +86,7 @@ rust_kernel::get_port_handle(rust_port *port) {
_kernel_lock.lock(); _kernel_lock.lock();
rust_handle<rust_port> *handle = NULL; rust_handle<rust_port> *handle = NULL;
if (_port_handles.get(port, &handle) == false) { if (_port_handles.get(port, &handle) == false) {
handle = new (this) handle = new (this, "rust_handle<rust_port>")
rust_handle<rust_port>(this, rust_handle<rust_port>(this,
port->task->sched->message_queue, port->task->sched->message_queue,
port); port);
@ -202,17 +200,17 @@ rust_kernel::~rust_kernel() {
} }
void * void *
rust_kernel::malloc(size_t size) { rust_kernel::malloc(size_t size, const char *tag) {
return _region->malloc(size); return _region.malloc(size, tag);
} }
void * void *
rust_kernel::realloc(void *mem, size_t size) { rust_kernel::realloc(void *mem, size_t size) {
return _region->realloc(mem, size); return _region.realloc(mem, size);
} }
void rust_kernel::free(void *mem) { void rust_kernel::free(void *mem) {
_region->free(mem); _region.free(mem);
} }
template<class T> void template<class T> void

View File

@ -43,7 +43,7 @@ class rust_task_thread;
* threads. * threads.
*/ */
class rust_kernel : public rust_thread { class rust_kernel : public rust_thread {
memory_region *_region; memory_region _region;
rust_log _log; rust_log _log;
rust_srv *_srv; rust_srv *_srv;
@ -109,7 +109,7 @@ public:
void fatal(char const *fmt, ...); void fatal(char const *fmt, ...);
virtual ~rust_kernel(); virtual ~rust_kernel();
void *malloc(size_t size); void *malloc(size_t size, const char *tag);
void *realloc(void *mem, size_t size); void *realloc(void *mem, size_t size);
void free(void *mem); void free(void *mem);

View File

@ -47,7 +47,8 @@ send(notification_type type, const char* label,
rust_handle<rust_task> *source, rust_handle<rust_task> *target) { rust_handle<rust_task> *source, rust_handle<rust_task> *target) {
memory_region *region = &target->message_queue->region; memory_region *region = &target->message_queue->region;
notify_message *message = notify_message *message =
new (region) notify_message(region, type, label, source, target); new (region, "notify_message")
notify_message(region, type, label, source, target);
target->message_queue->enqueue(message); target->message_queue->enqueue(message);
} }
@ -91,8 +92,8 @@ send(uint8_t *buffer, size_t buffer_sz, const char* label,
memory_region *region = &port->message_queue->region; memory_region *region = &port->message_queue->region;
data_message *message = data_message *message =
new (region) data_message(region, buffer, buffer_sz, label, source, new (region, "data_message")
port); data_message(region, buffer, buffer_sz, label, source, port);
LOG(source->referent(), comm, "==> sending \"%s\"" PTR " in queue " PTR, LOG(source->referent(), comm, "==> sending \"%s\"" PTR " in queue " PTR,
label, message, &port->message_queue); label, message, &port->message_queue);
port->message_queue->enqueue(message); port->message_queue->enqueue(message);

View File

@ -10,7 +10,8 @@ rust_port::rust_port(rust_task *task, size_t unit_sz)
PRIxPTR, (uintptr_t)task, unit_sz, (uintptr_t)this); PRIxPTR, (uintptr_t)task, unit_sz, (uintptr_t)this);
// Allocate a remote channel, for remote channel data. // Allocate a remote channel, for remote channel data.
remote_channel = new (task->kernel) rust_chan(task, this, unit_sz); remote_channel = new (task->kernel, "remote chan")
rust_chan(task, this, unit_sz);
} }
rust_port::~rust_port() { rust_port::~rust_port() {

View File

@ -290,7 +290,8 @@ rust_scheduler::get_cache() {
rust_task * rust_task *
rust_scheduler::create_task(rust_task *spawner, const char *name) { rust_scheduler::create_task(rust_task *spawner, const char *name) {
rust_task *task = rust_task *task =
new (this->kernel) rust_task (this, &newborn_tasks, spawner, name); new (this->kernel, "rust_task")
rust_task (this, &newborn_tasks, spawner, name);
DLOG(this, task, "created task: " PTR ", spawner: %s, name: %s", DLOG(this, task, "created task: " PTR ", spawner: %s, name: %s",
task, spawner ? spawner->name : "null", name); task, spawner ? spawner->name : "null", name);
if(spawner) { if(spawner) {

View File

@ -34,7 +34,7 @@ new_stk(rust_task *task, size_t minsz)
if (minsz < min_stk_bytes) if (minsz < min_stk_bytes)
minsz = min_stk_bytes; minsz = min_stk_bytes;
size_t sz = sizeof(stk_seg) + minsz; size_t sz = sizeof(stk_seg) + minsz;
stk_seg *stk = (stk_seg *)task->malloc(sz); stk_seg *stk = (stk_seg *)task->malloc(sz, "stack");
LOGPTR(task->sched, "new stk", (uintptr_t)stk); LOGPTR(task->sched, "new stk", (uintptr_t)stk);
memset(stk, 0, sizeof(stk_seg)); memset(stk, 0, sizeof(stk_seg));
stk->limit = (uintptr_t) &stk->data[minsz]; stk->limit = (uintptr_t) &stk->data[minsz];
@ -326,7 +326,7 @@ rust_task::unlink_gc(gc_alloc *gcm) {
} }
void * void *
rust_task::malloc(size_t sz, type_desc *td) rust_task::malloc(size_t sz, const char *tag, type_desc *td)
{ {
// FIXME: GC is disabled for now. // FIXME: GC is disabled for now.
// GC-memory classification is all wrong. // GC-memory classification is all wrong.
@ -335,7 +335,8 @@ rust_task::malloc(size_t sz, type_desc *td)
if (td) { if (td) {
sz += sizeof(gc_alloc); sz += sizeof(gc_alloc);
} }
void *mem = local_region.malloc(sz);
void *mem = local_region.malloc(sz, tag);
if (!mem) if (!mem)
return mem; return mem;
if (td) { if (td) {
@ -488,8 +489,8 @@ bool rust_task::can_schedule(int id)
} }
void * void *
rust_task::calloc(size_t size) { rust_task::calloc(size_t size, const char *tag) {
return local_region.calloc(size); return local_region.calloc(size, tag);
} }
void rust_task::pin() { void rust_task::pin() {

View File

@ -112,7 +112,7 @@ rust_task : public maybe_proxy<rust_task>,
void link_gc(gc_alloc *gcm); void link_gc(gc_alloc *gcm);
void unlink_gc(gc_alloc *gcm); void unlink_gc(gc_alloc *gcm);
void *malloc(size_t sz, type_desc *td=0); void *malloc(size_t sz, const char *tag, type_desc *td=0);
void *realloc(void *data, size_t sz, bool gc_mem=false); void *realloc(void *data, size_t sz, bool gc_mem=false);
void free(void *p, bool gc_mem=false); void free(void *p, bool gc_mem=false);
@ -157,7 +157,7 @@ rust_task : public maybe_proxy<rust_task>,
bool can_schedule(int worker); bool can_schedule(int worker);
void *calloc(size_t size); void *calloc(size_t size, const char *tag);
void pin(); void pin();
void pin(int id); void pin(int id);

View File

@ -104,7 +104,7 @@ upcall_new_port(rust_task *task, size_t unit_sz) {
(uintptr_t) task, task->name, unit_sz); (uintptr_t) task, task->name, unit_sz);
// take a reference on behalf of the port // take a reference on behalf of the port
task->ref(); task->ref();
return new (task->kernel) rust_port(task, unit_sz); return new (task->kernel, "rust_port") rust_port(task, unit_sz);
} }
extern "C" CDECL void extern "C" CDECL void
@ -129,7 +129,8 @@ upcall_new_chan(rust_task *task, rust_port *port) {
"task=0x%" PRIxPTR " (%s), port=0x%" PRIxPTR ")", "task=0x%" PRIxPTR " (%s), port=0x%" PRIxPTR ")",
(uintptr_t) task, task->name, port); (uintptr_t) task, task->name, port);
I(sched, port); I(sched, port);
return new (task->kernel) rust_chan(task, port, port->unit_sz); return new (task->kernel, "rust_chan")
rust_chan(task, port, port->unit_sz);
} }
/** /**
@ -152,8 +153,6 @@ extern "C" CDECL
void upcall_del_chan(rust_task *task, rust_chan *chan) { void upcall_del_chan(rust_task *task, rust_chan *chan) {
LOG_UPCALL_ENTRY(task); LOG_UPCALL_ENTRY(task);
I(task->sched, chan->task == task);
LOG(task, comm, "upcall del_chan(0x%" PRIxPTR ")", (uintptr_t) chan); LOG(task, comm, "upcall del_chan(0x%" PRIxPTR ")", (uintptr_t) chan);
chan->destroy(); chan->destroy();
} }
@ -169,6 +168,14 @@ upcall_clone_chan(rust_task *task, maybe_proxy<rust_task> *target,
return chan->clone(target); return chan->clone(target);
} }
extern "C" CDECL rust_task *
upcall_chan_target_task(rust_task *task, rust_chan *chan) {
LOG_UPCALL_ENTRY(task);
I(task->sched, !chan->port->is_proxy());
return chan->port->referent()->task;
}
extern "C" CDECL void extern "C" CDECL void
upcall_yield(rust_task *task) { upcall_yield(rust_task *task) {
LOG_UPCALL_ENTRY(task); LOG_UPCALL_ENTRY(task);
@ -277,7 +284,10 @@ upcall_malloc(rust_task *task, size_t nbytes, type_desc *td) {
" with gc-chain head = 0x%" PRIxPTR, " with gc-chain head = 0x%" PRIxPTR,
nbytes, td, task->gc_alloc_chain); nbytes, td, task->gc_alloc_chain);
void *p = task->malloc(nbytes, td); // TODO: Maybe use dladdr here to find a more useful name for the
// type_desc.
void *p = task->malloc(nbytes, "tdesc", td);
LOG(task, mem, LOG(task, mem,
"upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR "upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR
@ -308,7 +318,7 @@ upcall_shared_malloc(rust_task *task, size_t nbytes, type_desc *td) {
LOG(task, mem, LOG(task, mem,
"upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR ")", "upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR ")",
nbytes, td); nbytes, td);
void *p = task->kernel->malloc(nbytes); void *p = task->kernel->malloc(nbytes, "shared malloc");
LOG(task, mem, LOG(task, mem,
"upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR "upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR
") = 0x%" PRIxPTR, ") = 0x%" PRIxPTR,
@ -346,14 +356,13 @@ upcall_mark(rust_task *task, void* ptr) {
} }
rust_str *make_str(rust_task *task, char const *s, size_t fill) { rust_str *make_str(rust_task *task, char const *s, size_t fill) {
rust_scheduler *sched = task->sched;
size_t alloc = next_power_of_two(sizeof(rust_str) + fill); size_t alloc = next_power_of_two(sizeof(rust_str) + fill);
void *mem = task->malloc(alloc); void *mem = task->malloc(alloc, "rust_str (make_str)");
if (!mem) { if (!mem) {
task->fail(); task->fail();
return NULL; return NULL;
} }
rust_str *st = new (mem) rust_str(sched, alloc, fill, rust_str *st = new (mem) rust_str(alloc, fill,
(uint8_t const *) s); (uint8_t const *) s);
LOG(task, mem, LOG(task, mem,
"upcall new_str('%s', %" PRIdPTR ") = 0x%" PRIxPTR, "upcall new_str('%s', %" PRIdPTR ") = 0x%" PRIxPTR,
@ -381,12 +390,12 @@ upcall_new_vec(rust_task *task, size_t fill, type_desc *td) {
rust_scheduler *sched = task->sched; rust_scheduler *sched = task->sched;
DLOG(sched, mem, "upcall new_vec(%" PRIdPTR ")", fill); DLOG(sched, mem, "upcall new_vec(%" PRIdPTR ")", fill);
size_t alloc = next_power_of_two(sizeof(rust_vec) + fill); size_t alloc = next_power_of_two(sizeof(rust_vec) + fill);
void *mem = task->malloc(alloc, td); void *mem = task->malloc(alloc, "rust_vec (upcall_new_vec)", td);
if (!mem) { if (!mem) {
task->fail(); task->fail();
return NULL; return NULL;
} }
rust_vec *v = new (mem) rust_vec(sched, alloc, 0, NULL); rust_vec *v = new (mem) rust_vec(alloc, 0, NULL);
LOG(task, mem, LOG(task, mem,
"upcall new_vec(%" PRIdPTR ") = 0x%" PRIxPTR, fill, v); "upcall new_vec(%" PRIdPTR ") = 0x%" PRIxPTR, fill, v);
return v; return v;
@ -441,7 +450,7 @@ vec_grow(rust_task *task,
* that we need the copies performed for us. * that we need the copies performed for us.
*/ */
LOG(task, mem, "new vec path"); LOG(task, mem, "new vec path");
void *mem = task->malloc(alloc, td); void *mem = task->malloc(alloc, "rust_vec (vec_grow)", td);
if (!mem) { if (!mem) {
task->fail(); task->fail();
return NULL; return NULL;
@ -450,7 +459,7 @@ vec_grow(rust_task *task,
if (v->ref_count != CONST_REFCOUNT) if (v->ref_count != CONST_REFCOUNT)
v->deref(); v->deref();
v = new (mem) rust_vec(sched, alloc, 0, NULL); v = new (mem) rust_vec(alloc, 0, NULL);
*need_copy = 1; *need_copy = 1;
} }
I(sched, sizeof(rust_vec) + v->fill <= v->alloc); I(sched, sizeof(rust_vec) + v->fill <= v->alloc);
@ -599,7 +608,8 @@ upcall_ivec_spill_shared(rust_task *task,
size_t new_alloc = next_power_of_two(newsz); size_t new_alloc = next_power_of_two(newsz);
rust_ivec_heap *heap_part = (rust_ivec_heap *) rust_ivec_heap *heap_part = (rust_ivec_heap *)
task->kernel->malloc(new_alloc + sizeof(size_t)); task->kernel->malloc(new_alloc + sizeof(size_t),
"ivec spill shared");
heap_part->fill = newsz; heap_part->fill = newsz;
memcpy(&heap_part->data, v->payload.data, v->fill); memcpy(&heap_part->data, v->payload.data, v->fill);

View File

@ -23,7 +23,7 @@ ptr_vec<T>::ptr_vec(rust_task *task) :
task(task), task(task),
alloc(INIT_SIZE), alloc(INIT_SIZE),
fill(0), fill(0),
data(new (task) T*[alloc]) data(new (task, "ptr_vec<T>") T*[alloc])
{ {
I(task->sched, data); I(task->sched, data);
DLOG(task->sched, mem, "new ptr_vec(data=0x%" PRIxPTR ") -> 0x%" PRIxPTR, DLOG(task->sched, mem, "new ptr_vec(data=0x%" PRIxPTR ") -> 0x%" PRIxPTR,
@ -175,7 +175,7 @@ rust_vec : public rc_base<rust_vec>
size_t fill; size_t fill;
size_t pad; // Pad to align data[0] to 16 bytes. size_t pad; // Pad to align data[0] to 16 bytes.
uint8_t data[]; uint8_t data[];
rust_vec(rust_scheduler *sched, size_t alloc, size_t fill, rust_vec(size_t alloc, size_t fill,
uint8_t const *d) uint8_t const *d)
: alloc(alloc), : alloc(alloc),
fill(fill) fill(fill)

View File

@ -53,6 +53,7 @@ task_yield
task_join task_join
unsafe_vec_to_mut unsafe_vec_to_mut
unsupervise unsupervise
upcall_chan_target_task
upcall_clone_chan upcall_clone_chan
upcall_del_chan upcall_del_chan
upcall_del_port upcall_del_port

View File

@ -6,17 +6,30 @@ use std;
import std::task; import std::task;
fn start(chan[chan[str]] c) { fn start(chan[chan[str]] c) {
let port[str] p = port(); let port[str] p;
p = port();
c <| chan(p); c <| chan(p);
auto a; p |> a; p |> a;
// auto b; p |> b; // Never read the second string. log_err a;
p |> b;
log_err b;
auto a;
auto b;
} }
fn main() { fn main() {
let port[chan[str]] p = port(); let port[chan[str]] p;
auto child = spawn start(chan(p)); auto child;
auto c; p |> c;
p = port();
child = spawn start(chan(p));
p |> c;
c <| "A"; c <| "A";
c <| "B"; c <| "B";
task::yield(); task::yield();
auto c;
} }