Skip to content

Commit 6e9298a

Browse files
committed
Merge pull request #4619 from brson/exchange
Some work on freestanding Rust: foreign calls, exchange allocator
2 parents a281795 + e43c5bd commit 6e9298a

17 files changed

+306
-120
lines changed

mk/rt.mk

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ RUNTIME_CXXS_$(1) := \
6363
rt/rust_log.cpp \
6464
rt/rust_gc_metadata.cpp \
6565
rt/rust_util.cpp \
66+
rt/rust_exchange_alloc.cpp \
6667
rt/isaac/randport.cpp \
6768
rt/miniz.cpp \
6869
rt/rust_kernel.cpp \

src/libcore/private.rs

+13
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub mod global;
3030
pub mod finally;
3131
#[path = "private/weak_task.rs"]
3232
pub mod weak_task;
33+
#[path = "private/exchange_alloc.rs"]
34+
pub mod exchange_alloc;
3335

3436
extern mod rustrt {
3537
pub unsafe fn rust_create_little_lock() -> rust_little_lock;
@@ -86,6 +88,17 @@ fn test_run_in_bare_thread() {
8688
}
8789
}
8890

91+
#[test]
92+
fn test_run_in_bare_thread_exchange() {
93+
unsafe {
94+
// Does the exchange heap work without the runtime?
95+
let i = ~100;
96+
do run_in_bare_thread {
97+
assert i == ~100;
98+
}
99+
}
100+
}
101+
89102
fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
90103
unsafe {
91104
let old = rusti::atomic_cxchg(address, oldval, newval);

src/libcore/private/exchange_alloc.rs

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use sys::{TypeDesc, size_of};
12+
use libc::{c_void, size_t, uintptr_t};
13+
use c_malloc = libc::malloc;
14+
use c_free = libc::free;
15+
use managed::raw::{BoxHeaderRepr, BoxRepr};
16+
use cast::transmute;
17+
use ptr::{set_memory, null};
18+
use intrinsic::TyDesc;
19+
20+
pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void {
21+
unsafe {
22+
assert td.is_not_null();
23+
24+
let total_size = get_box_size(size, (*td).align);
25+
let p = c_malloc(total_size as size_t);
26+
assert p.is_not_null();
27+
28+
// FIXME #4761: Would be very nice to not memset all allocations
29+
let p: *mut u8 = transmute(p);
30+
set_memory(p, 0, total_size);
31+
32+
// FIXME #3475: Converting between our two different tydesc types
33+
let td: *TyDesc = transmute(td);
34+
35+
let box: &mut BoxRepr = transmute(p);
36+
box.header.ref_count = -1; // Exchange values not ref counted
37+
box.header.type_desc = td;
38+
box.header.prev = null();
39+
box.header.next = null();
40+
41+
let exchange_count = &mut *rust_get_exchange_count_ptr();
42+
rusti::atomic_xadd(exchange_count, 1);
43+
44+
return transmute(box);
45+
}
46+
}
47+
48+
pub unsafe fn free(ptr: *c_void) {
49+
let exchange_count = &mut *rust_get_exchange_count_ptr();
50+
rusti::atomic_xsub(exchange_count, 1);
51+
52+
assert ptr.is_not_null();
53+
c_free(ptr);
54+
}
55+
56+
fn get_box_size(body_size: uint, body_align: uint) -> uint {
57+
let header_size = size_of::<BoxHeaderRepr>();
58+
// FIXME (#2699): This alignment calculation is suspicious. Is it right?
59+
let total_size = align_to(header_size, body_align) + body_size;
60+
return total_size;
61+
}
62+
63+
// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power
64+
// of two.
65+
fn align_to(size: uint, align: uint) -> uint {
66+
assert align != 0;
67+
(size + align - 1) & !(align - 1)
68+
}
69+
70+
extern {
71+
#[rust_stack]
72+
fn rust_get_exchange_count_ptr() -> *mut int;
73+
}
74+
75+
#[abi = "rust-intrinsic"]
76+
extern mod rusti {
77+
fn atomic_xadd(dst: &mut int, src: int) -> int;
78+
fn atomic_xsub(dst: &mut int, src: int) -> int;
79+
}

src/libcore/rt.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use libc::{c_char, c_uchar, c_void, size_t, uintptr_t};
1515
use managed::raw::BoxRepr;
1616
use str;
1717
use sys;
18+
use private::exchange_alloc;
19+
use cast::transmute;
1820

1921
use gc::{cleanup_stack_for_failure, gc, Word};
2022

@@ -27,13 +29,6 @@ pub const FROZEN_BIT: uint = 0x80000000;
2729
pub const FROZEN_BIT: uint = 0x8000000000000000;
2830

2931
pub extern mod rustrt {
30-
#[rust_stack]
31-
unsafe fn rust_upcall_exchange_malloc(td: *c_char, size: uintptr_t)
32-
-> *c_char;
33-
34-
#[rust_stack]
35-
unsafe fn rust_upcall_exchange_free(ptr: *c_char);
36-
3732
#[rust_stack]
3833
unsafe fn rust_upcall_malloc(td: *c_char, size: uintptr_t) -> *c_char;
3934

@@ -67,10 +62,11 @@ pub unsafe fn rt_fail_borrowed() {
6762
}
6863
}
6964

65+
// XXX: Make these signatures agree with exchange_alloc's signatures
7066
#[rt(exchange_malloc)]
7167
#[lang="exchange_malloc"]
7268
pub unsafe fn rt_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
73-
return rustrt::rust_upcall_exchange_malloc(td, size);
69+
transmute(exchange_alloc::malloc(transmute(td), transmute(size)))
7470
}
7571

7672
// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
@@ -79,7 +75,7 @@ pub unsafe fn rt_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
7975
#[rt(exchange_free)]
8076
#[lang="exchange_free"]
8177
pub unsafe fn rt_exchange_free(ptr: *c_char) {
82-
rustrt::rust_upcall_exchange_free(ptr);
78+
exchange_alloc::free(transmute(ptr))
8379
}
8480

8581
#[rt(malloc)]

src/rt/rust_exchange_alloc.cpp

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#include "rust_exchange_alloc.h"
12+
#include "sync/sync.h"
13+
#include <stdlib.h>
14+
#include <assert.h>
15+
#include <string.h>
16+
#include <stdio.h>
17+
18+
uintptr_t exchange_count = 0;
19+
20+
void *
21+
rust_exchange_alloc::malloc(size_t size, bool zero) {
22+
void *value = ::malloc(size);
23+
assert(value);
24+
if (zero) {
25+
memset(value, 0, size);
26+
}
27+
28+
sync::increment(exchange_count);
29+
30+
return value;
31+
}
32+
33+
void *
34+
rust_exchange_alloc::calloc(size_t size) {
35+
return this->malloc(size);
36+
}
37+
38+
void *
39+
rust_exchange_alloc::realloc(void *ptr, size_t size) {
40+
void *new_ptr = ::realloc(ptr, size);
41+
assert(new_ptr);
42+
return new_ptr;
43+
}
44+
45+
void
46+
rust_exchange_alloc::free(void *ptr) {
47+
sync::decrement(exchange_count);
48+
::free(ptr);
49+
}
50+
51+
extern "C" uintptr_t *
52+
rust_get_exchange_count_ptr() {
53+
return &exchange_count;
54+
}
55+
56+
void
57+
rust_check_exchange_count_on_exit() {
58+
if (exchange_count != 0) {
59+
printf("exchange heap not empty on on exit");
60+
printf("%d dangling allocations", (int)exchange_count);
61+
abort();
62+
}
63+
}

src/rt/rust_exchange_alloc.h

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#ifndef RUST_EXCHANGE_ALLOC_H
12+
#define RUST_EXCHANGE_ALLOC_H
13+
14+
#include <stddef.h>
15+
#include <stdint.h>
16+
17+
class rust_exchange_alloc {
18+
public:
19+
void *malloc(size_t size, bool zero = true);
20+
void *calloc(size_t size);
21+
void *realloc(void *mem, size_t size);
22+
void free(void *mem);
23+
};
24+
25+
extern "C" uintptr_t *
26+
rust_get_exchange_count_ptr();
27+
28+
void
29+
rust_check_exchange_count_on_exit();
30+
31+
#endif

src/rt/rust_kernel.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
KLOG_LVL(this, field, log_err, __VA_ARGS__)
2323

2424
rust_kernel::rust_kernel(rust_env *env) :
25-
_region(env, true),
2625
_log(NULL),
2726
max_task_id(INIT_TASK_ID-1), // sync_add_and_fetch increments first
2827
rval(0),
@@ -77,21 +76,21 @@ rust_kernel::fatal(char const *fmt, ...) {
7776

7877
void *
7978
rust_kernel::malloc(size_t size, const char *tag) {
80-
return _region.malloc(size, tag);
79+
return exchange_alloc.malloc(size);
8180
}
8281

8382
void *
8483
rust_kernel::calloc(size_t size, const char *tag) {
85-
return _region.calloc(size, tag);
84+
return exchange_alloc.calloc(size);
8685
}
8786

8887
void *
8988
rust_kernel::realloc(void *mem, size_t size) {
90-
return _region.realloc(mem, size);
89+
return exchange_alloc.realloc(mem, size);
9190
}
9291

9392
void rust_kernel::free(void *mem) {
94-
_region.free(mem);
93+
exchange_alloc.free(mem);
9594
}
9695

9796
rust_sched_id
@@ -217,6 +216,7 @@ rust_kernel::run() {
217216
assert(osmain_driver != NULL);
218217
osmain_driver->start_main_loop();
219218
sched_reaper.join();
219+
rust_check_exchange_count_on_exit();
220220
return rval;
221221
}
222222

src/rt/rust_kernel.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@
4545
#include <map>
4646
#include <vector>
4747

48-
#include "memory_region.h"
48+
#include "rust_exchange_alloc.h"
4949
#include "rust_log.h"
5050
#include "rust_sched_reaper.h"
5151
#include "rust_type.h"
5252
#include "util/hash_map.h"
53+
#include "sync/lock_and_signal.h"
5354

5455
class rust_scheduler;
5556
class rust_sched_driver;
@@ -71,7 +72,7 @@ struct exit_functions {
7172
};
7273

7374
class rust_kernel {
74-
memory_region _region;
75+
rust_exchange_alloc exchange_alloc;
7576
rust_log _log;
7677

7778
// The next task id
@@ -135,7 +136,7 @@ class rust_kernel {
135136
void *calloc(size_t size, const char *tag);
136137
void *realloc(void *mem, size_t size);
137138
void free(void *mem);
138-
memory_region *region() { return &_region; }
139+
rust_exchange_alloc *region() { return &exchange_alloc; }
139140

140141
void fail();
141142

src/rt/rust_sched_loop.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ rust_sched_loop::run_single_turn() {
260260

261261
assert(!extra_c_stack);
262262
if (cached_c_stack) {
263-
destroy_stack(kernel->region(), cached_c_stack);
263+
destroy_exchange_stack(kernel->region(), cached_c_stack);
264264
cached_c_stack = NULL;
265265
}
266266

@@ -389,14 +389,15 @@ void
389389
rust_sched_loop::prepare_c_stack(rust_task *task) {
390390
assert(!extra_c_stack);
391391
if (!cached_c_stack && !task->have_c_stack()) {
392-
cached_c_stack = create_stack(kernel->region(), C_STACK_SIZE);
392+
cached_c_stack = create_exchange_stack(kernel->region(),
393+
C_STACK_SIZE);
393394
}
394395
}
395396

396397
void
397398
rust_sched_loop::unprepare_c_stack() {
398399
if (extra_c_stack) {
399-
destroy_stack(kernel->region(), extra_c_stack);
400+
destroy_exchange_stack(kernel->region(), extra_c_stack);
400401
extra_c_stack = NULL;
401402
}
402403
}

src/rt/rust_sched_loop.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ struct rust_sched_loop
135135
void place_task_in_tls(rust_task *task);
136136

137137
static rust_task *get_task_tls();
138+
static rust_task *try_get_task_tls();
138139

139140
// Called by each task when they are ready to be destroyed
140141
void release_task(rust_task *task);
@@ -154,7 +155,7 @@ rust_sched_loop::get_log() {
154155
return _log;
155156
}
156157

157-
inline rust_task* rust_sched_loop::get_task_tls()
158+
inline rust_task* rust_sched_loop::try_get_task_tls()
158159
{
159160
if (!tls_initialized)
160161
return NULL;
@@ -165,6 +166,12 @@ inline rust_task* rust_sched_loop::get_task_tls()
165166
rust_task *task = reinterpret_cast<rust_task *>
166167
(pthread_getspecific(task_key));
167168
#endif
169+
return task;
170+
}
171+
172+
inline rust_task* rust_sched_loop::get_task_tls()
173+
{
174+
rust_task *task = try_get_task_tls();
168175
assert(task && "Couldn't get the task from TLS!");
169176
return task;
170177
}

0 commit comments

Comments
 (0)