Skip to content

Commit 46cc11e

Browse files
committed
core: Serialize all access to the environment using a weak global task
1 parent 3038502 commit 46cc11e

File tree

8 files changed

+150
-71
lines changed

8 files changed

+150
-71
lines changed

src/libcore/core.rc

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ mod extfmt;
199199
mod unicode;
200200
mod priv;
201201
mod cmath;
202+
mod global_env;
202203

203204

204205
// Local Variables:

src/libcore/global_env.rs

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#[doc = "Internal module for serializing access to getenv/setenv"];
2+
3+
export getenv;
4+
export setenv;
5+
6+
native mod rustrt {
7+
fn rust_global_env_chan_ptr() -> *libc::uintptr_t;
8+
}
9+
10+
enum msg {
11+
msg_getenv(str, comm::chan<option<str>>),
12+
msg_setenv(str, str, comm::chan<()>)
13+
}
14+
15+
fn getenv(n: str) -> option<str> {
16+
let env_ch = get_global_env_chan();
17+
let po = comm::port();
18+
comm::send(env_ch, msg_getenv(n, comm::chan(po)));
19+
comm::recv(po)
20+
}
21+
22+
fn setenv(n: str, v: str) {
23+
let env_ch = get_global_env_chan();
24+
let po = comm::port();
25+
comm::send(env_ch, msg_setenv(n, v, comm::chan(po)));
26+
comm::recv(po)
27+
}
28+
29+
fn get_global_env_chan() -> comm::chan<msg> {
30+
let global_ptr = rustrt::rust_global_env_chan_ptr();
31+
let builder_fn = {||
32+
let builder = task::builder();
33+
task::unsupervise(builder);
34+
task::set_opts(builder, {
35+
sched: some({
36+
mode: task::single_threaded,
37+
// FIXME: This would be a good place to use
38+
// a very small native stack
39+
native_stack_size: none
40+
})
41+
with task::get_opts(builder)
42+
});
43+
builder
44+
};
45+
unsafe {
46+
priv::chan_from_global_ptr(
47+
global_ptr, builder_fn, global_env_task)
48+
}
49+
}
50+
51+
fn global_env_task(msg_po: comm::port<msg>) unsafe {
52+
priv::weaken_task {|weak_po|
53+
loop {
54+
alt comm::select2(msg_po, weak_po) {
55+
either::left(msg_getenv(n, resp_ch)) {
56+
comm::send(resp_ch, impl::getenv(n))
57+
}
58+
either::left(msg_setenv(n, v, resp_ch)) {
59+
comm::send(resp_ch, impl::setenv(n, v))
60+
}
61+
either::right(_) {
62+
break;
63+
}
64+
}
65+
}
66+
}
67+
}
68+
69+
mod impl {
70+
71+
#[cfg(target_os = "linux")]
72+
#[cfg(target_os = "macos")]
73+
#[cfg(target_os = "freebsd")]
74+
fn getenv(n: str) -> option<str> unsafe {
75+
let s = str::as_c_str(n, libc::getenv);
76+
ret if unsafe::reinterpret_cast(s) == 0 {
77+
option::none::<str>
78+
} else {
79+
let s = unsafe::reinterpret_cast(s);
80+
option::some::<str>(str::unsafe::from_buf(s))
81+
};
82+
}
83+
84+
#[cfg(target_os = "win32")]
85+
fn getenv(n: str) -> option<str> unsafe {
86+
import libc::types::os::arch::extra::*;
87+
import libc::funcs::extra::kernel32::*;
88+
import win32::*;
89+
as_utf16_p(n) {|u|
90+
fill_utf16_buf_and_decode() {|buf, sz|
91+
GetEnvironmentVariableW(u, buf, sz)
92+
}
93+
}
94+
}
95+
96+
97+
#[cfg(target_os = "linux")]
98+
#[cfg(target_os = "macos")]
99+
#[cfg(target_os = "freebsd")]
100+
fn setenv(n: str, v: str) {
101+
102+
// FIXME: remove this when export globs work properly.
103+
import libc::funcs::posix01::unistd::setenv;
104+
str::as_c_str(n) {|nbuf|
105+
str::as_c_str(v) {|vbuf|
106+
setenv(nbuf, vbuf, 1i32);
107+
}
108+
}
109+
}
110+
111+
112+
#[cfg(target_os = "win32")]
113+
fn setenv(n: str, v: str) {
114+
// FIXME: remove imports when export globs work properly.
115+
import libc::funcs::extra::kernel32::*;
116+
import win32::*;
117+
as_utf16_p(n) {|nbuf|
118+
as_utf16_p(v) {|vbuf|
119+
SetEnvironmentVariableW(nbuf, vbuf);
120+
}
121+
}
122+
}
123+
124+
}

