std: Re-enable at_exit()
The new semantics of this function are that the callbacks are run when the *main thread* exits, not when all threads have exited. This implies that other threads may still be running when the `at_exit` callbacks are invoked and users need to be prepared for this situation. Users in the standard library have been audited in accordance to these new rules as well. Closes #20012
This commit is contained in:
parent
d2368c3c11
commit
9e224c2bf1
39 changed files with 193 additions and 248 deletions
|
|
@ -20,6 +20,8 @@
|
|||
//! can be created in the future and there must be no active timers at that
|
||||
//! time.
|
||||
|
||||
#![macro_escape]
|
||||
|
||||
use prelude::*;
|
||||
|
||||
use cell::UnsafeCell;
|
||||
|
|
@ -68,6 +70,17 @@ struct RaceBox(helper_signal::signal);
|
|||
unsafe impl Send for RaceBox {}
|
||||
unsafe impl Sync for RaceBox {}
|
||||
|
||||
macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
|
||||
static $name: Helper<$m> = Helper {
|
||||
lock: ::sync::MUTEX_INIT,
|
||||
cond: ::sync::CONDVAR_INIT,
|
||||
chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
|
||||
signal: ::cell::UnsafeCell { value: 0 },
|
||||
initialized: ::cell::UnsafeCell { value: false },
|
||||
shutdown: ::cell::UnsafeCell { value: false },
|
||||
};
|
||||
) }
|
||||
|
||||
impl<M: Send> Helper<M> {
|
||||
/// Lazily boots a helper thread, becoming a no-op if the helper has already
|
||||
/// been spawned.
|
||||
|
|
@ -84,7 +97,7 @@ impl<M: Send> Helper<M> {
|
|||
{
|
||||
unsafe {
|
||||
let _guard = self.lock.lock().unwrap();
|
||||
if !*self.initialized.get() {
|
||||
if *self.chan.get() as uint == 0 {
|
||||
let (tx, rx) = channel();
|
||||
*self.chan.get() = mem::transmute(box tx);
|
||||
let (receive, send) = helper_signal::new();
|
||||
|
|
@ -93,15 +106,17 @@ impl<M: Send> Helper<M> {
|
|||
let receive = RaceBox(receive);
|
||||
|
||||
let t = f();
|
||||
Thread::spawn(move |:| {
|
||||
Thread::spawn(move || {
|
||||
helper(receive.0, rx, t);
|
||||
let _g = self.lock.lock().unwrap();
|
||||
*self.shutdown.get() = true;
|
||||
self.cond.notify_one()
|
||||
}).detach();
|
||||
|
||||
rt::at_exit(move|:| { self.shutdown() });
|
||||
rt::at_exit(move || { self.shutdown() });
|
||||
*self.initialized.get() = true;
|
||||
} else if *self.chan.get() as uint == 1 {
|
||||
panic!("cannot continue usage after shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -116,7 +131,9 @@ impl<M: Send> Helper<M> {
|
|||
// Must send and *then* signal to ensure that the child receives the
|
||||
// message. Otherwise it could wake up and go to sleep before we
|
||||
// send the message.
|
||||
assert!(!self.chan.get().is_null());
|
||||
assert!(*self.chan.get() as uint != 0);
|
||||
assert!(*self.chan.get() as uint != 1,
|
||||
"cannot continue usage after shutdown");
|
||||
(**self.chan.get()).send(msg);
|
||||
helper_signal::signal(*self.signal.get() as helper_signal::signal);
|
||||
}
|
||||
|
|
@ -129,9 +146,13 @@ impl<M: Send> Helper<M> {
|
|||
// returns.
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
|
||||
let ptr = *self.chan.get();
|
||||
if ptr as uint == 1 {
|
||||
panic!("cannot continue usage after shutdown");
|
||||
}
|
||||
// Close the channel by destroying it
|
||||
let chan: Box<Sender<M>> = mem::transmute(*self.chan.get());
|
||||
*self.chan.get() = 0 as *mut Sender<M>;
|
||||
*self.chan.get() = 1 as *mut Sender<M>;
|
||||
drop(chan);
|
||||
helper_signal::signal(*self.signal.get() as helper_signal::signal);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
#![macro_escape]
|
||||
|
||||
use io::{mod, IoError, IoResult};
|
||||
use prelude::*;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ impl Mutex {
|
|||
/// Behavior is undefined if the mutex is moved after the first method is
|
||||
/// called on the mutex.
|
||||
#[inline]
|
||||
#[allow(dead_code)] // sys is not exported yet
|
||||
pub unsafe fn new() -> Mutex { Mutex(imp::Mutex::new()) }
|
||||
|
||||
/// Lock the mutex blocking the current thread until it is available.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ use io::{IoResult, IoError};
|
|||
use sys::{mod, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock,
|
||||
wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval,
|
||||
decode_error_detailed};
|
||||
use sync::{Mutex, MutexGuard};
|
||||
use sync::Mutex;
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
use sync::MutexGuard;
|
||||
use sys_common::{mod, keep_going, short_write, timeout};
|
||||
use prelude::*;
|
||||
use cmp;
|
||||
|
|
@ -573,11 +575,13 @@ impl Drop for Inner {
|
|||
fn drop(&mut self) { unsafe { close_sock(self.fd); } }
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub struct Guard<'a> {
|
||||
pub fd: sock_t,
|
||||
pub guard: MutexGuard<'a, ()>,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[unsafe_destructor]
|
||||
impl<'a> Drop for Guard<'a> {
|
||||
fn drop(&mut self) {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ impl RWLock {
|
|||
/// Usage of an RWLock is undefined if it is moved after its first use (any
|
||||
/// function calls below).
|
||||
#[inline]
|
||||
#[allow(dead_code)] // sys is not exported yet
|
||||
pub unsafe fn new() -> RWLock { RWLock(imp::RWLock::new()) }
|
||||
|
||||
/// Acquire shared access to the underlying lock, blocking the current
|
||||
|
|
|
|||
|
|
@ -121,37 +121,6 @@ pub unsafe fn record_os_managed_stack_bounds(stack_lo: uint, _stack_hi: uint) {
|
|||
record_sp_limit(stack_lo + RED_ZONE);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn record_rust_managed_stack_bounds(stack_lo: uint, stack_hi: uint) {
|
||||
// When the old runtime had segmented stacks, it used a calculation that was
|
||||
// "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic
|
||||
// symbol resolution, llvm function calls, etc. In theory this red zone
|
||||
// value is 0, but it matters far less when we have gigantic stacks because
|
||||
// we don't need to be so exact about our stack budget. The "fudge factor"
|
||||
// was because LLVM doesn't emit a stack check for functions < 256 bytes in
|
||||
// size. Again though, we have giant stacks, so we round all these
|
||||
// calculations up to the nice round number of 20k.
|
||||
record_sp_limit(stack_lo + RED_ZONE);
|
||||
|
||||
return target_record_stack_bounds(stack_lo, stack_hi);
|
||||
|
||||
#[cfg(not(windows))] #[inline(always)]
|
||||
unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {}
|
||||
|
||||
#[cfg(all(windows, target_arch = "x86"))] #[inline(always)]
|
||||
unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) {
|
||||
// stack range is at TIB: %fs:0x04 (top) and %fs:0x08 (bottom)
|
||||
asm!("mov $0, %fs:0x04" :: "r"(stack_hi) :: "volatile");
|
||||
asm!("mov $0, %fs:0x08" :: "r"(stack_lo) :: "volatile");
|
||||
}
|
||||
#[cfg(all(windows, target_arch = "x86_64"))] #[inline(always)]
|
||||
unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) {
|
||||
// stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
|
||||
asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile");
|
||||
asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile");
|
||||
}
|
||||
}
|
||||
|
||||
/// Records the current limit of the stack as specified by `end`.
|
||||
///
|
||||
/// This is stored in an OS-dependent location, likely inside of the thread
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use thread::Thread;
|
||||
|
|
@ -15,10 +17,6 @@ use cell::RefCell;
|
|||
use string::String;
|
||||
|
||||
struct ThreadInfo {
|
||||
// This field holds the known bounds of the stack in (lo, hi)
|
||||
// form. Not all threads necessarily know their precise bounds,
|
||||
// hence this is optional.
|
||||
stack_bounds: (uint, uint),
|
||||
stack_guard: uint,
|
||||
thread: Thread,
|
||||
}
|
||||
|
|
@ -35,7 +33,6 @@ impl ThreadInfo {
|
|||
THREAD_INFO.with(|c| {
|
||||
if c.borrow().is_none() {
|
||||
*c.borrow_mut() = Some(ThreadInfo {
|
||||
stack_bounds: (0, 0),
|
||||
stack_guard: 0,
|
||||
thread: NewThread::new(None),
|
||||
})
|
||||
|
|
@ -53,10 +50,9 @@ pub fn stack_guard() -> uint {
|
|||
ThreadInfo::with(|info| info.stack_guard)
|
||||
}
|
||||
|
||||
pub fn set(stack_bounds: (uint, uint), stack_guard: uint, thread: Thread) {
|
||||
pub fn set(stack_guard: uint, thread: Thread) {
|
||||
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
|
||||
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
|
||||
stack_bounds: stack_bounds,
|
||||
stack_guard: stack_guard,
|
||||
thread: thread,
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -55,11 +55,11 @@
|
|||
//! ```
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(dead_code)] // sys isn't exported yet
|
||||
|
||||
use prelude::*;
|
||||
|
||||
use sync::atomic::{mod, AtomicUint};
|
||||
use sync::{Mutex, Once, ONCE_INIT};
|
||||
|
||||
use sys::thread_local as imp;
|
||||
|
||||
|
|
@ -140,9 +140,6 @@ pub const INIT_INNER: StaticKeyInner = StaticKeyInner {
|
|||
key: atomic::INIT_ATOMIC_UINT,
|
||||
};
|
||||
|
||||
static INIT_KEYS: Once = ONCE_INIT;
|
||||
static mut KEYS: *mut Mutex<Vec<imp::Key>> = 0 as *mut _;
|
||||
|
||||
impl StaticKey {
|
||||
/// Gets the value associated with this TLS key
|
||||
///
|
||||
|
|
|
|||
|
|
@ -83,12 +83,12 @@
|
|||
/// to symbols. This is a bit of a hokey implementation as-is, but it works for
|
||||
/// all unix platforms we support right now, so it at least gets the job done.
|
||||
|
||||
use prelude::*;
|
||||
|
||||
use c_str::CString;
|
||||
use io::{IoResult, Writer};
|
||||
use io::IoResult;
|
||||
use libc;
|
||||
use mem;
|
||||
use option::Option::{mod, Some, None};
|
||||
use result::Result::{Ok, Err};
|
||||
use sync::{StaticMutex, MUTEX_INIT};
|
||||
|
||||
use sys_common::backtrace::*;
|
||||
|
|
@ -151,7 +151,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
|
|||
// I/O done here is blocking I/O, not green I/O, so we don't have to
|
||||
// worry about this being a native vs green mutex.
|
||||
static LOCK: StaticMutex = MUTEX_INIT;
|
||||
let _g = unsafe { LOCK.lock() };
|
||||
let _g = LOCK.lock();
|
||||
|
||||
try!(writeln!(w, "stack backtrace:"));
|
||||
|
||||
|
|
@ -241,12 +241,8 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
|
|||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||
fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
|
||||
use iter::{Iterator, IteratorExt};
|
||||
use os;
|
||||
use path::GenericPath;
|
||||
use ptr::PtrExt;
|
||||
use ptr;
|
||||
use slice::SliceExt;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// libbacktrace.h API
|
||||
|
|
|
|||
|
|
@ -10,30 +10,14 @@
|
|||
|
||||
#![allow(missing_docs)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_unsafe)]
|
||||
#![allow(unused_mut)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use num;
|
||||
use num::{Int, SignedInt};
|
||||
use prelude::*;
|
||||
use io::{mod, IoResult, IoError};
|
||||
use sys_common::mkerr_libc;
|
||||
|
||||
macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
|
||||
static $name: Helper<$m> = Helper {
|
||||
lock: ::sync::MUTEX_INIT,
|
||||
cond: ::sync::CONDVAR_INIT,
|
||||
chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
|
||||
signal: ::cell::UnsafeCell { value: 0 },
|
||||
initialized: ::cell::UnsafeCell { value: false },
|
||||
shutdown: ::cell::UnsafeCell { value: false },
|
||||
};
|
||||
) }
|
||||
|
||||
pub mod backtrace;
|
||||
pub mod c;
|
||||
pub mod ext;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
use cell::UnsafeCell;
|
||||
use kinds::Sync;
|
||||
use sys::sync as ffi;
|
||||
use sys_common::mutex;
|
||||
|
||||
pub struct Mutex { inner: UnsafeCell<ffi::pthread_mutex_t> }
|
||||
|
||||
|
|
@ -26,6 +25,7 @@ pub const MUTEX_INIT: Mutex = Mutex {
|
|||
|
||||
unsafe impl Sync for Mutex {}
|
||||
|
||||
#[allow(dead_code)] // sys isn't exported yet
|
||||
impl Mutex {
|
||||
#[inline]
|
||||
pub unsafe fn new() -> Mutex {
|
||||
|
|
|
|||
|
|
@ -10,17 +10,16 @@
|
|||
|
||||
//! Implementation of `std::os` functionality for unix systems
|
||||
|
||||
#![allow(unused_imports)] // lots of cfg code here
|
||||
|
||||
use prelude::*;
|
||||
|
||||
use error::{FromError, Error};
|
||||
use fmt;
|
||||
use io::{IoError, IoResult};
|
||||
use libc::{mod, c_int, c_char, c_void};
|
||||
use libc::{mod, c_int, c_char};
|
||||
use os;
|
||||
use path::BytesContainer;
|
||||
use ptr;
|
||||
use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
|
||||
use sys::fs::FileDesc;
|
||||
use os;
|
||||
|
||||
use os::TMPBUF_SZ;
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ impl UnixStream {
|
|||
fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
|
||||
let ret = Guard {
|
||||
fd: self.fd(),
|
||||
guard: unsafe { self.inner.lock.lock().unwrap() },
|
||||
guard: self.inner.lock.lock().unwrap(),
|
||||
};
|
||||
assert!(set_nonblocking(self.fd(), true).is_ok());
|
||||
ret
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use self::Req::*;
|
|||
|
||||
use libc::{mod, pid_t, c_void, c_int};
|
||||
use c_str::CString;
|
||||
use io::{mod, IoResult, IoError, EndOfFile};
|
||||
use io::{IoResult, EndOfFile};
|
||||
use mem;
|
||||
use os;
|
||||
use ptr;
|
||||
|
|
@ -327,7 +327,7 @@ impl Process {
|
|||
// The actual communication between the helper thread and this thread is
|
||||
// quite simple, just a channel moving data around.
|
||||
|
||||
unsafe { HELPER.boot(register_sigchld, waitpid_helper) }
|
||||
HELPER.boot(register_sigchld, waitpid_helper);
|
||||
|
||||
match self.try_wait() {
|
||||
Some(ret) => return Ok(ret),
|
||||
|
|
@ -335,7 +335,7 @@ impl Process {
|
|||
}
|
||||
|
||||
let (tx, rx) = channel();
|
||||
unsafe { HELPER.send(NewChild(self.pid, tx, deadline)); }
|
||||
HELPER.send(NewChild(self.pid, tx, deadline));
|
||||
return match rx.recv_opt() {
|
||||
Ok(e) => Ok(e),
|
||||
Err(()) => Err(timeout("wait timed out")),
|
||||
|
|
@ -419,8 +419,15 @@ impl Process {
|
|||
Ok(NewChild(pid, tx, deadline)) => {
|
||||
active.push((pid, tx, deadline));
|
||||
}
|
||||
// Once we've been disconnected it means the main
|
||||
// thread is exiting (at_exit has run). We could
|
||||
// still have active waiter for other threads, so
|
||||
// we're just going to drop them all on the floor.
|
||||
// This means that they won't receive a "you're
|
||||
// done" message in which case they'll be considered
|
||||
// as timed out, but more generally errors will
|
||||
// start propagating.
|
||||
Err(comm::Disconnected) => {
|
||||
assert!(active.len() == 0);
|
||||
break 'outer;
|
||||
}
|
||||
Err(comm::Empty) => break,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ pub const RWLOCK_INIT: RWLock = RWLock {
|
|||
inner: UnsafeCell { value: ffi::PTHREAD_RWLOCK_INITIALIZER },
|
||||
};
|
||||
|
||||
#[allow(dead_code)] // sys isn't exported yet
|
||||
impl RWLock {
|
||||
#[inline]
|
||||
pub unsafe fn new() -> RWLock {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ impl Drop for Handler {
|
|||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
mod imp {
|
||||
use core::prelude::*;
|
||||
use sys_common::stack;
|
||||
|
||||
use super::Handler;
|
||||
|
|
|
|||
|
|
@ -135,10 +135,6 @@ impl TcpAcceptor {
|
|||
Err(sys_common::eof())
|
||||
}
|
||||
|
||||
pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
|
||||
net::sockname(self.fd(), libc::getsockname)
|
||||
}
|
||||
|
||||
pub fn set_timeout(&mut self, timeout: Option<u64>) {
|
||||
self.deadline = timeout.map(|a| sys::timer::now() + a).unwrap_or(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ pub fn now() -> u64 {
|
|||
fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
|
||||
let mut set: c::fd_set = unsafe { mem::zeroed() };
|
||||
|
||||
let mut fd = FileDesc::new(input, true);
|
||||
let fd = FileDesc::new(input, true);
|
||||
let mut timeout: libc::timeval = unsafe { mem::zeroed() };
|
||||
|
||||
// active timers are those which are able to be selected upon (and it's a
|
||||
|
|
@ -168,8 +168,15 @@ fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
|
|||
1 => {
|
||||
loop {
|
||||
match messages.try_recv() {
|
||||
// Once we've been disconnected it means the main thread
|
||||
// is exiting (at_exit has run). We could still have
|
||||
// active timers for other threads, so we're just going
|
||||
// to drop them all on the floor. This is all we can
|
||||
// really do, however, to prevent resource leakage. The
|
||||
// remaining timers will likely start panicking quickly
|
||||
// as they attempt to re-use this thread but are
|
||||
// disallowed to do so.
|
||||
Err(comm::Disconnected) => {
|
||||
assert!(active.len() == 0);
|
||||
break 'outer;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,5 +43,4 @@ impl TTY {
|
|||
pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
|
||||
Err(sys_common::unimpl())
|
||||
}
|
||||
pub fn isatty(&self) -> bool { false }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,19 +7,22 @@
|
|||
// <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.
|
||||
/// As always, windows has something very different than unix, we mainly want
|
||||
/// to avoid having to depend too much on libunwind for windows.
|
||||
///
|
||||
/// If you google around, you'll find a fair bit of references to built-in
|
||||
/// functions to get backtraces on windows. It turns out that most of these are
|
||||
/// in an external library called dbghelp. I was unable to find this library
|
||||
/// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
|
||||
/// of it.
|
||||
///
|
||||
/// You'll also find that there's a function called CaptureStackBackTrace
|
||||
/// mentioned frequently (which is also easy to use), but sadly I didn't have a
|
||||
/// copy of that function in my mingw install (maybe it was broken?). Instead,
|
||||
/// this takes the route of using StackWalk64 in order to walk the stack.
|
||||
|
||||
//! As always, windows has something very different than unix, we mainly want
|
||||
//! to avoid having to depend too much on libunwind for windows.
|
||||
//!
|
||||
//! If you google around, you'll find a fair bit of references to built-in
|
||||
//! functions to get backtraces on windows. It turns out that most of these are
|
||||
//! in an external library called dbghelp. I was unable to find this library
|
||||
//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
|
||||
//! of it.
|
||||
//!
|
||||
//! You'll also find that there's a function called CaptureStackBackTrace
|
||||
//! mentioned frequently (which is also easy to use), but sadly I didn't have a
|
||||
//! copy of that function in my mingw install (maybe it was broken?). Instead,
|
||||
//! this takes the route of using StackWalk64 in order to walk the stack.
|
||||
|
||||
#![allow(dead_code)] // constants/fields aren't always used on all platforms
|
||||
|
||||
use c_str::CString;
|
||||
use intrinsics;
|
||||
|
|
@ -294,7 +297,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> {
|
|||
// According to windows documentation, all dbghelp functions are
|
||||
// single-threaded.
|
||||
static LOCK: StaticMutex = MUTEX_INIT;
|
||||
let _g = unsafe { LOCK.lock() };
|
||||
let _g = LOCK.lock();
|
||||
|
||||
// Open up dbghelp.dll, we don't link to it explicitly because it can't
|
||||
// always be found. Additionally, it's nice having fewer dependencies.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
|
||||
use libc;
|
||||
use prelude::*;
|
||||
|
||||
pub const WSADESCRIPTION_LEN: uint = 256;
|
||||
pub const WSASYS_STATUS_LEN: uint = 128;
|
||||
|
|
|
|||
|
|
@ -10,21 +10,17 @@
|
|||
|
||||
//! Blocking Windows-based file I/O
|
||||
|
||||
use alloc::arc::Arc;
|
||||
use libc::{mod, c_int};
|
||||
|
||||
use c_str::CString;
|
||||
use mem;
|
||||
use sys::os::fill_utf16_buf_and_decode;
|
||||
use path;
|
||||
use ptr;
|
||||
use str;
|
||||
use io;
|
||||
use mem;
|
||||
use ptr;
|
||||
use sys::os::fill_utf16_buf_and_decode;
|
||||
|
||||
use prelude::*;
|
||||
use sys;
|
||||
use sys::os;
|
||||
use sys_common::{keep_going, eof, mkerr_libc};
|
||||
use sys_common::{unimpl, mkerr_libc};
|
||||
|
||||
use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
|
||||
use io::{IoResult, IoError, FileStat, SeekStyle};
|
||||
|
|
@ -445,7 +441,7 @@ pub fn stat(p: &Path) -> IoResult<FileStat> {
|
|||
// FIXME: move this to platform-specific modules (for now)?
|
||||
pub fn lstat(_p: &Path) -> IoResult<FileStat> {
|
||||
// FIXME: implementation is missing
|
||||
Err(super::unimpl())
|
||||
Err(unimpl())
|
||||
}
|
||||
|
||||
pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
|
||||
|
|
|
|||
|
|
@ -11,30 +11,14 @@
|
|||
#![allow(missing_docs)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_unsafe)]
|
||||
#![allow(unused_mut)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use num;
|
||||
use mem;
|
||||
use prelude::*;
|
||||
use io::{mod, IoResult, IoError};
|
||||
use sync::{Once, ONCE_INIT};
|
||||
|
||||
macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
|
||||
static $name: Helper<$m> = Helper {
|
||||
lock: ::sync::MUTEX_INIT,
|
||||
cond: ::sync::CONDVAR_INIT,
|
||||
chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
|
||||
signal: ::cell::UnsafeCell { value: 0 },
|
||||
initialized: ::cell::UnsafeCell { value: false },
|
||||
shutdown: ::cell::UnsafeCell { value: false },
|
||||
};
|
||||
) }
|
||||
|
||||
pub mod backtrace;
|
||||
pub mod c;
|
||||
pub mod ext;
|
||||
|
|
@ -179,14 +163,6 @@ pub fn init_net() {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn unimpl() -> IoError {
|
||||
IoError {
|
||||
kind: io::IoUnavailable,
|
||||
desc: "operation is not implemented",
|
||||
detail: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> {
|
||||
match s {
|
||||
Some(s) => Ok({
|
||||
|
|
|
|||
|
|
@ -15,14 +15,12 @@
|
|||
|
||||
use prelude::*;
|
||||
|
||||
use fmt;
|
||||
use io::{IoResult, IoError};
|
||||
use libc::{c_int, c_char, c_void};
|
||||
use libc::{c_int, c_void};
|
||||
use libc;
|
||||
use os;
|
||||
use path::BytesContainer;
|
||||
use ptr;
|
||||
use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
|
||||
use sys::fs::FileDesc;
|
||||
use slice;
|
||||
|
||||
|
|
|
|||
|
|
@ -365,7 +365,7 @@ impl UnixStream {
|
|||
// acquire the lock.
|
||||
//
|
||||
// See comments in close_read() about why this lock is necessary.
|
||||
let guard = unsafe { self.inner.lock.lock() };
|
||||
let guard = self.inner.lock.lock();
|
||||
if self.read_closed() {
|
||||
return Err(eof())
|
||||
}
|
||||
|
|
@ -441,7 +441,7 @@ impl UnixStream {
|
|||
// going after we woke up.
|
||||
//
|
||||
// See comments in close_read() about why this lock is necessary.
|
||||
let guard = unsafe { self.inner.lock.lock() };
|
||||
let guard = self.inner.lock.lock();
|
||||
if self.write_closed() {
|
||||
return Err(epipe())
|
||||
}
|
||||
|
|
@ -516,14 +516,14 @@ impl UnixStream {
|
|||
// close_read() between steps 1 and 2. By atomically executing steps 1
|
||||
// and 2 with a lock with respect to close_read(), we're guaranteed that
|
||||
// no thread will erroneously sit in a read forever.
|
||||
let _guard = unsafe { self.inner.lock.lock() };
|
||||
let _guard = self.inner.lock.lock();
|
||||
self.inner.read_closed.store(true, atomic::SeqCst);
|
||||
self.cancel_io()
|
||||
}
|
||||
|
||||
pub fn close_write(&mut self) -> IoResult<()> {
|
||||
// see comments in close_read() for why this lock is necessary
|
||||
let _guard = unsafe { self.inner.lock.lock() };
|
||||
let _guard = self.inner.lock.lock();
|
||||
self.inner.write_closed.store(true, atomic::SeqCst);
|
||||
self.cancel_io()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,25 +8,24 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use libc::{pid_t, c_void, c_int};
|
||||
use prelude::*;
|
||||
|
||||
use libc::{pid_t, c_void};
|
||||
use libc;
|
||||
use c_str::CString;
|
||||
use io;
|
||||
use mem;
|
||||
use os;
|
||||
use ptr;
|
||||
use prelude::*;
|
||||
use io::process::{ProcessExit, ExitStatus, ExitSignal};
|
||||
use io::process::{ProcessExit, ExitStatus};
|
||||
use collections;
|
||||
use path::BytesContainer;
|
||||
use hash::Hash;
|
||||
use io::{IoResult, IoError};
|
||||
|
||||
use sys::fs;
|
||||
use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer};
|
||||
use sys::timer;
|
||||
use sys::fs::FileDesc;
|
||||
use sys_common::helper_thread::Helper;
|
||||
use sys_common::{AsInner, mkerr_libc, timeout};
|
||||
use sys_common::{AsInner, timeout};
|
||||
|
||||
use io::fs::PathExtensions;
|
||||
|
||||
|
|
@ -121,8 +120,6 @@ impl Process {
|
|||
use libc::funcs::extra::msvcrt::get_osfhandle;
|
||||
|
||||
use mem;
|
||||
use iter::{Iterator, IteratorExt};
|
||||
use str::StrExt;
|
||||
|
||||
if cfg.gid().is_some() || cfg.uid().is_some() {
|
||||
return Err(IoError {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use ptr;
|
|||
use mem;
|
||||
use libc;
|
||||
use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL};
|
||||
use sys_common::{stack, thread_info};
|
||||
use sys_common::stack;
|
||||
|
||||
pub struct Handler {
|
||||
_data: *mut libc::c_void
|
||||
|
|
@ -30,14 +30,6 @@ impl Drop for Handler {
|
|||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
// get_task_info is called from an exception / signal handler.
|
||||
// It returns the guard page of the current task or 0 if that
|
||||
// guard page doesn't exist. None is returned if there's currently
|
||||
// no local task.
|
||||
unsafe fn get_task_guard_page() -> uint {
|
||||
thread_info::stack_guard()
|
||||
}
|
||||
|
||||
// This is initialized in init() and only read from after
|
||||
static mut PAGE_SIZE: uint = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,11 +14,10 @@ use libc;
|
|||
use mem;
|
||||
use ptr;
|
||||
use prelude::*;
|
||||
use super::{last_error, last_net_error, retry, sock_t};
|
||||
use super::{last_error, last_net_error, sock_t};
|
||||
use sync::{Arc, atomic};
|
||||
use sys::fs::FileDesc;
|
||||
use sys::{mod, c, set_nonblocking, wouldblock, timer};
|
||||
use sys_common::{mod, timeout, eof, net};
|
||||
use sys_common::{timeout, eof, net};
|
||||
|
||||
pub use sys_common::net::TcpStream;
|
||||
|
||||
|
|
@ -205,10 +204,6 @@ impl TcpAcceptor {
|
|||
Err(eof())
|
||||
}
|
||||
|
||||
pub fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
|
||||
net::sockname(self.socket(), libc::getsockname)
|
||||
}
|
||||
|
||||
pub fn set_timeout(&mut self, timeout: Option<u64>) {
|
||||
self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use boxed::Box;
|
||||
use cmp;
|
||||
use mem;
|
||||
|
|
|
|||
|
|
@ -137,9 +137,9 @@ unsafe fn init_dtors() {
|
|||
rt::at_exit(move|| {
|
||||
DTOR_LOCK.lock();
|
||||
let dtors = DTORS;
|
||||
DTORS = 0 as *mut _;
|
||||
DTORS = 1 as *mut _;
|
||||
mem::transmute::<_, Box<Vec<(Key, Dtor)>>>(dtors);
|
||||
assert!(DTORS.is_null()); // can't re-init after destructing
|
||||
assert!(DTORS as uint == 1); // can't re-init after destructing
|
||||
DTOR_LOCK.unlock();
|
||||
});
|
||||
}
|
||||
|
|
@ -147,6 +147,9 @@ unsafe fn init_dtors() {
|
|||
unsafe fn register_dtor(key: Key, dtor: Dtor) {
|
||||
DTOR_LOCK.lock();
|
||||
init_dtors();
|
||||
assert!(DTORS as uint != 0);
|
||||
assert!(DTORS as uint != 1,
|
||||
"cannot create new TLS keys after the main thread has exited");
|
||||
(*DTORS).push((key, dtor));
|
||||
DTOR_LOCK.unlock();
|
||||
}
|
||||
|
|
@ -154,6 +157,9 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) {
|
|||
unsafe fn unregister_dtor(key: Key) -> bool {
|
||||
DTOR_LOCK.lock();
|
||||
init_dtors();
|
||||
assert!(DTORS as uint != 0);
|
||||
assert!(DTORS as uint != 1,
|
||||
"cannot unregister destructors after the main thread has exited");
|
||||
let ret = {
|
||||
let dtors = &mut *DTORS;
|
||||
let before = dtors.len();
|
||||
|
|
@ -232,6 +238,7 @@ unsafe extern "system" fn on_tls_callback(h: LPVOID,
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // not actually dead
|
||||
unsafe fn run_dtors() {
|
||||
let mut any_run = true;
|
||||
for _ in range(0, 5i) {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@ use libc;
|
|||
use ptr;
|
||||
use comm;
|
||||
|
||||
use sys::c;
|
||||
use sys::fs::FileDesc;
|
||||
use sys_common::helper_thread::Helper;
|
||||
use prelude::*;
|
||||
use io::IoResult;
|
||||
|
|
@ -80,9 +78,10 @@ fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
|
|||
None => {}
|
||||
}
|
||||
}
|
||||
// See the comment in unix::timer for why we don't have any
|
||||
// asserts here and why we're likely just leaving timers on
|
||||
// the floor as we exit.
|
||||
Err(comm::Disconnected) => {
|
||||
assert_eq!(objs.len(), 1);
|
||||
assert_eq!(chans.len(), 0);
|
||||
break 'outer;
|
||||
}
|
||||
Err(..) => break
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
//! to working in raw UTF-16, with such a wrapper around it.
|
||||
|
||||
use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode};
|
||||
use super::c::{ERROR_ILLEGAL_CHARACTER};
|
||||
use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS};
|
||||
use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT};
|
||||
use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
|
||||
|
|
@ -38,6 +37,8 @@ use prelude::*;
|
|||
use ptr;
|
||||
use str::from_utf8;
|
||||
|
||||
use sys_common::unimpl;
|
||||
|
||||
fn invalid_encoding() -> IoError {
|
||||
IoError {
|
||||
kind: io::InvalidInput,
|
||||
|
|
@ -149,11 +150,8 @@ impl TTY {
|
|||
// Make a CONSOLE_SCREEN_BUFFER_INFO
|
||||
// Call GetConsoleScreenBufferInfo
|
||||
// Maybe call GetLargestConsoleWindowSize instead?
|
||||
Err(super::unimpl())
|
||||
Err(unimpl())
|
||||
}
|
||||
|
||||
// Let us magically declare this as a TTY
|
||||
pub fn isatty(&self) -> bool { true }
|
||||
}
|
||||
|
||||
impl Drop for TTY {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue