Skip to content

Commit 3ae4dcd

Browse files
Eric Holkbrson
authored andcommitted
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.
1 parent a44fb04 commit 3ae4dcd

24 files changed

+313
-240
lines changed

src/comp/back/upcall.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type upcalls =
3838
ValueRef flush_chan,
3939
ValueRef del_chan,
4040
ValueRef clone_chan,
41+
ValueRef chan_target_task,
4142
ValueRef _yield,
4243
ValueRef sleep,
4344
ValueRef send,
@@ -95,6 +96,9 @@ fn declare_upcalls(type_names tn, TypeRef tydesc_type, TypeRef taskptr_type,
9596
del_chan=dv("del_chan", ~[T_opaque_chan_ptr()]),
9697
clone_chan=d("clone_chan", ~[taskptr_type, T_opaque_chan_ptr()],
9798
T_opaque_chan_ptr()),
99+
chan_target_task=d("chan_target_task",
100+
~[T_opaque_chan_ptr()],
101+
taskptr_type),
98102
_yield=dv("yield", empty_vec),
99103
sleep=dv("sleep", ~[T_size_t()]),
100104
send=dv("send", ~[T_opaque_chan_ptr(), T_ptr(T_i8())]),

src/comp/middle/trans_comm.rs

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ import back::link::mangle_internal_name_by_path_and_seq;
2222
import trans_common::*;
2323
import trans::*;
2424

25+
export trans_port;
26+
export trans_chan;
27+
export trans_spawn;
28+
export trans_send;
29+
export trans_recv;
30+
2531
fn trans_port(&@block_ctxt cx, ast::node_id id) -> result {
2632
auto t = node_id_type(cx.fcx.lcx.ccx, id);
2733
auto unit_ty;
@@ -123,13 +129,7 @@ fn trans_spawn(&@block_ctxt cx, &ast::spawn_dom dom, &option::t[str] name,
123129
auto llargs = alloc_ty(bcx, args_ty);
124130
auto i = 0u;
125131
for (ValueRef v in arg_vals) {
126-
// log_err #fmt("ty(llargs) = %s",
127-
// val_str(bcx.fcx.lcx.ccx.tn, llargs.val));
128-
129132
auto target = bcx.build.GEP(llargs.val, ~[C_int(0), C_int(i as int)]);
130-
// log_err #fmt("ty(v) = %s", val_str(bcx.fcx.lcx.ccx.tn, v));
131-
// log_err #fmt("ty(target) = %s",
132-
// val_str(bcx.fcx.lcx.ccx.tn, target));
133133

134134
bcx.build.Store(v, target);
135135
i += 1u;
@@ -199,55 +199,6 @@ fn mk_spawn_wrapper(&@block_ctxt cx, &@ast::expr func, &ty::t args_ty) ->
199199
ret rslt(cx, llfndecl);
200200
}
201201

202-
// Does a deep copy of a value. This is needed for passing arguments to child
203-
// tasks, and for sending things through channels. There are probably some
204-
// uniqueness optimizations and things we can do here for tasks in the same
205-
// domain.
206-
fn deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t, ValueRef target_task)
207-
-> result
208-
{
209-
// TODO: make sure all paths add any reference counting that they need to.
210-
211-
// TODO: Teach deep copy to understand everything else it needs to.
212-
213-
auto tcx = bcx.fcx.lcx.ccx.tcx;
214-
if(ty::type_is_scalar(tcx, t)) {
215-
ret rslt(bcx, v);
216-
}
217-
else if(ty::type_is_str(tcx, t)) {
218-
ret rslt(bcx,
219-
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.dup_str,
220-
~[bcx.fcx.lltaskptr, target_task, v]));
221-
}
222-
else if(ty::type_is_chan(tcx, t)) {
223-
// If this is a channel, we need to clone it.
224-
auto chan_ptr = bcx.build.PointerCast(v, T_opaque_chan_ptr());
225-
226-
auto chan_raw_val =
227-
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.clone_chan,
228-
~[bcx.fcx.lltaskptr, target_task, chan_ptr]);
229-
230-
// Cast back to the type the context was expecting.
231-
auto chan_val = bcx.build.PointerCast(chan_raw_val,
232-
val_ty(v));
233-
234-
ret rslt(bcx, chan_val);
235-
}
236-
else if(ty::type_is_structural(tcx, t)) {
237-
fn inner_deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t) -> result {
238-
log_err "Unimplemented type for deep_copy.";
239-
fail;
240-
}
241-
242-
ret iter_structural_ty(bcx, v, t, inner_deep_copy);
243-
}
244-
else {
245-
bcx.fcx.lcx.ccx.sess.bug("unexpected type in " +
246-
"trans::deep_copy: " +
247-
ty_to_str(tcx, t));
248-
}
249-
}
250-
251202
fn trans_send(&@block_ctxt cx, &@ast::expr lhs, &@ast::expr rhs,
252203
ast::node_id id) -> result {
253204
auto bcx = cx;
@@ -302,3 +253,52 @@ fn recv_val(&@block_ctxt cx, ValueRef to, &@ast::expr from, &ty::t unit_ty,
302253
ret rslt(bcx, to);
303254
}
304255

256+
// Does a deep copy of a value. This is needed for passing arguments to child
257+
// tasks, and for sending things through channels. There are probably some
258+
// uniqueness optimizations and things we can do here for tasks in the same
259+
// domain.
260+
fn deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t, ValueRef target_task)
261+
-> result
262+
{
263+
// TODO: make sure all paths add any reference counting that they need to.
264+
265+
// TODO: Teach deep copy to understand everything else it needs to.
266+
267+
auto tcx = bcx.fcx.lcx.ccx.tcx;
268+
if(ty::type_is_scalar(tcx, t)) {
269+
ret rslt(bcx, v);
270+
}
271+
else if(ty::type_is_str(tcx, t)) {
272+
ret rslt(bcx,
273+
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.dup_str,
274+
~[bcx.fcx.lltaskptr, target_task, v]));
275+
}
276+
else if(ty::type_is_chan(tcx, t)) {
277+
// If this is a channel, we need to clone it.
278+
auto chan_ptr = bcx.build.PointerCast(v, T_opaque_chan_ptr());
279+
280+
auto chan_raw_val =
281+
bcx.build.Call(bcx.fcx.lcx.ccx.upcalls.clone_chan,
282+
~[bcx.fcx.lltaskptr, target_task, chan_ptr]);
283+
284+
// Cast back to the type the context was expecting.
285+
auto chan_val = bcx.build.PointerCast(chan_raw_val,
286+
val_ty(v));
287+
288+
ret rslt(bcx, chan_val);
289+
}
290+
else if(ty::type_is_structural(tcx, t)) {
291+
fn inner_deep_copy(&@block_ctxt bcx, ValueRef v, ty::t t) -> result {
292+
log_err "Unimplemented type for deep_copy.";
293+
fail;
294+
}
295+
296+
ret iter_structural_ty(bcx, v, t, inner_deep_copy);
297+
}
298+
else {
299+
bcx.fcx.lcx.ccx.sess.bug("unexpected type in " +
300+
"trans::deep_copy: " +
301+
ty_to_str(tcx, t));
302+
}
303+
}
304+

src/rt/circular_buffer.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
#include "rust_internal.h"
66

7-
circular_buffer::circular_buffer(rust_task *task, size_t unit_sz) :
8-
sched(task->sched),
9-
task(task),
7+
circular_buffer::circular_buffer(rust_kernel *kernel, size_t unit_sz) :
8+
sched(kernel->sched),
9+
kernel(kernel),
1010
unit_sz(unit_sz),
1111
_buffer_sz(initial_size()),
1212
_next(0),
1313
_unread(0),
14-
_buffer((uint8_t *)task->malloc(_buffer_sz)) {
14+
_buffer((uint8_t *)kernel->malloc(_buffer_sz, "circular_buffer")) {
1515

1616
A(sched, unit_sz, "Unit size must be larger than zero.");
1717

@@ -20,16 +20,14 @@ circular_buffer::circular_buffer(rust_task *task, size_t unit_sz) :
2020
_buffer_sz, _unread, this);
2121

2222
A(sched, _buffer, "Failed to allocate buffer.");
23-
task->ref();
2423
}
2524

2625
circular_buffer::~circular_buffer() {
2726
DLOG(sched, mem, "~circular_buffer 0x%" PRIxPTR, this);
2827
I(sched, _buffer);
2928
W(sched, _unread == 0,
3029
"freeing circular_buffer with %d unread bytes", _unread);
31-
task->free(_buffer);
32-
--task->ref_count;
30+
kernel->free(_buffer);
3331
}
3432

