提交 aec67c2e 编写于 作者: A Alex Crichton

Revert "std: Re-enable at_exit()"

This reverts commit 9e224c2b.

Conflicts:
	src/libstd/sys/windows/os.rs
上级 582cba18
......@@ -177,7 +177,7 @@
use std::os;
use std::rt;
use std::slice;
use std::sync::{Once, ONCE_INIT, StaticMutex, MUTEX_INIT};
use std::sync::{Once, ONCE_INIT};
use regex::Regex;
......@@ -193,8 +193,6 @@
/// The default logging level of a crate if no other is specified.
const DEFAULT_LOG_LEVEL: u32 = 1;
static LOCK: StaticMutex = MUTEX_INIT;
/// An unsafe constant that is the maximum logging level of any module
/// specified. This is the first line of defense to determining whether a
/// logging statement should be run.
......@@ -281,18 +279,9 @@ fn drop(&mut self) {
pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
// Test the literal string from args against the current filter, if there
// is one.
unsafe {
let _g = LOCK.lock();
match FILTER as uint {
0 => {}
1 => panic!("cannot log after main thread has exited"),
n => {
let filter = mem::transmute::<_, &Regex>(n);
if !filter.is_match(args.to_string().as_slice()) {
return
}
}
}
match unsafe { FILTER.as_ref() } {
Some(filter) if !filter.is_match(args.to_string()[]) => return,
_ => {}
}
// Completely remove the local logger from TLS in case anyone attempts to
......@@ -374,15 +363,9 @@ pub fn mod_enabled(level: u32, module: &str) -> bool {
// This assertion should never get tripped unless we're in an at_exit
// handler after logging has been torn down and a logging attempt was made.
assert!(unsafe { !DIRECTIVES.is_null() });
let _g = LOCK.lock();
unsafe {
assert!(DIRECTIVES as uint != 0);
assert!(DIRECTIVES as uint != 1,
"cannot log after the main thread has exited");
enabled(level, module, (*DIRECTIVES).iter())
}
enabled(level, module, unsafe { (*DIRECTIVES).iter() })
}
fn enabled(level: u32,
......@@ -438,15 +421,14 @@ fn init() {
// Schedule the cleanup for the globals for when the runtime exits.
rt::at_exit(move |:| {
let _g = LOCK.lock();
assert!(!DIRECTIVES.is_null());
let _directives: Box<Vec<directive::LogDirective>> =
mem::transmute(DIRECTIVES);
DIRECTIVES = 1 as *const Vec<directive::LogDirective>;
DIRECTIVES = 0 as *const Vec<directive::LogDirective>;
if !FILTER.is_null() {
let _filter: Box<Regex> = mem::transmute(FILTER);
FILTER = 1 as *const _;
FILTER = 0 as *const _;
}
});
}
......
......@@ -26,19 +26,29 @@
//! ```
use self::StdSource::*;
use prelude::*;
use boxed::Box;
use cell::RefCell;
use clone::Clone;
use failure::LOCAL_STDERR;
use fmt;
use io::{IoResult, IoError, OtherIoError};
use io::{standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
use io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer,
standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
use kinds::{Sync, Send};
use libc;
use mem;
use option::Option;
use option::Option::{Some, None};
use ops::{Deref, DerefMut, FnOnce};
use result::Result::{Ok, Err};
use rt;
use slice::SliceExt;
use str::StrExt;
use string::String;
use sys::{fs, tty};
use sync::{Arc, Mutex, MutexGuard, StaticMutex, MUTEX_INIT};
use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT};
use uint;
use vec::Vec;
// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
......@@ -205,15 +215,14 @@ fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult<u64> {
pub fn stdin() -> StdinReader {
// We're following the same strategy as kimundi's lazy_static library
static mut STDIN: *const StdinReader = 0 as *const StdinReader;
static LOCK: StaticMutex = MUTEX_INIT;
static ONCE: Once = ONCE_INIT;
unsafe {
let _g = LOCK.lock();
if STDIN as uint == 0 {
// The default buffer capacity is 64k, but apparently windows
// doesn't like 64k reads on stdin. See #13304 for details, but the
// idea is that on windows we use a slightly smaller buffer that's
// been seen to be acceptable.
ONCE.doit(|| {
// The default buffer capacity is 64k, but apparently windows doesn't like
// 64k reads on stdin. See #13304 for details, but the idea is that on
// windows we use a slightly smaller buffer that's been seen to be
// acceptable.
let stdin = if cfg!(windows) {
BufferedReader::with_capacity(8 * 1024, stdin_raw())
} else {
......@@ -226,15 +235,11 @@ pub fn stdin() -> StdinReader {
// Make sure to free it at exit
rt::at_exit(|| {
let g = LOCK.lock();
let stdin = STDIN;
STDIN = 1 as *const _;
drop(g);
mem::transmute::<_, Box<StdinReader>>(stdin);
mem::transmute::<_, Box<StdinReader>>(STDIN);
STDIN = 0 as *const _;
});
} else if STDIN as uint == 1 {
panic!("accessing stdin after the main thread has exited")
}
});
(*STDIN).clone()
}
}
......
......@@ -229,13 +229,13 @@
pub mod sync;
pub mod comm;
#[path = "sys/common/mod.rs"] mod sys_common;
#[cfg(unix)]
#[path = "sys/unix/mod.rs"] mod sys;
#[cfg(windows)]
#[path = "sys/windows/mod.rs"] mod sys;
#[path = "sys/common/mod.rs"] mod sys_common;
pub mod rt;
mod failure;
......
......@@ -29,8 +29,6 @@
static LOCK: Mutex = MUTEX_INIT;
static mut QUEUE: *mut Queue = 0 as *mut Queue;
const DTOR_RUN_ITERS: uint = 10;
unsafe fn init() {
if QUEUE.is_null() {
let state: Box<Queue> = box Vec::new();
......@@ -51,7 +49,7 @@ pub fn cleanup() {
unsafe {
LOCK.lock();
let queue = QUEUE;
QUEUE = 1u as *mut _;
QUEUE = 1 as *mut _;
LOCK.unlock();
// make sure we're not recursively cleaning up
......
......@@ -92,7 +92,9 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
// but we just do this to name the main thread and to give it correct
// info about the stack bounds.
let thread: Thread = NewThread::new(Some("<main>".to_string()));
thread_info::set(sys::thread::guard::main(), thread);
thread_info::set((my_stack_bottom, my_stack_top),
sys::thread::guard::main(),
thread);
// By default, some platforms will send a *signal* when a EPIPE error
// would otherwise be delivered. This runtime doesn't install a SIGPIPE
......@@ -131,14 +133,20 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
}
}
/// Enqueues a procedure to run when the main thread exits.
/// Enqueues a procedure to run when the runtime is cleaned up
///
/// The procedure passed to this function will be executed as part of the
/// runtime cleanup phase. For normal rust programs, this means that it will run
/// after all other threads have exited.
///
/// The procedure is *not* executed with a local `Thread` available to it, so
/// primitives like logging, I/O, channels, spawning, etc, are *not* available.
/// This is meant for "bare bones" usage to clean up runtime details, this is
/// not meant as a general-purpose "let's clean everything up" function.
///
/// It is forbidden for procedures to register more `at_exit` handlers when they
/// are running, and doing so will lead to a process abort.
///
/// Note that other threads may still be running when `at_exit` routines start
/// running.
pub fn at_exit<F: FnOnce() + Send>(f: F) {
pub fn at_exit<F:FnOnce()+Send>(f: F) {
at_exit_imp::push(Thunk::new(f));
}
......@@ -154,5 +162,8 @@ pub fn at_exit<F: FnOnce() + Send>(f: F) {
pub unsafe fn cleanup() {
args::cleanup();
sys::stack_overflow::cleanup();
at_exit_imp::cleanup();
// FIXME: (#20012): the resources being cleaned up by at_exit
// currently are not prepared for cleanup to happen asynchronously
// with detached threads using the resources; for now, we leak.
// at_exit_imp::cleanup();
}
......@@ -68,7 +68,7 @@
use libc::c_void;
use mem;
use sync::atomic;
use sys_common::mutex::{Mutex, MUTEX_INIT};
use sync::{Once, ONCE_INIT};
use rt::libunwind as uw;
......@@ -540,20 +540,11 @@ pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, uint)) ->
/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
/// }` from ~1900/3700 (-O/no opts) to 180/590.
#[inline(never)] #[cold] // this is the slow path, please never inline this
fn begin_unwind_inner(msg: Box<Any + Send>,
file_line: &(&'static str, uint)) -> ! {
fn begin_unwind_inner(msg: Box<Any + Send>, file_line: &(&'static str, uint)) -> ! {
// Make sure the default failure handler is registered before we look at the
// callbacks.
unsafe {
static LOCK: Mutex = MUTEX_INIT;
static mut INIT: bool = false;
LOCK.lock();
if !INIT {
register(failure::on_fail);
INIT = true;
}
LOCK.unlock();
}
static INIT: Once = ONCE_INIT;
INIT.doit(|| unsafe { register(failure::on_fail); });
// First, invoke call the user-defined callbacks triggered on thread panic.
//
......
......@@ -20,8 +20,6 @@
//! can be created in the future and there must be no active timers at that
//! time.
#![macro_escape]
use prelude::*;
use cell::UnsafeCell;
......@@ -70,17 +68,6 @@ unsafe impl<M:Send> Sync for Helper<M> { }
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.
......@@ -97,7 +84,7 @@ pub fn boot<T, F>(&'static self, f: F, helper: fn(helper_signal::signal, Receive
{
unsafe {
let _guard = self.lock.lock().unwrap();
if *self.chan.get() as uint == 0 {
if !*self.initialized.get() {
let (tx, rx) = channel();
*self.chan.get() = mem::transmute(box tx);
let (receive, send) = helper_signal::new();
......@@ -106,17 +93,15 @@ pub fn boot<T, F>(&'static self, f: F, helper: fn(helper_signal::signal, Receive
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");
}
}
}
......@@ -131,9 +116,7 @@ pub fn send(&'static self, msg: 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() as uint != 0);
assert!(*self.chan.get() as uint != 1,
"cannot continue usage after shutdown");
assert!(!self.chan.get().is_null());
(**self.chan.get()).send(msg);
helper_signal::signal(*self.signal.get() as helper_signal::signal);
}
......@@ -146,13 +129,9 @@ fn shutdown(&'static self) {
// 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() = 1 as *mut Sender<M>;
*self.chan.get() = 0 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)]
#![macro_escape]
#![allow(dead_code)]
use io::{mod, IoError, IoResult};
use prelude::*;
......
......@@ -29,7 +29,6 @@ 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.
......
......@@ -23,9 +23,7 @@
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;
#[cfg(not(target_os = "linux"))]
use sync::MutexGuard;
use sync::{Mutex, MutexGuard};
use sys_common::{mod, keep_going, short_write, timeout};
use prelude::*;
use cmp;
......@@ -613,13 +611,11 @@ 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,7 +26,6 @@ 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,6 +121,37 @@ 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,8 +8,6 @@
// 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;
......@@ -17,6 +15,10 @@
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,
}
......@@ -33,6 +35,7 @@ fn with<R>(f: |&mut ThreadInfo| -> R) -> R {
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),
})
......@@ -50,9 +53,10 @@ pub fn stack_guard() -> uint {
ThreadInfo::with(|info| info.stack_guard)
}
pub fn set(stack_guard: uint, thread: Thread) {
pub fn set(stack_bounds: (uint, uint), 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,6 +140,9 @@ pub struct Key {
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;
use io::{IoResult, Writer};
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 @@ struct Context<'a> {
// 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 = LOCK.lock();
let _g = unsafe { LOCK.lock() };
try!(writeln!(w, "stack backtrace:"));
......@@ -241,8 +241,12 @@ fn dladdr(addr: *const libc::c_void,
#[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,14 +10,30 @@
#![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,6 +11,7 @@
use cell::UnsafeCell;
use kinds::Sync;
use sys::sync as ffi;
use sys_common::mutex;
pub struct Mutex { inner: UnsafeCell<ffi::pthread_mutex_t> }
......@@ -25,7 +26,6 @@ pub unsafe fn raw(m: &Mutex) -> *mut ffi::pthread_mutex_t {
unsafe impl Sync for Mutex {}
#[allow(dead_code)] // sys isn't exported yet
impl Mutex {
#[inline]
pub unsafe fn new() -> Mutex {
......
......@@ -10,16 +10,17 @@
//! 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};
use os;
use libc::{mod, c_int, c_char, c_void};
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 @@ fn lock_nonblocking(&self) {}
fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
let ret = Guard {
fd: self.fd(),
guard: self.inner.lock.lock().unwrap(),
guard: unsafe { self.inner.lock.lock().unwrap() },
};
assert!(set_nonblocking(self.fd(), true).is_ok());
ret
......
......@@ -11,7 +11,7 @@
use libc::{mod, pid_t, c_void, c_int};
use c_str::CString;
use io::{IoResult, EndOfFile};
use io::{mod, IoResult, IoError, EndOfFile};
use mem;
use os;
use ptr;
......@@ -327,7 +327,7 @@ pub fn wait(&self, deadline: u64) -> IoResult<ProcessExit> {
// The actual communication between the helper thread and this thread is
// quite simple, just a channel moving data around.
HELPER.boot(register_sigchld, waitpid_helper);
unsafe { HELPER.boot(register_sigchld, waitpid_helper) }
match self.try_wait() {
Some(ret) => return Ok(ret),
......@@ -335,7 +335,7 @@ pub fn wait(&self, deadline: u64) -> IoResult<ProcessExit> {
}
let (tx, rx) = channel();
HELPER.send(NewChild(self.pid, tx, deadline));
unsafe { HELPER.send(NewChild(self.pid, tx, deadline)); }
return match rx.recv_opt() {
Ok(e) => Ok(e),
Err(()) => Err(timeout("wait timed out")),
......@@ -419,15 +419,8 @@ fn waitpid_helper(input: libc::c_int,
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,7 +17,6 @@ pub struct RWLock { inner: UnsafeCell<ffi::pthread_rwlock_t> }
inner: UnsafeCell { value: ffi::PTHREAD_RWLOCK_INITIALIZER },
};
#[allow(dead_code)] // sys isn't exported yet
impl RWLock {
#[inline]
pub unsafe fn new() -> RWLock {
......
......@@ -34,6 +34,7 @@ fn drop(&mut self) {
#[cfg(any(target_os = "linux", target_os = "macos"))]
mod imp {
use core::prelude::*;
use sys_common::stack;
use super::Handler;
......
......@@ -135,6 +135,10 @@ pub fn accept(&mut self) -> IoResult<TcpStream> {
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 fd = FileDesc::new(input, true);
let mut 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,15 +168,8 @@ fn signal(active: &mut Vec<Box<Inner>>,
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,4 +43,5 @@ pub fn set_raw(&mut self, _raw: bool) -> IoResult<()> {
pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
Err(sys_common::unimpl())
}
pub fn isatty(&self) -> bool { false }
}
......@@ -7,22 +7,19 @@
// <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.
#![allow(dead_code)] // constants/fields aren't always used on all platforms
/// 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.
use c_str::CString;
use intrinsics;
......@@ -297,7 +294,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 = LOCK.lock();
let _g = unsafe { 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,6 +15,7 @@
#![allow(non_camel_case_types)]
use libc;
use prelude::*;
pub const WSADESCRIPTION_LEN: uint = 256;
pub const WSASYS_STATUS_LEN: uint = 128;
......
......@@ -10,17 +10,21 @@
//! Blocking Windows-based file I/O
use alloc::arc::Arc;
use libc::{mod, c_int};
use io;
use c_str::CString;
use mem;
use ptr;
use sys::os::fill_utf16_buf_and_decode;
use path;
use ptr;
use str;
use io;
use prelude::*;
use sys;
use sys::os;
use sys_common::{unimpl, mkerr_libc};
use sys_common::{keep_going, eof, mkerr_libc};
use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode};
use io::{IoResult, IoError, FileStat, SeekStyle};
......@@ -441,7 +445,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(unimpl())
Err(super::unimpl())
}
pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> {
......
......@@ -11,14 +11,30 @@
#![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;
......@@ -164,6 +180,14 @@ 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,6 +15,7 @@
use prelude::*;
use fmt;
use io::{IoResult, IoError};
use iter::repeat;
use libc::{c_int, c_void};
......
......@@ -365,7 +365,7 @@ pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
// acquire the lock.
//
// See comments in close_read() about why this lock is necessary.
let guard = self.inner.lock.lock();
let guard = unsafe { self.inner.lock.lock() };
if self.read_closed() {
return Err(eof())
}
......@@ -441,7 +441,7 @@ pub fn write(&mut self, buf: &[u8]) -> IoResult<()> {
// going after we woke up.
//
// See comments in close_read() about why this lock is necessary.
let guard = self.inner.lock.lock();
let guard = unsafe { self.inner.lock.lock() };
if self.write_closed() {
return Err(epipe())
}
......@@ -516,14 +516,14 @@ pub fn close_read(&mut self) -> IoResult<()> {
// 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 = self.inner.lock.lock();
let _guard = unsafe { 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 = self.inner.lock.lock();
let _guard = unsafe { self.inner.lock.lock() };
self.inner.write_closed.store(true, atomic::SeqCst);
self.cancel_io()
}
......
......@@ -8,24 +8,25 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use prelude::*;
use libc::{pid_t, c_void};
use libc::{pid_t, c_void, c_int};
use libc;
use c_str::CString;
use io;
use mem;
use os;
use ptr;
use io::process::{ProcessExit, ExitStatus};
use prelude::*;
use io::process::{ProcessExit, ExitStatus, ExitSignal};
use collections;
use path::BytesContainer;
use hash::Hash;
use io::{IoResult, IoError};
use sys::timer;
use sys::fs;
use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer};
use sys::fs::FileDesc;
use sys_common::{AsInner, timeout};
use sys_common::helper_thread::Helper;
use sys_common::{AsInner, mkerr_libc, timeout};
use io::fs::PathExtensions;
......@@ -120,6 +121,8 @@ pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>,
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 mem;
use libc;
use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL};
use sys_common::stack;
use sys_common::{stack, thread_info};
pub struct Handler {
_data: *mut libc::c_void
......@@ -30,6 +30,14 @@ 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,10 +14,11 @@
use mem;
use ptr;
use prelude::*;
use super::{last_error, last_net_error, sock_t};
use super::{last_error, last_net_error, retry, sock_t};
use sync::{Arc, atomic};
use sys::fs::FileDesc;
use sys::{mod, c, set_nonblocking, wouldblock, timer};
use sys_common::{timeout, eof, net};
use sys_common::{mod, timeout, eof, net};
pub use sys_common::net::TcpStream;
......@@ -204,6 +205,10 @@ pub fn accept(&mut self) -> IoResult<TcpStream> {
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,6 +8,8 @@
// 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 = 1 as *mut _;
DTORS = 0 as *mut _;
mem::transmute::<_, Box<Vec<(Key, Dtor)>>>(dtors);
assert!(DTORS as uint == 1); // can't re-init after destructing
assert!(DTORS.is_null()); // can't re-init after destructing
DTOR_LOCK.unlock();
});
}
......@@ -147,9 +147,6 @@ 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();
}
......@@ -157,9 +154,6 @@ 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();
......@@ -238,7 +232,6 @@ unsafe fn unregister_dtor(key: Key) -> bool {
}
}
#[allow(dead_code)] // not actually dead
unsafe fn run_dtors() {
let mut any_run = true;
for _ in range(0, 5i) {
......
......@@ -26,6 +26,8 @@
use ptr;
use comm;
use sys::c;
use sys::fs::FileDesc;
use sys_common::helper_thread::Helper;
use prelude::*;
use io::IoResult;
......@@ -78,10 +80,9 @@ 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,6 +26,7 @@
//! 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,8 +39,6 @@
use ptr;
use str::from_utf8;
use sys_common::unimpl;
fn invalid_encoding() -> IoError {
IoError {
kind: io::InvalidInput,
......@@ -151,8 +150,11 @@ pub fn get_winsize(&mut self) -> IoResult<(int, int)> {
// Make a CONSOLE_SCREEN_BUFFER_INFO
// Call GetConsoleScreenBufferInfo
// Maybe call GetLargestConsoleWindowSize instead?
Err(unimpl())
Err(super::unimpl())
}
// Let us magically declare this as a TTY
pub fn isatty(&self) -> bool { true }
}
impl Drop for TTY {
......
......@@ -232,10 +232,13 @@ fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> JoinGuard<T> {
let my_stack_top = addr as uint;
let my_stack_bottom = my_stack_top - stack_size + 1024;
unsafe {
stack::record_os_managed_stack_bounds(my_stack_bottom,
my_stack_top);
thread_info::set(imp::guard::current(), their_thread);
stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top);
}
thread_info::set(
(my_stack_bottom, my_stack_top),
unsafe { imp::guard::current() },
their_thread
);
let mut output = None;
let f: Thunk<(), T> = if stdout.is_some() || stderr.is_some() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册