core: Serialize all access to the environment using a weak global task
This commit is contained in:
parent
30385022c1
commit
46cc11ea88
|
@ -199,6 +199,7 @@ mod extfmt;
|
|||
mod unicode;
|
||||
mod priv;
|
||||
mod cmath;
|
||||
mod global_env;
|
||||
|
||||
|
||||
// Local Variables:
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
#[doc = "Internal module for serializing access to getenv/setenv"];
|
||||
|
||||
export getenv;
|
||||
export setenv;
|
||||
|
||||
native mod rustrt {
|
||||
fn rust_global_env_chan_ptr() -> *libc::uintptr_t;
|
||||
}
|
||||
|
||||
enum msg {
|
||||
msg_getenv(str, comm::chan<option<str>>),
|
||||
msg_setenv(str, str, comm::chan<()>)
|
||||
}
|
||||
|
||||
fn getenv(n: str) -> option<str> {
|
||||
let env_ch = get_global_env_chan();
|
||||
let po = comm::port();
|
||||
comm::send(env_ch, msg_getenv(n, comm::chan(po)));
|
||||
comm::recv(po)
|
||||
}
|
||||
|
||||
fn setenv(n: str, v: str) {
|
||||
let env_ch = get_global_env_chan();
|
||||
let po = comm::port();
|
||||
comm::send(env_ch, msg_setenv(n, v, comm::chan(po)));
|
||||
comm::recv(po)
|
||||
}
|
||||
|
||||
fn get_global_env_chan() -> comm::chan<msg> {
|
||||
let global_ptr = rustrt::rust_global_env_chan_ptr();
|
||||
let builder_fn = {||
|
||||
let builder = task::builder();
|
||||
task::unsupervise(builder);
|
||||
task::set_opts(builder, {
|
||||
sched: some({
|
||||
mode: task::single_threaded,
|
||||
// FIXME: This would be a good place to use
|
||||
// a very small native stack
|
||||
native_stack_size: none
|
||||
})
|
||||
with task::get_opts(builder)
|
||||
});
|
||||
builder
|
||||
};
|
||||
unsafe {
|
||||
priv::chan_from_global_ptr(
|
||||
global_ptr, builder_fn, global_env_task)
|
||||
}
|
||||
}
|
||||
|
||||
fn global_env_task(msg_po: comm::port<msg>) unsafe {
|
||||
priv::weaken_task {|weak_po|
|
||||
loop {
|
||||
alt comm::select2(msg_po, weak_po) {
|
||||
either::left(msg_getenv(n, resp_ch)) {
|
||||
comm::send(resp_ch, impl::getenv(n))
|
||||
}
|
||||
either::left(msg_setenv(n, v, resp_ch)) {
|
||||
comm::send(resp_ch, impl::setenv(n, v))
|
||||
}
|
||||
either::right(_) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod impl {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn getenv(n: str) -> option<str> unsafe {
|
||||
let s = str::as_c_str(n, libc::getenv);
|
||||
ret if unsafe::reinterpret_cast(s) == 0 {
|
||||
option::none::<str>
|
||||
} else {
|
||||
let s = unsafe::reinterpret_cast(s);
|
||||
option::some::<str>(str::unsafe::from_buf(s))
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
fn getenv(n: str) -> option<str> unsafe {
|
||||
import libc::types::os::arch::extra::*;
|
||||
import libc::funcs::extra::kernel32::*;
|
||||
import win32::*;
|
||||
as_utf16_p(n) {|u|
|
||||
fill_utf16_buf_and_decode() {|buf, sz|
|
||||
GetEnvironmentVariableW(u, buf, sz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn setenv(n: str, v: str) {
|
||||
|
||||
// FIXME: remove this when export globs work properly.
|
||||
import libc::funcs::posix01::unistd::setenv;
|
||||
str::as_c_str(n) {|nbuf|
|
||||
str::as_c_str(v) {|vbuf|
|
||||
setenv(nbuf, vbuf, 1i32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
fn setenv(n: str, v: str) {
|
||||
// FIXME: remove imports when export globs work properly.
|
||||
import libc::funcs::extra::kernel32::*;
|
||||
import win32::*;
|
||||
as_utf16_p(n) {|nbuf|
|
||||
as_utf16_p(v) {|vbuf|
|
||||
SetEnvironmentVariableW(nbuf, vbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -121,60 +121,13 @@ mod win32 {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn getenv(n: str) -> option<str> unsafe {
|
||||
let s = as_c_charp(n, libc::getenv);
|
||||
ret if unsafe::reinterpret_cast(s) == 0 {
|
||||
option::none::<str>
|
||||
} else {
|
||||
let s = unsafe::reinterpret_cast(s);
|
||||
option::some::<str>(str::unsafe::from_buf(s))
|
||||
};
|
||||
fn getenv(n: str) -> option<str> {
|
||||
global_env::getenv(n)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
fn getenv(n: str) -> option<str> unsafe {
|
||||
import libc::types::os::arch::extra::*;
|
||||
import libc::funcs::extra::kernel32::*;
|
||||
import win32::*;
|
||||
as_utf16_p(n) {|u|
|
||||
fill_utf16_buf_and_decode() {|buf, sz|
|
||||
GetEnvironmentVariableW(u, buf, sz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn setenv(n: str, v: str) {
|
||||
|
||||
// FIXME: remove this when export globs work properly.
|
||||
import libc::funcs::posix01::unistd::setenv;
|
||||
as_c_charp(n) {|nbuf|
|
||||
as_c_charp(v) {|vbuf|
|
||||
setenv(nbuf, vbuf, 1i32);
|
||||
global_env::setenv(n, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
fn setenv(n: str, v: str) {
|
||||
// FIXME: remove imports when export globs work properly.
|
||||
import libc::funcs::extra::kernel32::*;
|
||||
import win32::*;
|
||||
as_utf16_p(n) {|nbuf|
|
||||
as_utf16_p(v) {|vbuf|
|
||||
SetEnvironmentVariableW(nbuf, vbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn fdopen(fd: c_int) -> *FILE {
|
||||
ret as_c_charp("r") {|modebuf|
|
||||
|
@ -726,7 +679,6 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore(reason = "fails periodically on mac")]
|
||||
fn test_setenv() {
|
||||
let n = make_rand_name();
|
||||
setenv(n, "VALUE");
|
||||
|
@ -734,7 +686,6 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore(reason = "fails periodically on mac")]
|
||||
fn test_setenv_overwrite() {
|
||||
let n = make_rand_name();
|
||||
setenv(n, "1");
|
||||
|
@ -747,7 +698,6 @@ mod tests {
|
|||
// Windows GetEnvironmentVariable requires some extra work to make sure
|
||||
// the buffer the variable is copied into is the right size
|
||||
#[test]
|
||||
#[ignore(reason = "fails periodically on mac")]
|
||||
fn test_getenv_big() {
|
||||
let mut s = "";
|
||||
let mut i = 0;
|
||||
|
|
|
@ -823,21 +823,7 @@ impl tm for tm {
|
|||
mod tests {
|
||||
import task;
|
||||
|
||||
// FIXME #2160: These tests are all run in the same task because
|
||||
// getenv/setenv interacts poorly with threads on OS X
|
||||
#[test]
|
||||
fn test_all() {
|
||||
test_get_time();
|
||||
test_precise_time();
|
||||
test_at_utc();
|
||||
test_at();
|
||||
test_to_timespec();
|
||||
test_conversions();
|
||||
test_strptime();
|
||||
test_ctime();
|
||||
test_strftime();
|
||||
}
|
||||
|
||||
fn test_get_time() {
|
||||
const some_recent_date: i64 = 1325376000i64; // 2012-01-01T00:00:00Z
|
||||
const some_future_date: i64 = 1577836800i64; // 2020-01-01T00:00:00Z
|
||||
|
@ -861,6 +847,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_precise_time() {
|
||||
let s0 = precise_time_s();
|
||||
let ns1 = precise_time_ns();
|
||||
|
@ -878,6 +865,7 @@ mod tests {
|
|||
assert ns2 >= ns1;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_at_utc() {
|
||||
os::setenv("TZ", "America/Los_Angeles");
|
||||
|
||||
|
@ -898,6 +886,7 @@ mod tests {
|
|||
assert utc.tm_nsec == 54321_i32;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_at() {
|
||||
os::setenv("TZ", "America/Los_Angeles");
|
||||
|
||||
|
@ -923,6 +912,7 @@ mod tests {
|
|||
assert local.tm_nsec == 54321_i32;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_timespec() {
|
||||
os::setenv("TZ", "America/Los_Angeles");
|
||||
|
||||
|
@ -933,6 +923,7 @@ mod tests {
|
|||
assert utc.to_local().to_timespec() == time;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conversions() {
|
||||
os::setenv("TZ", "America/Los_Angeles");
|
||||
|
||||
|
@ -948,6 +939,7 @@ mod tests {
|
|||
assert utc.to_local().to_utc() == utc;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strptime() {
|
||||
os::setenv("TZ", "America/Los_Angeles");
|
||||
|
||||
|
@ -1092,6 +1084,7 @@ mod tests {
|
|||
assert test("%", "%%");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ctime() {
|
||||
os::setenv("TZ", "America/Los_Angeles");
|
||||
|
||||
|
@ -1103,6 +1096,7 @@ mod tests {
|
|||
assert local.ctime() == "Fri Feb 13 15:31:30 2009";
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strftime() {
|
||||
os::setenv("TZ", "America/Los_Angeles");
|
||||
|
||||
|
|
|
@ -781,6 +781,12 @@ rust_task_unweaken(rust_port_id chan) {
|
|||
task->kernel->unweaken_task(chan);
|
||||
}
|
||||
|
||||
extern "C" CDECL uintptr_t*
|
||||
rust_global_env_chan_ptr() {
|
||||
rust_task *task = rust_get_current_task();
|
||||
return task->kernel->get_global_env_chan();
|
||||
}
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
// mode: C++
|
||||
|
|
|
@ -22,11 +22,11 @@ rust_kernel::rust_kernel(rust_env *env) :
|
|||
sched_reaper(this),
|
||||
osmain_driver(NULL),
|
||||
non_weak_tasks(0),
|
||||
global_loop_chan(0),
|
||||
global_env_chan(0),
|
||||
env(env)
|
||||
|
||||
{
|
||||
// set up storage of pointers needed to
|
||||
// access the global loop.
|
||||
global_loop_chan = 0;
|
||||
|
||||
// Create the single threaded scheduler that will run on the platform's
|
||||
// main thread
|
||||
|
|
|
@ -75,6 +75,8 @@ class rust_kernel {
|
|||
|
||||
// Used to communicate with the process-side, global libuv loop
|
||||
uintptr_t global_loop_chan;
|
||||
// Used to serialize access to getenv/setenv
|
||||
uintptr_t global_env_chan;
|
||||
|
||||
public:
|
||||
struct rust_env *env;
|
||||
|
@ -122,6 +124,7 @@ public:
|
|||
bool send_to_port(rust_port_id chan, void *sptr);
|
||||
|
||||
uintptr_t* get_global_loop() { return &global_loop_chan; }
|
||||
uintptr_t* get_global_env_chan() { return &global_env_chan; }
|
||||
};
|
||||
|
||||
template <typename T> struct kernel_owned {
|
||||
|
|
|
@ -148,3 +148,4 @@ rust_dbg_lock_signal
|
|||
rust_dbg_call
|
||||
rust_osmain_sched_id
|
||||
rust_compare_and_swap_ptr
|
||||
rust_global_env_chan_ptr
|
||||
|
|
Loading…
Reference in New Issue