3533
size_t
@@ -144,9 +142,10 @@ circular_buffer::grow() {
144142
size_t new_buffer_sz = _buffer_sz * 2;
145143
I(sched, new_buffer_sz <= MAX_CIRCULAR_BUFFER_SIZE);
146144
DLOG(sched, mem, "circular_buffer is growing to %d bytes", new_buffer_sz);
147-
void *new_buffer = task->malloc(new_buffer_sz);
145+
void *new_buffer = kernel->malloc(new_buffer_sz,
146+
"new circular_buffer (grow)");
148147
transfer(new_buffer);
149-
task->free(_buffer);
148+
kernel->free(_buffer);
150149
_buffer = (uint8_t *)new_buffer;
151150
_next = 0;
152151
_buffer_sz = new_buffer_sz;
@@ -158,9 +157,10 @@ circular_buffer::shrink() {
158157
I(sched, initial_size() <= new_buffer_sz);
159158
DLOG(sched, mem, "circular_buffer is shrinking to %d bytes",
160159
new_buffer_sz);
161-
void *new_buffer = task->malloc(new_buffer_sz);
160+
void *new_buffer = kernel->malloc(new_buffer_sz,
161+
"new circular_buffer (shrink)");
162162
transfer(new_buffer);
163-
task->free(_buffer);
163+
kernel->free(_buffer);
164164
_buffer = (uint8_t *)new_buffer;
165165
_next = 0;
166166
_buffer_sz = new_buffer_sz;

src/rt/circular_buffer.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
#define CIRCULAR_BUFFER_H
77

88
class
9-
circular_buffer : public task_owned<circular_buffer> {
9+
circular_buffer : public kernel_owned<circular_buffer> {
1010
static const size_t INITIAL_CIRCULAR_BUFFER_SIZE_IN_UNITS = 8;
1111
static const size_t MAX_CIRCULAR_BUFFER_SIZE = 1 << 24;
1212

1313
rust_scheduler *sched;
1414

1515
public:
16-
rust_task *task;
16+
rust_kernel *kernel;
1717
// Size of the data unit in bytes.
1818
const size_t unit_sz;
19-
circular_buffer(rust_task *task, size_t unit_sz);
19+
circular_buffer(rust_kernel *kernel, size_t unit_sz);
2020
~circular_buffer();
2121
void transfer(void *dst);
2222
void enqueue(void *src);

src/rt/memory.h

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,38 @@
33
#define MEMORY_H
44

55
// FIXME: It would be really nice to be able to get rid of this.
6-
inline void *operator new[](size_t size, rust_task *task) {
7-
return task->malloc(size);
6+
inline void *operator new[](size_t size, rust_task *task, const char *tag) {
7+
return task->malloc(size, tag);
88
}
99

1010
template <typename T>
11-
inline void *task_owned<T>::operator new(size_t size, rust_task *task) {
12-
return task->malloc(size);
11+
inline void *task_owned<T>::operator new(size_t size, rust_task *task,
12+
const char *tag) {
13+
return task->malloc(size, tag);
1314
}
1415

1516
template <typename T>
16-
inline void *task_owned<T>::operator new[](size_t size, rust_task *task) {
17-
return task->malloc(size);
17+
inline void *task_owned<T>::operator new[](size_t size, rust_task *task,
18+
const char *tag) {
19+
return task->malloc(size, tag);
1820
}
1921

2022
template <typename T>
21-
inline void *task_owned<T>::operator new(size_t size, rust_task &task) {
22-
return task.malloc(size);
23+
inline void *task_owned<T>::operator new(size_t size, rust_task &task,
24+
const char *tag) {
25+
return task.malloc(size, tag);
2326
}
2427

2528
template <typename T>
26-
inline void *task_owned<T>::operator new[](size_t size, rust_task &task) {
27-
return task.malloc(size);
29+
inline void *task_owned<T>::operator new[](size_t size, rust_task &task,
30+
const char *tag) {
31+
return task.malloc(size, tag);
2832
}
2933

3034
template <typename T>
31-
inline void *kernel_owned<T>::operator new(size_t size, rust_kernel *kernel) {
32-
return kernel->malloc(size);
35+
inline void *kernel_owned<T>::operator new(size_t size, rust_kernel *kernel,
36+
const char *tag) {
37+
return kernel->malloc(size, tag);
3338
}
3439

3540

0 commit comments

Comments
 (0)