Skip to content

Commit b9f1f77

Browse files
author
Eric Holk
committed
Fixed memory accounting and task stack creation bugs.
1 parent 2f23405 commit b9f1f77

File tree

7 files changed

+81
-35
lines changed

7 files changed

+81
-35
lines changed

src/lib/task.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ native "rust" mod rustrt {
2121
fn start_task(id : task_id);
2222
fn get_task_trampoline() -> u32;
2323

24+
fn migrate_alloc(alloc : *u8, target : task_id);
25+
2426
fn leak[@T](thing : -T);
2527
}
2628

@@ -104,6 +106,7 @@ fn _spawn(thunk : fn() -> ()) -> task_id {
104106
*env = raw_thunk.env;
105107
*ra = rustrt::get_task_trampoline();
106108

109+
rustrt::migrate_alloc(cast(raw_thunk.env), id);
107110
rustrt::start_task(id);
108111

109112
rustrt::leak(thunk);

src/rt/memory_region.cpp

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// NB: please do not commit code with this uncommented. It's
55
// hugely expensive and should only be used as a last resort.
66
//
7-
#define TRACK_ALLOCATIONS
7+
// #define TRACK_ALLOCATIONS
88

99
#define MAGIC 0xbadc0ffe
1010

@@ -25,13 +25,13 @@ memory_region::memory_region(memory_region *parent) :
2525
}
2626

2727
void memory_region::add_alloc() {
28-
_live_allocations++;
29-
//sync::increment(_live_allocations);
28+
//_live_allocations++;
29+
sync::increment(_live_allocations);
3030
}
3131

3232
void memory_region::dec_alloc() {
33-
_live_allocations--;
34-
//sync::decrement(_live_allocations);
33+
//_live_allocations--;
34+
sync::decrement(_live_allocations);
3535
}
3636

