Skip to content

Commit fb92993

Browse files
committed
core: Convert getenv/setenv to use a mutex
This much simpler implementation uses a global mutex and eliminates the kernel environment channel.
1 parent 8852279 commit fb92993

File tree

5 files changed

+68
-147
lines changed

5 files changed

+68
-147
lines changed

src/libcore/os.rs

Lines changed: 68 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -139,169 +139,101 @@ pub mod win32 {
139139
}
140140
}
141141

142-
pub fn getenv(n: &str) -> Option<~str> {
143-
global_env::getenv(n)
144-
}
142+
/*
143+
Accessing environment variables is not generally threadsafe.
144+
This uses a per-runtime lock to serialize access.
145+
XXX: It would probably be appropriate to make this a real global
146+
*/
147+
fn with_env_lock<T>(f: &fn() -> T) -> T {
148+
use private::global::global_data_clone_create;
149+
use private::{Exclusive, exclusive};
150+
151+
struct SharedValue(());
152+
type ValueMutex = Exclusive<SharedValue>;
153+
fn key(_: ValueMutex) { }
145154

146-
pub fn setenv(n: &str, v: &str) {
147-
global_env::setenv(n, v)
148-
}
155+
unsafe {
156+
let lock: ValueMutex = global_data_clone_create(key, || {
157+
~exclusive(SharedValue(()))
158+
});
149159

150-
pub fn env() -> ~[(~str,~str)] {
151-
global_env::env()
160+
lock.with_imm(|_| f() )
161+
}
152162
}
153163

154-
mod global_env {
155-
//! Internal module for serializing access to getenv/setenv
156-
use either;
157-
use libc;
158-
use oldcomm;
159-
use option::Option;
160-
use private;
161-
use str;
162-
use task;
163-
164+
pub fn env() -> ~[(~str,~str)] {
164165
extern mod rustrt {
165-
unsafe fn rust_global_env_chan_ptr() -> *libc::uintptr_t;
166-
}
167-
168-
enum Msg {
169-
MsgGetEnv(~str, oldcomm::Chan<Option<~str>>),
170-
MsgSetEnv(~str, ~str, oldcomm::Chan<()>),
171-
MsgEnv(oldcomm::Chan<~[(~str,~str)]>)
172-
}
173-
174-
pub fn getenv(n: &str) -> Option<~str> {
175-
let env_ch = get_global_env_chan();
176-
let po = oldcomm::Port();
177-
oldcomm::send(env_ch, MsgGetEnv(str::from_slice(n),
178-
oldcomm::Chan(&po)));
179-
oldcomm::recv(po)
180-
}
181-
182-
pub fn setenv(n: &str, v: &str) {
183-
let env_ch = get_global_env_chan();
184-
let po = oldcomm::Port();
185-
oldcomm::send(env_ch, MsgSetEnv(str::from_slice(n),
186-
str::from_slice(v),
187-
oldcomm::Chan(&po)));
188-
oldcomm::recv(po)
166+
unsafe fn rust_env_pairs() -> ~[~str];
189167
}
190168

191-
pub fn env() -> ~[(~str,~str)] {
192-
let env_ch = get_global_env_chan();
193-
let po = oldcomm::Port();
194-
oldcomm::send(env_ch, MsgEnv(oldcomm::Chan(&po)));
195-
oldcomm::recv(po)
196-
}
197-
198-
fn get_global_env_chan() -> oldcomm::Chan<Msg> {
199-
unsafe {
200-
let global_ptr = rustrt::rust_global_env_chan_ptr();
201-
private::chan_from_global_ptr(global_ptr, || {
202-
// FIXME (#2621): This would be a good place to use a very
203-
// small foreign stack
204-
task::task().sched_mode(task::SingleThreaded).unlinked()
205-
}, global_env_task)
206-
}
207-
}
208-
209-
fn global_env_task(msg_po: oldcomm::Port<Msg>) {
210-
unsafe {
211-
do private::weaken_task |weak_po| {
212-
loop {
213-
match oldcomm::select2(msg_po, weak_po) {
214-
either::Left(MsgGetEnv(ref n, resp_ch)) => {
215-
oldcomm::send(resp_ch, impl_::getenv(*n))
216-
}
217-
either::Left(MsgSetEnv(ref n, ref v, resp_ch)) => {
218-
oldcomm::send(resp_ch, impl_::setenv(*n, *v))
219-
}
220-
either::Left(MsgEnv(resp_ch)) => {
221-
oldcomm::send(resp_ch, impl_::env())
222-
}
223-
either::Right(_) => break
224-
}
225-
}
169+
unsafe {
170+
do with_env_lock {
171+
let mut pairs = ~[];
172+
for vec::each(rustrt::rust_env_pairs()) |p| {
173+
let vs = str::splitn_char(*p, '=', 1u);
174+
assert vec::len(vs) == 2u;
175+
pairs.push((copy vs[0], copy vs[1]));
226176
}
177+
move pairs
227178
}
228179
}
180+
}
229181

230-
mod impl_ {
231-
use cast;
232-
use libc;
233-
use option::Option;
234-
use option;
235-
use ptr;
236-
use str;
237-
use vec;
238-
239-
extern mod rustrt {
240-
unsafe fn rust_env_pairs() -> ~[~str];
241-
}
242-
243-
pub fn env() -> ~[(~str,~str)] {
244-
unsafe {
245-
let mut pairs = ~[];
246-
for vec::each(rustrt::rust_env_pairs()) |p| {
247-
let vs = str::splitn_char(*p, '=', 1u);
248-
assert vec::len(vs) == 2u;
249-
pairs.push((copy vs[0], copy vs[1]));
250-
}
251-
move pairs
252-
}
253-
}
254-
255-
#[cfg(unix)]
256-
pub fn getenv(n: &str) -> Option<~str> {
257-
unsafe {
258-
let s = str::as_c_str(n, |s| libc::getenv(s));
259-
return if ptr::null::<u8>() == cast::reinterpret_cast(&s) {
260-
option::None::<~str>
261-
} else {
262-
let s = cast::reinterpret_cast(&s);
263-
option::Some::<~str>(str::raw::from_buf(s))
264-
};
182+
#[cfg(unix)]
183+
pub fn getenv(n: &str) -> Option<~str> {
184+
unsafe {
185+
do with_env_lock {
186+
let s = str::as_c_str(n, |s| libc::getenv(s));
187+
if ptr::null::<u8>() == cast::reinterpret_cast(&s) {
188+
option::None::<~str>
189+
} else {
190+
let s = cast::reinterpret_cast(&s);
191+
option::Some::<~str>(str::raw::from_buf(s))
265192
}
266193
}
194+
}
195+
}
267196

268-
#[cfg(windows)]
269-
pub fn getenv(n: &str) -> Option<~str> {
270-
unsafe {
271-
use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
272-
do as_utf16_p(n) |u| {
273-
do fill_utf16_buf_and_decode() |buf, sz| {
274-
libc::GetEnvironmentVariableW(u, buf, sz)
275-
}
197+
#[cfg(windows)]
198+
pub fn getenv(n: &str) -> Option<~str> {
199+
unsafe {
200+
do with_env_lock {
201+
use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
202+
do as_utf16_p(n) |u| {
203+
do fill_utf16_buf_and_decode() |buf, sz| {
204+
libc::GetEnvironmentVariableW(u, buf, sz)
276205
}
277206
}
278207
}
208+
}
209+
}
279210

280211

281-
#[cfg(unix)]
282-
pub fn setenv(n: &str, v: &str) {
283-
unsafe {
284-
do str::as_c_str(n) |nbuf| {
285-
do str::as_c_str(v) |vbuf| {
286-
libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
287-
}
212+
#[cfg(unix)]
213+
pub fn setenv(n: &str, v: &str) {
214+
unsafe {
215+
do with_env_lock {
216+
do str::as_c_str(n) |nbuf| {
217+
do str::as_c_str(v) |vbuf| {
218+
libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
288219
}
289220
}
290221
}
222+
}
223+
}
291224

292225

293-
#[cfg(windows)]
294-
pub fn setenv(n: &str, v: &str) {
295-
unsafe {
296-
use os::win32::as_utf16_p;
297-
do as_utf16_p(n) |nbuf| {
298-
do as_utf16_p(v) |vbuf| {
299-
libc::SetEnvironmentVariableW(nbuf, vbuf);
300-
}
226+
#[cfg(windows)]
227+
pub fn setenv(n: &str, v: &str) {
228+
unsafe {
229+
do with_env_lock {
230+
use os::win32::as_utf16_p;
231+
do as_utf16_p(n) |nbuf| {
232+
do as_utf16_p(v) |vbuf| {
233+
libc::SetEnvironmentVariableW(nbuf, vbuf);
301234
}
302235
}
303236
}
304-
305237
}
306238
}
307239

src/rt/rust_builtin.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -870,12 +870,6 @@ rust_task_unweaken(rust_port_id chan) {
870870
task->kernel->unweaken_task(chan);
871871
}
872872

873-
extern "C" CDECL uintptr_t*
874-
rust_global_env_chan_ptr() {
875-
rust_task *task = rust_get_current_task();
876-
return task->kernel->get_global_env_chan();
877-
}
878-
879873
extern "C" void
880874
rust_task_inhibit_kill(rust_task *task) {
881875
task->inhibit_kill();

src/rt/rust_kernel.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ rust_kernel::rust_kernel(rust_env *env) :
3535
osmain_driver(NULL),
3636
non_weak_tasks(0),
3737
global_loop_chan(0),
38-
global_env_chan(0),
3938
at_exit_runner(NULL),
4039
at_exit_started(false),
4140
env(env),

src/rt/rust_kernel.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,6 @@ class rust_kernel {
131131

132132
// Used to communicate with the process-side, global libuv loop
133133
uintptr_t global_loop_chan;
134-
// Used to serialize access to getenv/setenv
135-
uintptr_t global_env_chan;
136134

137135
lock_and_signal at_exit_lock;
138136
spawn_fn at_exit_runner;
@@ -193,7 +191,6 @@ class rust_kernel {
193191
bool send_to_port(rust_port_id chan, void *sptr);
194192

195193
uintptr_t* get_global_loop() { return &global_loop_chan; }
196-
uintptr_t* get_global_env_chan() { return &global_env_chan; }
197194

198195
void register_exit_function(spawn_fn runner, fn_env_pair *f);
199196
};

src/rt/rustrt.def.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ rust_dbg_do_nothing
174174
rust_dbg_breakpoint
175175
rust_osmain_sched_id
176176
rust_compare_and_swap_ptr
177-
rust_global_env_chan_ptr
178177
rust_port_take
179178
rust_port_drop
180179
rust_port_task

0 commit comments

Comments
 (0)