2013-01-25 17:51:53 -08:00
|
|
|
// 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.
|
|
|
|
|
2013-01-12 23:27:46 -08:00
|
|
|
/*!
|
|
|
|
Global data
|
|
|
|
|
|
|
|
An interface for creating and retrieving values with global
|
|
|
|
(per-runtime) scope.
|
|
|
|
|
|
|
|
Global values are stored in a map and protected by a single global
|
|
|
|
mutex. Operations are provided for accessing and cloning the value
|
|
|
|
under the mutex.
|
|
|
|
|
|
|
|
Because all globals go through a single mutex, they should be used
|
|
|
|
sparingly. The interface is intended to be used with clonable,
|
|
|
|
atomically reference counted synchronization types, like ARCs, in
|
|
|
|
which case the value should be cached locally whenever possible to
|
|
|
|
avoid hitting the mutex.
|
|
|
|
*/
|
|
|
|
|
|
|
|
use cast::{transmute, reinterpret_cast};
|
|
|
|
use clone::Clone;
|
|
|
|
use kinds::Owned;
|
|
|
|
use libc::{c_void, uintptr_t};
|
|
|
|
use option::{Option, Some, None};
|
|
|
|
use ops::Drop;
|
2013-02-27 19:53:31 -08:00
|
|
|
use unstable::{Exclusive, exclusive};
|
|
|
|
use unstable::at_exit::at_exit;
|
|
|
|
use unstable::intrinsics::atomic_cxchg;
|
2013-01-25 17:51:53 -08:00
|
|
|
use hashmap::linear::LinearMap;
|
2013-01-12 23:27:46 -08:00
|
|
|
use sys::Closure;
|
2013-02-27 00:10:03 -05:00
|
|
|
|
2013-02-28 11:57:33 -05:00
|
|
|
#[cfg(test)] use unstable::{SharedMutableState, shared_mutable_state};
|
|
|
|
#[cfg(test)] use unstable::get_shared_immutable_state;
|
|
|
|
#[cfg(test)] use task::spawn;
|
|
|
|
#[cfg(test)] use uint;
|
2013-01-12 23:27:46 -08:00
|
|
|
|
2013-01-28 10:46:43 -08:00
|
|
|
pub type GlobalDataKey<T> = &fn(v: T);
|
2013-01-12 23:27:46 -08:00
|
|
|
|
2013-02-20 17:07:17 -08:00
|
|
|
pub unsafe fn global_data_clone_create<T:Owned + Clone>(
|
2013-01-12 23:27:46 -08:00
|
|
|
key: GlobalDataKey<T>, create: &fn() -> ~T) -> T {
|
|
|
|
/*!
|
|
|
|
* Clone a global value or, if it has not been created,
|
|
|
|
* first construct the value then return a clone.
|
|
|
|
*
|
|
|
|
* # Safety note
|
|
|
|
*
|
|
|
|
* Both the clone operation and the constructor are
|
|
|
|
* called while the global lock is held. Recursive
|
|
|
|
* use of the global interface in either of these
|
|
|
|
* operations will result in deadlock.
|
|
|
|
*/
|
|
|
|
global_data_clone_create_(key_ptr(key), create)
|
|
|
|
}
|
|
|
|
|
2013-02-20 17:07:17 -08:00
|
|
|
unsafe fn global_data_clone_create_<T:Owned + Clone>(
|
2013-01-12 23:27:46 -08:00
|
|
|
key: uint, create: &fn() -> ~T) -> T {
|
|
|
|
|
|
|
|
let mut clone_value: Option<T> = None;
|
|
|
|
do global_data_modify_(key) |value: Option<~T>| {
|
|
|
|
match value {
|
|
|
|
None => {
|
|
|
|
let value = create();
|
|
|
|
clone_value = Some(value.clone());
|
|
|
|
Some(value)
|
|
|
|
}
|
|
|
|
Some(value) => {
|
|
|
|
clone_value = Some(value.clone());
|
|
|
|
Some(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return clone_value.unwrap();
|
|
|
|
}
|
|
|
|
|
2013-02-20 17:07:17 -08:00
|
|
|
unsafe fn global_data_modify<T:Owned>(
|
2013-01-12 23:27:46 -08:00
|
|
|
key: GlobalDataKey<T>, op: &fn(Option<~T>) -> Option<~T>) {
|
|
|
|
|
|
|
|
global_data_modify_(key_ptr(key), op)
|
|
|
|
}
|
|
|
|
|
2013-02-20 17:07:17 -08:00
|
|
|
unsafe fn global_data_modify_<T:Owned>(
|
2013-01-12 23:27:46 -08:00
|
|
|
key: uint, op: &fn(Option<~T>) -> Option<~T>) {
|
|
|
|
|
|
|
|
let mut old_dtor = None;
|
2013-01-25 17:51:53 -08:00
|
|
|
do get_global_state().with |gs| {
|
2013-01-12 23:27:46 -08:00
|
|
|
let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) {
|
|
|
|
Some((ptr, dtor)) => {
|
|
|
|
let value: ~T = transmute(ptr);
|
|
|
|
(op(Some(value)), Some(dtor))
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
(op(None), None)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
match maybe_new_value {
|
|
|
|
Some(value) => {
|
|
|
|
let data: *c_void = transmute(value);
|
|
|
|
let dtor: ~fn() = match maybe_dtor {
|
|
|
|
Some(dtor) => dtor,
|
|
|
|
None => {
|
|
|
|
let dtor: ~fn() = || unsafe {
|
|
|
|
let _destroy_value: ~T = transmute(data);
|
|
|
|
};
|
|
|
|
dtor
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let value = (data, dtor);
|
|
|
|
gs.map.insert(key, value);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
match maybe_dtor {
|
|
|
|
Some(dtor) => old_dtor = Some(dtor),
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-20 17:07:17 -08:00
|
|
|
pub unsafe fn global_data_clone<T:Owned + Clone>(
|
2013-01-19 23:38:17 -08:00
|
|
|
key: GlobalDataKey<T>) -> Option<T> {
|
|
|
|
let mut maybe_clone: Option<T> = None;
|
|
|
|
do global_data_modify(key) |current| {
|
|
|
|
match ¤t {
|
|
|
|
&Some(~ref value) => {
|
|
|
|
maybe_clone = Some(value.clone());
|
|
|
|
}
|
|
|
|
&None => ()
|
|
|
|
}
|
|
|
|
current
|
|
|
|
}
|
|
|
|
return maybe_clone;
|
|
|
|
}
|
|
|
|
|
2013-01-12 23:27:46 -08:00
|
|
|
// GlobalState is a map from keys to unique pointers and a
|
|
|
|
// destructor. Keys are pointers derived from the type of the
|
|
|
|
// global value. There is a single GlobalState instance per runtime.
|
|
|
|
struct GlobalState {
|
|
|
|
map: LinearMap<uint, (*c_void, ~fn())>
|
|
|
|
}
|
|
|
|
|
2013-02-14 11:47:00 -08:00
|
|
|
impl Drop for GlobalState {
|
2013-01-12 23:27:46 -08:00
|
|
|
fn finalize(&self) {
|
|
|
|
for self.map.each_value |v| {
|
|
|
|
match v {
|
|
|
|
&(_, ref dtor) => (*dtor)()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-25 17:51:53 -08:00
|
|
|
fn get_global_state() -> Exclusive<GlobalState> {
|
2013-01-12 23:27:46 -08:00
|
|
|
|
|
|
|
const POISON: int = -1;
|
|
|
|
|
2013-01-31 19:34:46 -08:00
|
|
|
// FIXME #4728: Doing atomic_cxchg to initialize the global state
|
2013-01-12 23:27:46 -08:00
|
|
|
// lazily, which wouldn't be necessary with a runtime written
|
|
|
|
// in Rust
|
2013-01-25 17:51:53 -08:00
|
|
|
let global_ptr = unsafe { rust_get_global_data_ptr() };
|
2013-01-12 23:27:46 -08:00
|
|
|
|
2013-01-25 17:51:53 -08:00
|
|
|
if unsafe { *global_ptr } == 0 {
|
2013-01-12 23:27:46 -08:00
|
|
|
// Global state doesn't exist yet, probably
|
|
|
|
|
|
|
|
// The global state object
|
|
|
|
let state = GlobalState {
|
2013-01-25 17:51:53 -08:00
|
|
|
map: LinearMap::new()
|
2013-01-12 23:27:46 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
// It's under a reference-counted mutex
|
|
|
|
let state = ~exclusive(state);
|
|
|
|
|
|
|
|
// Convert it to an integer
|
2013-01-10 10:59:58 -08:00
|
|
|
let state_i: int = unsafe {
|
|
|
|
let state_ptr: &Exclusive<GlobalState> = state;
|
|
|
|
transmute(state_ptr)
|
|
|
|
};
|
2013-01-12 23:27:46 -08:00
|
|
|
|
|
|
|
// Swap our structure into the global pointer
|
2013-01-25 17:51:53 -08:00
|
|
|
let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) };
|
2013-01-12 23:27:46 -08:00
|
|
|
|
|
|
|
// Sanity check that we're not trying to reinitialize after shutdown
|
|
|
|
assert prev_i != POISON;
|
|
|
|
|
|
|
|
if prev_i == 0 {
|
|
|
|
// Successfully installed the global pointer
|
|
|
|
|
|
|
|
// Take a handle to return
|
|
|
|
let clone = state.clone();
|
|
|
|
|
|
|
|
// Install a runtime exit function to destroy the global object
|
2013-01-25 17:51:53 -08:00
|
|
|
do at_exit {
|
2013-01-12 23:27:46 -08:00
|
|
|
// Poison the global pointer
|
2013-01-25 17:51:53 -08:00
|
|
|
let prev_i = unsafe {
|
|
|
|
atomic_cxchg(&mut *global_ptr, state_i, POISON)
|
|
|
|
};
|
2013-01-12 23:27:46 -08:00
|
|
|
assert prev_i == state_i;
|
|
|
|
|
|
|
|
// Capture the global state object in the at_exit closure
|
|
|
|
// so that it is destroyed at the right time
|
|
|
|
let _capture_global_state = &state;
|
|
|
|
};
|
|
|
|
return clone;
|
|
|
|
} else {
|
|
|
|
// Somebody else initialized the globals first
|
2013-01-25 17:51:53 -08:00
|
|
|
let state: &Exclusive<GlobalState> = unsafe { transmute(prev_i) };
|
2013-01-12 23:27:46 -08:00
|
|
|
return state.clone();
|
|
|
|
}
|
|
|
|
} else {
|
2013-01-25 17:51:53 -08:00
|
|
|
let state: &Exclusive<GlobalState> = unsafe {
|
|
|
|
transmute(*global_ptr)
|
|
|
|
};
|
2013-01-12 23:27:46 -08:00
|
|
|
return state.clone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-20 17:07:17 -08:00
|
|
|
fn key_ptr<T:Owned>(key: GlobalDataKey<T>) -> uint {
|
2013-01-25 17:51:53 -08:00
|
|
|
unsafe {
|
|
|
|
let closure: Closure = reinterpret_cast(&key);
|
|
|
|
return transmute(closure.code);
|
|
|
|
}
|
2013-01-12 23:27:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
extern {
|
|
|
|
fn rust_get_global_data_ptr() -> *mut int;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-01-25 17:51:53 -08:00
|
|
|
fn test_clone_rc() {
|
2013-01-12 23:27:46 -08:00
|
|
|
type MyType = SharedMutableState<int>;
|
|
|
|
|
|
|
|
fn key(_v: SharedMutableState<int>) { }
|
|
|
|
|
|
|
|
for uint::range(0, 100) |_| {
|
2013-01-25 17:51:53 -08:00
|
|
|
do spawn {
|
|
|
|
unsafe {
|
|
|
|
let val = do global_data_clone_create(key) {
|
|
|
|
~shared_mutable_state(10)
|
|
|
|
};
|
2013-01-12 23:27:46 -08:00
|
|
|
|
2013-01-25 17:51:53 -08:00
|
|
|
assert get_shared_immutable_state(&val) == &10;
|
|
|
|
}
|
2013-01-12 23:27:46 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-01-25 17:51:53 -08:00
|
|
|
fn test_modify() {
|
2013-01-12 23:27:46 -08:00
|
|
|
type MyType = SharedMutableState<int>;
|
|
|
|
|
|
|
|
fn key(_v: SharedMutableState<int>) { }
|
|
|
|
|
2013-01-25 17:51:53 -08:00
|
|
|
unsafe {
|
|
|
|
do global_data_modify(key) |v| {
|
|
|
|
match v {
|
|
|
|
None => {
|
|
|
|
unsafe {
|
|
|
|
Some(~shared_mutable_state(10))
|
|
|
|
}
|
|
|
|
}
|
2013-02-11 19:26:38 -08:00
|
|
|
_ => fail!()
|
2013-01-12 23:27:46 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-25 17:51:53 -08:00
|
|
|
do global_data_modify(key) |v| {
|
|
|
|
match v {
|
|
|
|
Some(sms) => {
|
|
|
|
let v = get_shared_immutable_state(sms);
|
|
|
|
assert *v == 10;
|
|
|
|
None
|
|
|
|
},
|
2013-02-11 19:26:38 -08:00
|
|
|
_ => fail!()
|
2013-01-25 17:51:53 -08:00
|
|
|
}
|
2013-01-12 23:27:46 -08:00
|
|
|
}
|
|
|
|
|
2013-01-25 17:51:53 -08:00
|
|
|
do global_data_modify(key) |v| {
|
|
|
|
match v {
|
|
|
|
None => {
|
|
|
|
unsafe {
|
|
|
|
Some(~shared_mutable_state(10))
|
|
|
|
}
|
|
|
|
}
|
2013-02-11 19:26:38 -08:00
|
|
|
_ => fail!()
|
2013-01-12 23:27:46 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|