3737
void memory_region::free(void *mem) {
@@ -40,21 +40,10 @@ void memory_region::free(void *mem) {
4040
if (_synchronized) { _lock.lock(); }
4141
alloc_header *alloc = get_header(mem);
4242
assert(alloc->magic == MAGIC);
43-
#ifdef TRACK_ALLOCATIONS
44-
if (_allocation_list[alloc->index] != alloc) {
45-
printf("free: ptr 0x%" PRIxPTR " (%s) is not in allocation_list\n",
46-
(uintptr_t) &alloc->data, alloc->tag);
47-
_srv->fatal("not in allocation_list", __FILE__, __LINE__, "");
48-
}
49-
else {
50-
// printf("freed index %d\n", index);
51-
_allocation_list[alloc->index] = NULL;
52-
}
53-
#endif
5443
if (_live_allocations < 1) {
5544
_srv->fatal("live_allocs < 1", __FILE__, __LINE__, "");
5645
}
57-
dec_alloc();
46+
release_alloc(mem);
5847
_srv->free(alloc);
5948
if (_synchronized) { _lock.unlock(); }
6049
}
@@ -90,18 +79,13 @@ memory_region::realloc(void *mem, size_t size) {
9079
void *
9180
memory_region::malloc(size_t size, const char *tag, bool zero) {
9281
if (_synchronized) { _lock.lock(); }
93-
add_alloc();
9482
size_t old_size = size;
9583
size += sizeof(alloc_header);
9684
alloc_header *mem = (alloc_header *)_srv->malloc(size);
9785
mem->magic = MAGIC;
9886
mem->tag = tag;
99-
#ifdef TRACK_ALLOCATIONS
100-
mem->index = _allocation_list.append(mem);
101-
// printf("malloc: stored %p at index %d\n", mem, index);
102-
#endif
103-
// printf("malloc: ptr 0x%" PRIxPTR " region=%p\n",
104-
// (uintptr_t) mem, this);
87+
mem->index = -1;
88+
claim_alloc(mem->data);
10589

10690
if(zero) {
10791
memset(mem->data, 0, old_size);
@@ -118,27 +102,32 @@ memory_region::calloc(size_t size, const char *tag) {
118102

119103
memory_region::~memory_region() {
120104
if (_synchronized) { _lock.lock(); }
121-
if (_live_allocations == 0) {
105+
if (_live_allocations == 0 && !_detailed_leaks) {
122106
if (_synchronized) { _lock.unlock(); }
123107
return;
124108
}
125109
char msg[128];
126-
snprintf(msg, sizeof(msg),
127-
"leaked memory in rust main loop (%" PRIuPTR " objects)",
128-
_live_allocations);
110+
if(_live_allocations > 0) {
111+
snprintf(msg, sizeof(msg),
112+
"leaked memory in rust main loop (%d objects)",
113+
_live_allocations);
114+
}
129115
#ifdef TRACK_ALLOCATIONS
130116
if (_detailed_leaks) {
117+
unsigned int leak_count = 0;
131118
for (size_t i = 0; i < _allocation_list.size(); i++) {
132119
if (_allocation_list[i] != NULL) {
133120
alloc_header *header = (alloc_header*)_allocation_list[i];
134121
printf("allocation (%s) 0x%" PRIxPTR " was not freed\n",
135122
header->tag,
136123
(uintptr_t) &header->data);
124+
++leak_count;
137125
}
138126
}
127+
assert(leak_count == _live_allocations);
139128
}
140129
#endif
141-
if (!_hack_allow_leaks) {
130+
if (!_hack_allow_leaks && _live_allocations > 0) {
142131
_srv->fatal(msg, __FILE__, __LINE__,
143132
"%d objects", _live_allocations);
144133
}
@@ -150,6 +139,36 @@ memory_region::hack_allow_leaks() {
150139
_hack_allow_leaks = true;
151140
}
152141

142+
void
143+
memory_region::release_alloc(void *mem) {
144+
alloc_header *alloc = get_header(mem);
145+
assert(alloc->magic == MAGIC);
146+
147+
#ifdef TRACK_ALLOCATIONS
148+
if (_allocation_list[alloc->index] != alloc) {
149+
printf("free: ptr 0x%" PRIxPTR " (%s) is not in allocation_list\n",
150+
(uintptr_t) &alloc->data, alloc->tag);
151+
_srv->fatal("not in allocation_list", __FILE__, __LINE__, "");
152+
}
153+
else {
154+
// printf("freed index %d\n", index);
155+
_allocation_list[alloc->index] = NULL;
156+
alloc->index = -1;
157+
}
158+
#endif
159+
dec_alloc();
160+
}
161+
162+
void
163+
memory_region::claim_alloc(void *mem) {
164+
alloc_header *alloc = get_header(mem);
165+
assert(alloc->magic == MAGIC);
166+
#ifdef TRACK_ALLOCATIONS
167+
alloc->index = _allocation_list.append(alloc);
168+
#endif
169+
add_alloc();
170+
}
171+
153172
//
154173
// Local Variables:
155174
// mode: C++

src/rt/memory_region.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class memory_region {
2727

2828
rust_srv *_srv;
2929
memory_region *_parent;
30-
size_t _live_allocations;
30+
int _live_allocations;
3131
array_list<alloc_header *> _allocation_list;
3232
const bool _detailed_leaks;
3333
const bool _synchronized;
@@ -48,6 +48,9 @@ class memory_region {
4848
// to not kill the entire process, which the test runner needs. Please
4949
// kill with prejudice once unwinding works.
5050
void hack_allow_leaks();
51+
52+
void release_alloc(void *mem);
53+
void claim_alloc(void *mem);
5154
};
5255

5356
inline void *operator new(size_t size, memory_region &region,

src/rt/rust_builtin.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ task_yield(rust_task *task) {
289289
extern "C" CDECL intptr_t
290290
task_join(rust_task *task, rust_task_id tid) {
291291
// If the other task is already dying, we don't have to wait for it.
292-
smart_ptr<rust_task> join_task = task->kernel->get_task_by_id(tid);
292+
rust_task *join_task = task->kernel->get_task_by_id(tid);
293293
// FIXME: find task exit status and return that.
294294
if(!join_task) return 0;
295295
join_task->lock.lock();
@@ -720,10 +720,11 @@ new_task(rust_task *task) {
720720

721721
extern "C" CDECL registers_t *
722722
get_task_context(rust_task *task, rust_task_id id) {
723-
registers_t *regs = &task->kernel->get_task_by_id(id)->ctx.regs;
723+
rust_task *target = task->kernel->get_task_by_id(id);
724+
registers_t *regs = &target->ctx.regs;
724725
// This next line is a little dangerous.. It means we can only safely call
725726
// this when starting a task.
726-
regs->esp = task->rust_sp;
727+
regs->esp = target->rust_sp;
727728
return regs;
728729
}
729730

@@ -746,6 +747,20 @@ get_task_trampoline(rust_task *task) {
746747
return &task_trampoline;
747748
}
748749

750+
extern "C" CDECL void
751+
migrate_alloc(rust_task *task, void *alloc, rust_task_id tid) {
752+
if(!alloc) return;
753+
rust_task *target = task->kernel->get_task_by_id(tid);
754+
if(target) {
755+
task->local_region.release_alloc(alloc);
756+
target->local_region.claim_alloc(alloc);
757+
}
758+
else {
759+
// We couldn't find the target. Maybe we should just free?
760+
task->fail();
761+
}
762+
}
763+
749764
extern "C" CDECL rust_chan *
750765
clone_chan(rust_task *task, rust_chan *chan) {
751766
return chan->clone(task);

src/rt/rust_task.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,13 @@ struct spawn_args {
108108
};
109109

110110
extern "C" CDECL
111-
void task_exit(void *env, int rval, rust_task *task) {
111+
void task_exit(intptr_t *env, int rval, rust_task *task) {
112112
LOG(task, task, "task exited with value %d", rval);
113+
if(env) {
114+
// free the environment.
115+
I(task->sched, 1 == *env); // the ref count better be 1
116+
task->free(env);
117+
}
113118
task->die();
114119
task->lock.lock();
115120
task->notify_tasks_waiting_to_join();

src/rt/rustrt.def.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ ivec_reserve_shared
4141
ivec_to_ptr
4242
last_os_error
4343
leak
44+
migrate_alloc
4445
nano_time
4546
new_chan
4647
new_port

src/test/stdtest/task.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,4 @@ fn test_lib_spawn() {
4343
fn test_lib_spawn2() {
4444
fn foo(x : int) { assert(x == 42); }
4545
task::_spawn(bind foo(42));
46-
}
46+
}

0 commit comments

Comments
 (0)