Skip to content

Commit

Permalink
Merge pull request #4619 from brson/exchange
Browse files Browse the repository at this point in the history
Some work on freestanding Rust: foreign calls, exchange allocator
  • Loading branch information
brson committed Feb 7, 2013
2 parents a281795 + e43c5bd commit 6e9298a
Show file tree
Hide file tree
Showing 17 changed files with 306 additions and 120 deletions.
1 change: 1 addition & 0 deletions mk/rt.mk
Expand Up @@ -63,6 +63,7 @@ RUNTIME_CXXS_$(1) := \
rt/rust_log.cpp \
rt/rust_gc_metadata.cpp \
rt/rust_util.cpp \
rt/rust_exchange_alloc.cpp \
rt/isaac/randport.cpp \
rt/miniz.cpp \
rt/rust_kernel.cpp \
Expand Down
13 changes: 13 additions & 0 deletions src/libcore/private.rs
Expand Up @@ -30,6 +30,8 @@ pub mod global;
pub mod finally;
#[path = "private/weak_task.rs"]
pub mod weak_task;
#[path = "private/exchange_alloc.rs"]
pub mod exchange_alloc;

extern mod rustrt {
pub unsafe fn rust_create_little_lock() -> rust_little_lock;
Expand Down Expand Up @@ -86,6 +88,17 @@ fn test_run_in_bare_thread() {
}
}

#[test]
fn test_run_in_bare_thread_exchange() {
unsafe {
// Does the exchange heap work without the runtime?
let i = ~100;
do run_in_bare_thread {
assert i == ~100;
}
}
}

fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
unsafe {
let old = rusti::atomic_cxchg(address, oldval, newval);
Expand Down
79 changes: 79 additions & 0 deletions src/libcore/private/exchange_alloc.rs
@@ -0,0 +1,79 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use sys::{TypeDesc, size_of};
use libc::{c_void, size_t, uintptr_t};
use c_malloc = libc::malloc;
use c_free = libc::free;
use managed::raw::{BoxHeaderRepr, BoxRepr};
use cast::transmute;
use ptr::{set_memory, null};
use intrinsic::TyDesc;

pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void {
unsafe {
assert td.is_not_null();

let total_size = get_box_size(size, (*td).align);
let p = c_malloc(total_size as size_t);
assert p.is_not_null();

// FIXME #4761: Would be very nice to not memset all allocations
let p: *mut u8 = transmute(p);
set_memory(p, 0, total_size);

// FIXME #3475: Converting between our two different tydesc types
let td: *TyDesc = transmute(td);

let box: &mut BoxRepr = transmute(p);
box.header.ref_count = -1; // Exchange values not ref counted
box.header.type_desc = td;
box.header.prev = null();
box.header.next = null();

let exchange_count = &mut *rust_get_exchange_count_ptr();
rusti::atomic_xadd(exchange_count, 1);

return transmute(box);
}
}

pub unsafe fn free(ptr: *c_void) {
let exchange_count = &mut *rust_get_exchange_count_ptr();
rusti::atomic_xsub(exchange_count, 1);

assert ptr.is_not_null();
c_free(ptr);
}

fn get_box_size(body_size: uint, body_align: uint) -> uint {
let header_size = size_of::<BoxHeaderRepr>();
// FIXME (#2699): This alignment calculation is suspicious. Is it right?
let total_size = align_to(header_size, body_align) + body_size;
return total_size;
}

// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power
// of two.
fn align_to(size: uint, align: uint) -> uint {
assert align != 0;
(size + align - 1) & !(align - 1)
}

extern {
#[rust_stack]
fn rust_get_exchange_count_ptr() -> *mut int;
}

#[abi = "rust-intrinsic"]
extern mod rusti {
fn atomic_xadd(dst: &mut int, src: int) -> int;
fn atomic_xsub(dst: &mut int, src: int) -> int;
}
14 changes: 5 additions & 9 deletions src/libcore/rt.rs
Expand Up @@ -15,6 +15,8 @@ use libc::{c_char, c_uchar, c_void, size_t, uintptr_t};
use managed::raw::BoxRepr;
use str;
use sys;
use private::exchange_alloc;
use cast::transmute;

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

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

pub extern mod rustrt {
#[rust_stack]
unsafe fn rust_upcall_exchange_malloc(td: *c_char, size: uintptr_t)
-> *c_char;

#[rust_stack]
unsafe fn rust_upcall_exchange_free(ptr: *c_char);

#[rust_stack]
unsafe fn rust_upcall_malloc(td: *c_char, size: uintptr_t) -> *c_char;

Expand Down Expand Up @@ -67,10 +62,11 @@ pub unsafe fn rt_fail_borrowed() {
}
}

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

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

#[rt(malloc)]
Expand Down
63 changes: 63 additions & 0 deletions src/rt/rust_exchange_alloc.cpp
@@ -0,0 +1,63 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#include "rust_exchange_alloc.h"
#include "sync/sync.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>

uintptr_t exchange_count = 0;

void *
rust_exchange_alloc::malloc(size_t size, bool zero) {
void *value = ::malloc(size);
assert(value);
if (zero) {
memset(value, 0, size);
}

sync::increment(exchange_count);

return value;
}

void *
rust_exchange_alloc::calloc(size_t size) {
return this->malloc(size);
}

void *
rust_exchange_alloc::realloc(void *ptr, size_t size) {
void *new_ptr = ::realloc(ptr, size);
assert(new_ptr);
return new_ptr;
}

void
rust_exchange_alloc::free(void *ptr) {
sync::decrement(exchange_count);
::free(ptr);
}

extern "C" uintptr_t *
rust_get_exchange_count_ptr() {
return &exchange_count;
}

void
rust_check_exchange_count_on_exit() {
if (exchange_count != 0) {
printf("exchange heap not empty on on exit");
printf("%d dangling allocations", (int)exchange_count);
abort();
}
}
31 changes: 31 additions & 0 deletions src/rt/rust_exchange_alloc.h
@@ -0,0 +1,31 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#ifndef RUST_EXCHANGE_ALLOC_H
#define RUST_EXCHANGE_ALLOC_H

#include <stddef.h>
#include <stdint.h>

class rust_exchange_alloc {
public:
void *malloc(size_t size, bool zero = true);
void *calloc(size_t size);
void *realloc(void *mem, size_t size);
void free(void *mem);
};

extern "C" uintptr_t *
rust_get_exchange_count_ptr();

void
rust_check_exchange_count_on_exit();

#endif
10 changes: 5 additions & 5 deletions src/rt/rust_kernel.cpp
Expand Up @@ -22,7 +22,6 @@
KLOG_LVL(this, field, log_err, __VA_ARGS__)

rust_kernel::rust_kernel(rust_env *env) :
_region(env, true),
_log(NULL),
max_task_id(INIT_TASK_ID-1), // sync_add_and_fetch increments first
rval(0),
Expand Down Expand Up @@ -77,21 +76,21 @@ rust_kernel::fatal(char const *fmt, ...) {

void *
rust_kernel::malloc(size_t size, const char *tag) {
return _region.malloc(size, tag);
return exchange_alloc.malloc(size);
}

void *
rust_kernel::calloc(size_t size, const char *tag) {
return _region.calloc(size, tag);
return exchange_alloc.calloc(size);
}

void *
rust_kernel::realloc(void *mem, size_t size) {
return _region.realloc(mem, size);
return exchange_alloc.realloc(mem, size);
}

void rust_kernel::free(void *mem) {
_region.free(mem);
exchange_alloc.free(mem);
}

rust_sched_id
Expand Down Expand Up @@ -217,6 +216,7 @@ rust_kernel::run() {
assert(osmain_driver != NULL);
osmain_driver->start_main_loop();
sched_reaper.join();
rust_check_exchange_count_on_exit();
return rval;
}

Expand Down
7 changes: 4 additions & 3 deletions src/rt/rust_kernel.h
Expand Up @@ -45,11 +45,12 @@
#include <map>
#include <vector>

#include "memory_region.h"
#include "rust_exchange_alloc.h"
#include "rust_log.h"
#include "rust_sched_reaper.h"
#include "rust_type.h"
#include "util/hash_map.h"
#include "sync/lock_and_signal.h"

class rust_scheduler;
class rust_sched_driver;
Expand All @@ -71,7 +72,7 @@ struct exit_functions {
};

class rust_kernel {
memory_region _region;
rust_exchange_alloc exchange_alloc;
rust_log _log;

// The next task id
Expand Down Expand Up @@ -135,7 +136,7 @@ class rust_kernel {
void *calloc(size_t size, const char *tag);
void *realloc(void *mem, size_t size);
void free(void *mem);
memory_region *region() { return &_region; }
rust_exchange_alloc *region() { return &exchange_alloc; }

void fail();

Expand Down
7 changes: 4 additions & 3 deletions src/rt/rust_sched_loop.cpp
Expand Up @@ -260,7 +260,7 @@ rust_sched_loop::run_single_turn() {

assert(!extra_c_stack);
if (cached_c_stack) {
destroy_stack(kernel->region(), cached_c_stack);
destroy_exchange_stack(kernel->region(), cached_c_stack);
cached_c_stack = NULL;
}

Expand Down Expand Up @@ -389,14 +389,15 @@ void
rust_sched_loop::prepare_c_stack(rust_task *task) {
assert(!extra_c_stack);
if (!cached_c_stack && !task->have_c_stack()) {
cached_c_stack = create_stack(kernel->region(), C_STACK_SIZE);
cached_c_stack = create_exchange_stack(kernel->region(),
C_STACK_SIZE);
}
}

void
rust_sched_loop::unprepare_c_stack() {
if (extra_c_stack) {
destroy_stack(kernel->region(), extra_c_stack);
destroy_exchange_stack(kernel->region(), extra_c_stack);
extra_c_stack = NULL;
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/rt/rust_sched_loop.h
Expand Up @@ -135,6 +135,7 @@ struct rust_sched_loop
void place_task_in_tls(rust_task *task);

static rust_task *get_task_tls();
static rust_task *try_get_task_tls();

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

inline rust_task* rust_sched_loop::get_task_tls()
inline rust_task* rust_sched_loop::try_get_task_tls()
{
if (!tls_initialized)
return NULL;
Expand All @@ -165,6 +166,12 @@ inline rust_task* rust_sched_loop::get_task_tls()
rust_task *task = reinterpret_cast<rust_task *>
(pthread_getspecific(task_key));
#endif
return task;
}

inline rust_task* rust_sched_loop::get_task_tls()
{
rust_task *task = try_get_task_tls();
assert(task && "Couldn't get the task from TLS!");
return task;
}
Expand Down

0 comments on commit 6e9298a

Please sign in to comment.