src/libcore/os.rs

+3-53
Original file line numberDiff line numberDiff line change
@@ -121,61 +121,14 @@ mod win32 {
121121
}
122122
}
123123

124-
125-
#[cfg(target_os = "linux")]
126-
#[cfg(target_os = "macos")]
127-
#[cfg(target_os = "freebsd")]
128-
fn getenv(n: str) -> option<str> unsafe {
129-
let s = as_c_charp(n, libc::getenv);
130-
ret if unsafe::reinterpret_cast(s) == 0 {
131-
option::none::<str>
132-
} else {
133-
let s = unsafe::reinterpret_cast(s);
134-
option::some::<str>(str::unsafe::from_buf(s))
135-
};
136-
}
137-
138-
#[cfg(target_os = "win32")]
139-
fn getenv(n: str) -> option<str> unsafe {
140-
import libc::types::os::arch::extra::*;
141-
import libc::funcs::extra::kernel32::*;
142-
import win32::*;
143-
as_utf16_p(n) {|u|
144-
fill_utf16_buf_and_decode() {|buf, sz|
145-
GetEnvironmentVariableW(u, buf, sz)
146-
}
147-
}
148-
}
149-
150-
151-
#[cfg(target_os = "linux")]
152-
#[cfg(target_os = "macos")]
153-
#[cfg(target_os = "freebsd")]
154-
fn setenv(n: str, v: str) {
155-
156-
// FIXME: remove this when export globs work properly.
157-
import libc::funcs::posix01::unistd::setenv;
158-
as_c_charp(n) {|nbuf|
159-
as_c_charp(v) {|vbuf|
160-
setenv(nbuf, vbuf, 1i32);
161-
}
162-
}
124+
fn getenv(n: str) -> option<str> {
125+
global_env::getenv(n)
163126
}
164127

165-
166-
#[cfg(target_os = "win32")]
167128
fn setenv(n: str, v: str) {
168-
// FIXME: remove imports when export globs work properly.
169-
import libc::funcs::extra::kernel32::*;
170-
import win32::*;
171-
as_utf16_p(n) {|nbuf|
172-
as_utf16_p(v) {|vbuf|
173-
SetEnvironmentVariableW(nbuf, vbuf);
174-
}
175-
}
129+
global_env::setenv(n, v)
176130
}
177131

178-
179132
fn fdopen(fd: c_int) -> *FILE {
180133
ret as_c_charp("r") {|modebuf|
181134
libc::fdopen(fd, modebuf)
@@ -726,15 +679,13 @@ mod tests {
726679
}
727680

728681
#[test]
729-
#[ignore(reason = "fails periodically on mac")]
730682
fn test_setenv() {
731683
let n = make_rand_name();
732684
setenv(n, "VALUE");
733685
assert getenv(n) == option::some("VALUE");
734686
}
735687

736688
#[test]
737-
#[ignore(reason = "fails periodically on mac")]
738689
fn test_setenv_overwrite() {
739690
let n = make_rand_name();
740691
setenv(n, "1");
@@ -747,7 +698,6 @@ mod tests {
747698
// Windows GetEnvironmentVariable requires some extra work to make sure
748699
// the buffer the variable is copied into is the right size
749700
#[test]
750-
#[ignore(reason = "fails periodically on mac")]
751701
fn test_getenv_big() {
752702
let mut s = "";
753703
let mut i = 0;

src/libstd/time.rs

+8-14
Original file line numberDiff line numberDiff line change
@@ -823,21 +823,7 @@ impl tm for tm {
823823
mod tests {
824824
import task;
825825

826-
// FIXME #2160: These tests are all run in the same task because
827-
// getenv/setenv interacts poorly with threads on OS X
828826
#[test]
829-
fn test_all() {
830-
test_get_time();
831-
test_precise_time();
832-
test_at_utc();
833-
test_at();
834-
test_to_timespec();
835-
test_conversions();
836-
test_strptime();
837-
test_ctime();
838-
test_strftime();
839-
}
840-
841827
fn test_get_time() {
842828
const some_recent_date: i64 = 1325376000i64; // 2012-01-01T00:00:00Z
843829
const some_future_date: i64 = 1577836800i64; // 2020-01-01T00:00:00Z
@@ -861,6 +847,7 @@ mod tests {
861847
}
862848
}
863849

850+
#[test]
864851
fn test_precise_time() {
865852
let s0 = precise_time_s();
866853
let ns1 = precise_time_ns();
@@ -878,6 +865,7 @@ mod tests {
878865
assert ns2 >= ns1;
879866
}
880867

868+
#[test]
881869
fn test_at_utc() {
882870
os::setenv("TZ", "America/Los_Angeles");
883871

@@ -898,6 +886,7 @@ mod tests {
898886
assert utc.tm_nsec == 54321_i32;
899887
}
900888

889+
#[test]
901890
fn test_at() {
902891
os::setenv("TZ", "America/Los_Angeles");
903892

@@ -923,6 +912,7 @@ mod tests {
923912
assert local.tm_nsec == 54321_i32;
924913
}
925914

915+
#[test]
926916
fn test_to_timespec() {
927917
os::setenv("TZ", "America/Los_Angeles");
928918

@@ -933,6 +923,7 @@ mod tests {
933923
assert utc.to_local().to_timespec() == time;
934924
}
935925

926+
#[test]
936927
fn test_conversions() {
937928
os::setenv("TZ", "America/Los_Angeles");
938929

@@ -948,6 +939,7 @@ mod tests {
948939
assert utc.to_local().to_utc() == utc;
949940
}
950941

942+
#[test]
951943
fn test_strptime() {
952944
os::setenv("TZ", "America/Los_Angeles");
953945

@@ -1092,6 +1084,7 @@ mod tests {
10921084
assert test("%", "%%");
10931085
}
10941086

1087+
#[test]
10951088
fn test_ctime() {
10961089
os::setenv("TZ", "America/Los_Angeles");
10971090

@@ -1103,6 +1096,7 @@ mod tests {
11031096
assert local.ctime() == "Fri Feb 13 15:31:30 2009";
11041097
}
11051098

1099+
#[test]
11061100
fn test_strftime() {
11071101
os::setenv("TZ", "America/Los_Angeles");
11081102

src/rt/rust_builtin.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,12 @@ rust_task_unweaken(rust_port_id chan) {
781781
task->kernel->unweaken_task(chan);
782782
}
783783

784+
extern "C" CDECL uintptr_t*
785+
rust_global_env_chan_ptr() {
786+
rust_task *task = rust_get_current_task();
787+
return task->kernel->get_global_env_chan();
788+
}
789+
784790
//
785791
// Local Variables:
786792
// mode: C++

src/rt/rust_kernel.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ rust_kernel::rust_kernel(rust_env *env) :
2222
sched_reaper(this),
2323
osmain_driver(NULL),
2424
non_weak_tasks(0),
25+
global_loop_chan(0),
26+
global_env_chan(0),
2527
env(env)
28+
2629
{
27-
// set up storage of pointers needed to
28-
// access the global loop.
29-
global_loop_chan = 0;
3030

3131
// Create the single threaded scheduler that will run on the platform's
3232
// main thread

src/rt/rust_kernel.h

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ class rust_kernel {
7575

7676
// Used to communicate with the process-side, global libuv loop
7777
uintptr_t global_loop_chan;
78+
// Used to serialize access to getenv/setenv
79+
uintptr_t global_env_chan;
7880

7981
public:
8082
struct rust_env *env;
@@ -122,6 +124,7 @@ class rust_kernel {
122124
bool send_to_port(rust_port_id chan, void *sptr);
123125

124126
uintptr_t* get_global_loop() { return &global_loop_chan; }
127+
uintptr_t* get_global_env_chan() { return &global_env_chan; }
125128
};
126129

127130
template <typename T> struct kernel_owned {

src/rt/rustrt.def.in

+2-1
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,5 @@ rust_dbg_lock_wait
147147
rust_dbg_lock_signal
148148
rust_dbg_call
149149
rust_osmain_sched_id
150-
rust_compare_and_swap_ptr
150+
rust_compare_and_swap_ptr
151+
rust_global_env_chan_ptr

0 commit comments

Comments
 (0)