Skip to content

Commit 1b7c996

Browse files
committed
std::rt: Support os::args
1 parent 7a9a6e4 commit 1b7c996

File tree

5 files changed

+176
-11
lines changed

5 files changed

+176
-11
lines changed

src/libstd/os.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ use option::{Some, None};
4040
use os;
4141
use prelude::*;
4242
use ptr;
43+
use rt;
44+
use rt::TaskContext;
4345
use str;
4446
use uint;
4547
use unstable::finally::Finally;
@@ -1167,10 +1169,17 @@ pub fn real_args() -> ~[~str] {
11671169
#[cfg(target_os = "android")]
11681170
#[cfg(target_os = "freebsd")]
11691171
pub fn real_args() -> ~[~str] {
1170-
unsafe {
1171-
let argc = rustrt::rust_get_argc();
1172-
let argv = rustrt::rust_get_argv();
1173-
load_argc_and_argv(argc, argv)
1172+
if rt::context() == TaskContext {
1173+
match rt::args::clone() {
1174+
Some(args) => args,
1175+
None => fail!("process arguments not initialized")
1176+
}
1177+
} else {
1178+
unsafe {
1179+
let argc = rustrt::rust_get_argc();
1180+
let argv = rustrt::rust_get_argv();
1181+
load_argc_and_argv(argc, argv)
1182+
}
11741183
}
11751184
}
11761185

src/libstd/rt/args.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright 2012-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+
//! Global storage for command line arguments
12+
//!
13+
//! The current incarnation of the Rust runtime expects for
14+
//! the processes `argc` and `argv` arguments to be stored
15+
//! in a globally-accessible location for use by the `os` module.
16+
//!
17+
//! XXX: Would be nice for this to not exist.
18+
//! XXX: This has a lot of C glue for lack of globals.
19+
20+
use libc;
21+
use option::{Option, Some, None};
22+
use str;
23+
use uint;
24+
use unstable::finally::Finally;
25+
use util;
26+
27+
/// One-time global initialization.
28+
pub unsafe fn init(argc: int, argv: **u8) {
29+
let args = load_argc_and_argv(argc, argv);
30+
put(args);
31+
}
32+
33+
/// One-time global cleanup.
34+
pub fn cleanup() {
35+
rtassert!(take().is_some());
36+
}
37+
38+
/// Take the global arguments from global storage.
39+
pub fn take() -> Option<~[~str]> {
40+
with_lock(|| unsafe {
41+
let ptr = get_global_ptr();
42+
let val = util::replace(&mut *ptr, None);
43+
val.map(|s: &~~[~str]| (**s).clone())
44+
})
45+
}
46+
47+
/// Give the global arguments to global storage.
48+
///
49+
/// It is an error if the arguments already exist.
50+
pub fn put(args: ~[~str]) {
51+
with_lock(|| unsafe {
52+
let ptr = get_global_ptr();
53+
rtassert!((*ptr).is_none());
54+
(*ptr) = Some(~args.clone());
55+
})
56+
}
57+
58+
/// Make a clone of the global arguments.
59+
pub fn clone() -> Option<~[~str]> {
60+
with_lock(|| unsafe {
61+
let ptr = get_global_ptr();
62+
(*ptr).map(|s: &~~[~str]| (**s).clone())
63+
})
64+
}
65+
66+
fn with_lock<T>(f: &fn() -> T) -> T {
67+
do (|| {
68+
unsafe {
69+
rust_take_global_args_lock();
70+
f()
71+
}
72+
}).finally {
73+
unsafe {
74+
rust_drop_global_args_lock();
75+
}
76+
}
77+
}
78+
79+
fn get_global_ptr() -> *mut Option<~~[~str]> {
80+
unsafe { rust_get_global_args_ptr() }
81+
}
82+
83+
// Copied from `os`.
84+
unsafe fn load_argc_and_argv(argc: int, argv: **u8) -> ~[~str] {
85+
let mut args = ~[];
86+
for uint::range(0, argc as uint) |i| {
87+
args.push(str::raw::from_c_str(*(argv as **libc::c_char).offset(i)));
88+
}
89+
return args;
90+
}
91+
92+
extern {
93+
fn rust_take_global_args_lock();
94+
fn rust_drop_global_args_lock();
95+
fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>;
96+
}
97+
98+
#[cfg(test)]
99+
mod tests {
100+
use option::{Some, None};
101+
use super::*;
102+
use unstable::finally::Finally;
103+
104+
#[test]
105+
fn smoke_test() {
106+
// Preserve the actual global state.
107+
let saved_value = take();
108+
109+
let expected = ~[~"happy", ~"today?"];
110+
111+
put(expected.clone());
112+
assert!(clone() == Some(expected.clone()));
113+
assert!(take() == Some(expected.clone()));
114+
assert!(take() == None);
115+
116+
do (|| {
117+
}).finally {
118+
// Restore the actual global state.
119+
match saved_value {
120+
Some(ref args) => put(args.clone()),
121+
None => ()
122+
}
123+
}
124+
}
125+
}

src/libstd/rt/mod.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ pub mod metrics;
159159
/// Just stuff
160160
pub mod util;
161161

162+
// Global command line argument storage
163+
pub mod args;
164+
162165
/// Set up a default runtime configuration, given compiler-supplied arguments.
163166
///
164167
/// This is invoked by the `start` _language item_ (unstable::lang) to
@@ -173,20 +176,28 @@ pub mod util;
173176
/// # Return value
174177
///
175178
/// The return value is used as the process return code. 0 on success, 101 on error.
176-
pub fn start(_argc: int, _argv: **u8, crate_map: *u8, main: ~fn()) -> int {
179+
pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
177180

178-
init(crate_map);
181+
init(argc, argv, crate_map);
179182
let exit_code = run(main);
180183
cleanup();
181184

182185
return exit_code;
183186
}
184187

185-
/// One-time runtime initialization. Currently all this does is set up logging
186-
/// based on the RUST_LOG environment variable.
187-
pub fn init(crate_map: *u8) {
188-
logging::init(crate_map);
189-
unsafe { rust_update_gc_metadata(crate_map) }
188+
/// One-time runtime initialization.
189+
///
190+
/// Initializes global state, including frobbing
191+
/// the crate's logging flags, registering GC
192+
/// metadata, and storing the process arguments.
193+
pub fn init(argc: int, argv: **u8, crate_map: *u8) {
194+
// XXX: Derefing these pointers is not safe.
195+
// Need to propagate the unsafety to `start`.
196+
unsafe {
197+
args::init(argc, argv);
198+
logging::init(crate_map);
199+
rust_update_gc_metadata(crate_map);
200+
}
190201

191202
extern {
192203
fn rust_update_gc_metadata(crate_map: *u8);
@@ -195,6 +206,7 @@ pub fn init(crate_map: *u8) {
195206

196207
/// One-time runtime cleanup.
197208
pub fn cleanup() {
209+
args::cleanup();
198210
global_heap::cleanup();
199211
}
200212

src/rt/rust_builtin.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,24 @@ rust_get_num_cpus() {
932932
return get_num_cpus();
933933
}
934934

935+
static lock_and_signal global_args_lock;
936+
static uintptr_t global_args_ptr = 0;
937+
938+
extern "C" CDECL void
939+
rust_take_global_args_lock() {
940+
global_args_lock.lock();
941+
}
942+
943+
extern "C" CDECL void
944+
rust_drop_global_args_lock() {
945+
global_args_lock.unlock();
946+
}
947+
948+
extern "C" CDECL uintptr_t*
949+
rust_get_global_args_ptr() {
950+
return &global_args_ptr;
951+
}
952+
935953
//
936954
// Local Variables:
937955
// mode: C++

src/rt/rustrt.def.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,4 @@ rust_drop_env_lock
242242
rust_update_log_settings
243243
rust_running_on_valgrind
244244
rust_get_num_cpus
245+
rust_get_global_args_ptr

0 commit comments

Comments
 (0)