Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some work on freestanding Rust: foreign calls, exchange allocator #4619

Merged
merged 3 commits into from
Feb 7, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mk/rt.mk
Original file line number Diff line number Diff line change
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
3 changes: 0 additions & 3 deletions mk/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -746,9 +746,6 @@ $(3)/test/$$(FT_DRIVER)-$(2).out: \
--logfile tmp/$$(FT_DRIVER)-$(2).log

check-fast-T-$(2)-H-$(3): \
check-stage2-T-$(2)-H-$(3)-rustc \
check-stage2-T-$(2)-H-$(3)-core \
check-stage2-T-$(2)-H-$(3)-std \
$(3)/test/$$(FT_DRIVER)-$(2).out

endef
Expand Down
13 changes: 13 additions & 0 deletions src/libcore/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,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 @@ -91,6 +93,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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,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 @@ -30,13 +32,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 @@ -70,10 +65,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 @@ -82,7 +78,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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading