From 3a527f2b3311d5b1c6dd7c72db71c45596e6db49 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 30 Sep 2014 17:03:56 -0700 Subject: Runtime removal: add private sys, sys_common modules These modules will house the code that used to be part of the runtime system in libnative. The `sys_common` module contains a few low-level but cross-platform details. The `sys` module is set up using `#[cfg()]` to include either a unix or windows implementation of a common API surface. This API surface is *not* exported directly in `libstd`, but is instead used to bulid `std::os` and `std::io`. Ultimately, the low-level details in `sys` will be exposed in a controlled way through a separate platform-specific surface, but that setup is not part of this patch. --- src/libnative/io/c_unix.rs | 261 ----------------------------------------- src/libnative/io/c_windows.rs | 246 --------------------------------------- src/libnative/io/mod.rs | 3 - src/libnative/io/util.rs | 209 --------------------------------- src/libstd/io/mod.rs | 92 +-------------- src/libstd/lib.rs | 7 ++ src/libstd/os.rs | 155 +------------------------ src/libstd/sys/common/mod.rs | 91 +++++++++++++++ src/libstd/sys/unix/c.rs | 262 ++++++++++++++++++++++++++++++++++++++++++ src/libstd/sys/unix/mod.rs | 92 +++++++++++++++ src/libstd/sys/unix/os.rs | 101 ++++++++++++++++ src/libstd/sys/windows/c.rs | 250 ++++++++++++++++++++++++++++++++++++++++ src/libstd/sys/windows/mod.rs | 178 ++++++++++++++++++++++++++++ src/libstd/sys/windows/os.rs | 103 +++++++++++++++++ 14 files changed, 1093 insertions(+), 957 deletions(-) delete mode 100644 src/libnative/io/c_unix.rs delete mode 100644 src/libnative/io/c_windows.rs delete mode 100644 src/libnative/io/util.rs create mode 100644 src/libstd/sys/common/mod.rs create mode 100644 src/libstd/sys/unix/c.rs create mode 100644 src/libstd/sys/unix/mod.rs create mode 100644 src/libstd/sys/unix/os.rs create mode 100644 src/libstd/sys/windows/c.rs create mode 100644 src/libstd/sys/windows/mod.rs create mode 100644 src/libstd/sys/windows/os.rs diff --git a/src/libnative/io/c_unix.rs b/src/libnative/io/c_unix.rs deleted file mode 100644 index f1757d367c3..00000000000 --- a/src/libnative/io/c_unix.rs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! C definitions used by libnative that don't belong in liblibc - -#![allow(dead_code)] - -pub use self::select::fd_set; -pub use self::signal::{sigaction, siginfo, sigset_t}; -pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP}; -pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD}; - -use libc; - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] -pub const FIONBIO: libc::c_ulong = 0x8004667e; -#[cfg(any(all(target_os = "linux", - any(target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm")), - target_os = "android"))] -pub const FIONBIO: libc::c_ulong = 0x5421; -#[cfg(all(target_os = "linux", - any(target_arch = "mips", target_arch = "mipsel")))] -pub const FIONBIO: libc::c_ulong = 0x667e; - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] -pub const FIOCLEX: libc::c_ulong = 0x20006601; -#[cfg(any(all(target_os = "linux", - any(target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm")), - target_os = "android"))] -pub const FIOCLEX: libc::c_ulong = 0x5451; -#[cfg(all(target_os = "linux", - any(target_arch = "mips", target_arch = "mipsel")))] -pub const FIOCLEX: libc::c_ulong = 0x6601; - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] -pub const MSG_DONTWAIT: libc::c_int = 0x80; -#[cfg(any(target_os = "linux", target_os = "android"))] -pub const MSG_DONTWAIT: libc::c_int = 0x40; - -pub const WNOHANG: libc::c_int = 1; - -extern { - pub fn gettimeofday(timeval: *mut libc::timeval, - tzp: *mut libc::c_void) -> libc::c_int; - pub fn select(nfds: libc::c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut libc::timeval) -> libc::c_int; - pub fn getsockopt(sockfd: libc::c_int, - level: libc::c_int, - optname: libc::c_int, - optval: *mut libc::c_void, - optlen: *mut libc::socklen_t) -> libc::c_int; - pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int; - - - pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int, - options: libc::c_int) -> libc::pid_t; - - pub fn sigaction(signum: libc::c_int, - act: *const sigaction, - oldact: *mut sigaction) -> libc::c_int; - - pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; - pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; - pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int; -} - -#[cfg(any(target_os = "macos", target_os = "ios"))] -mod select { - pub const FD_SETSIZE: uint = 1024; - - #[repr(C)] - pub struct fd_set { - fds_bits: [i32, ..(FD_SETSIZE / 32)] - } - - pub fn fd_set(set: &mut fd_set, fd: i32) { - set.fds_bits[(fd / 32) as uint] |= 1 << ((fd % 32) as uint); - } -} - -#[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux"))] -mod select { - use std::uint; - use libc; - - pub const FD_SETSIZE: uint = 1024; - - #[repr(C)] - pub struct fd_set { - // FIXME: shouldn't this be a c_ulong? - fds_bits: [libc::uintptr_t, ..(FD_SETSIZE / uint::BITS)] - } - - pub fn fd_set(set: &mut fd_set, fd: i32) { - let fd = fd as uint; - set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS); - } -} - -#[cfg(any(all(target_os = "linux", - any(target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm")), - target_os = "android"))] -mod signal { - use libc; - - pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; - pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002; - pub const SA_NODEFER: libc::c_ulong = 0x40000000; - pub const SA_ONSTACK: libc::c_ulong = 0x08000000; - pub const SA_RESETHAND: libc::c_ulong = 0x80000000; - pub const SA_RESTART: libc::c_ulong = 0x10000000; - pub const SA_SIGINFO: libc::c_ulong = 0x00000004; - pub const SIGCHLD: libc::c_int = 17; - - // This definition is not as accurate as it could be, {pid, uid, status} is - // actually a giant union. Currently we're only interested in these fields, - // however. - #[repr(C)] - pub struct siginfo { - si_signo: libc::c_int, - si_errno: libc::c_int, - si_code: libc::c_int, - pub pid: libc::pid_t, - pub uid: libc::uid_t, - pub status: libc::c_int, - } - - #[repr(C)] - pub struct sigaction { - pub sa_handler: extern fn(libc::c_int), - pub sa_mask: sigset_t, - pub sa_flags: libc::c_ulong, - sa_restorer: *mut libc::c_void, - } - - #[repr(C)] - #[cfg(target_word_size = "32")] - pub struct sigset_t { - __val: [libc::c_ulong, ..32], - } - - #[repr(C)] - #[cfg(target_word_size = "64")] - pub struct sigset_t { - __val: [libc::c_ulong, ..16], - } -} - -#[cfg(all(target_os = "linux", - any(target_arch = "mips", target_arch = "mipsel")))] -mod signal { - use libc; - - pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; - pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000; - pub const SA_NODEFER: libc::c_ulong = 0x40000000; - pub const SA_ONSTACK: libc::c_ulong = 0x08000000; - pub const SA_RESETHAND: libc::c_ulong = 0x80000000; - pub const SA_RESTART: libc::c_ulong = 0x10000000; - pub const SA_SIGINFO: libc::c_ulong = 0x00000008; - pub const SIGCHLD: libc::c_int = 18; - - // This definition is not as accurate as it could be, {pid, uid, status} is - // actually a giant union. Currently we're only interested in these fields, - // however. - #[repr(C)] - pub struct siginfo { - si_signo: libc::c_int, - si_code: libc::c_int, - si_errno: libc::c_int, - pub pid: libc::pid_t, - pub uid: libc::uid_t, - pub status: libc::c_int, - } - - #[repr(C)] - pub struct sigaction { - pub sa_flags: libc::c_uint, - pub sa_handler: extern fn(libc::c_int), - pub sa_mask: sigset_t, - sa_restorer: *mut libc::c_void, - sa_resv: [libc::c_int, ..1], - } - - #[repr(C)] - pub struct sigset_t { - __val: [libc::c_ulong, ..32], - } -} - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] -mod signal { - use libc; - - pub const SA_ONSTACK: libc::c_int = 0x0001; - pub const SA_RESTART: libc::c_int = 0x0002; - pub const SA_RESETHAND: libc::c_int = 0x0004; - pub const SA_NOCLDSTOP: libc::c_int = 0x0008; - pub const SA_NODEFER: libc::c_int = 0x0010; - pub const SA_NOCLDWAIT: libc::c_int = 0x0020; - pub const SA_SIGINFO: libc::c_int = 0x0040; - pub const SIGCHLD: libc::c_int = 20; - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub type sigset_t = u32; - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[repr(C)] - pub struct sigset_t { - bits: [u32, ..4], - } - - // This structure has more fields, but we're not all that interested in - // them. - #[repr(C)] - pub struct siginfo { - pub si_signo: libc::c_int, - pub si_errno: libc::c_int, - pub si_code: libc::c_int, - pub pid: libc::pid_t, - pub uid: libc::uid_t, - pub status: libc::c_int, - } - - #[repr(C)] - pub struct sigaction { - pub sa_handler: extern fn(libc::c_int), - pub sa_flags: libc::c_int, - pub sa_mask: sigset_t, - } -} diff --git a/src/libnative/io/c_windows.rs b/src/libnative/io/c_windows.rs deleted file mode 100644 index ee6aa26ede2..00000000000 --- a/src/libnative/io/c_windows.rs +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! C definitions used by libnative that don't belong in liblibc - -#![allow(overflowing_literals)] - -use libc; - -pub const WSADESCRIPTION_LEN: uint = 256; -pub const WSASYS_STATUS_LEN: uint = 128; -pub const FIONBIO: libc::c_long = 0x8004667e; -pub const FD_SETSIZE: uint = 64; -pub const MSG_DONTWAIT: libc::c_int = 0; -pub const ERROR_ILLEGAL_CHARACTER: libc::c_int = 582; -pub const ENABLE_ECHO_INPUT: libc::DWORD = 0x4; -pub const ENABLE_EXTENDED_FLAGS: libc::DWORD = 0x80; -pub const ENABLE_INSERT_MODE: libc::DWORD = 0x20; -pub const ENABLE_LINE_INPUT: libc::DWORD = 0x2; -pub const ENABLE_PROCESSED_INPUT: libc::DWORD = 0x1; -pub const ENABLE_QUICK_EDIT_MODE: libc::DWORD = 0x40; -pub const WSA_INVALID_EVENT: WSAEVENT = 0 as WSAEVENT; - -pub const FD_ACCEPT: libc::c_long = 0x08; -pub const FD_MAX_EVENTS: uint = 10; -pub const WSA_INFINITE: libc::DWORD = libc::INFINITE; -pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT; -pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0; -pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED; - -#[repr(C)] -#[cfg(target_arch = "x86")] -pub struct WSADATA { - pub wVersion: libc::WORD, - pub wHighVersion: libc::WORD, - pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], - pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: *mut u8, -} -#[repr(C)] -#[cfg(target_arch = "x86_64")] -pub struct WSADATA { - pub wVersion: libc::WORD, - pub wHighVersion: libc::WORD, - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: *mut u8, - pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], - pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], -} - -pub type LPWSADATA = *mut WSADATA; - -#[repr(C)] -pub struct WSANETWORKEVENTS { - pub lNetworkEvents: libc::c_long, - pub iErrorCode: [libc::c_int, ..FD_MAX_EVENTS], -} - -pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS; - -pub type WSAEVENT = libc::HANDLE; - -#[repr(C)] -pub struct fd_set { - fd_count: libc::c_uint, - fd_array: [libc::SOCKET, ..FD_SETSIZE], -} - -pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) { - set.fd_array[set.fd_count as uint] = s; - set.fd_count += 1; -} - -#[link(name = "ws2_32")] -extern "system" { - pub fn WSAStartup(wVersionRequested: libc::WORD, - lpWSAData: LPWSADATA) -> libc::c_int; - pub fn WSAGetLastError() -> libc::c_int; - pub fn WSACloseEvent(hEvent: WSAEVENT) -> libc::BOOL; - pub fn WSACreateEvent() -> WSAEVENT; - pub fn WSAEventSelect(s: libc::SOCKET, - hEventObject: WSAEVENT, - lNetworkEvents: libc::c_long) -> libc::c_int; - pub fn WSASetEvent(hEvent: WSAEVENT) -> libc::BOOL; - pub fn WSAWaitForMultipleEvents(cEvents: libc::DWORD, - lphEvents: *const WSAEVENT, - fWaitAll: libc::BOOL, - dwTimeout: libc::DWORD, - fAltertable: libc::BOOL) -> libc::DWORD; - pub fn WSAEnumNetworkEvents(s: libc::SOCKET, - hEventObject: WSAEVENT, - lpNetworkEvents: LPWSANETWORKEVENTS) - -> libc::c_int; - - pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long, - argp: *mut libc::c_ulong) -> libc::c_int; - pub fn select(nfds: libc::c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - exceptfds: *mut fd_set, - timeout: *mut libc::timeval) -> libc::c_int; - pub fn getsockopt(sockfd: libc::SOCKET, - level: libc::c_int, - optname: libc::c_int, - optval: *mut libc::c_char, - optlen: *mut libc::c_int) -> libc::c_int; - - pub fn SetEvent(hEvent: libc::HANDLE) -> libc::BOOL; - pub fn WaitForMultipleObjects(nCount: libc::DWORD, - lpHandles: *const libc::HANDLE, - bWaitAll: libc::BOOL, - dwMilliseconds: libc::DWORD) -> libc::DWORD; - - pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL; - pub fn CancelIoEx(hFile: libc::HANDLE, - lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; -} - -pub mod compat { - use std::intrinsics::{atomic_store_relaxed, transmute}; - use std::iter::Iterator; - use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; - - extern "system" { - fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; - fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; - } - - // store_func() is idempotent, so using relaxed ordering for the atomics - // should be enough. This way, calling a function in this compatibility - // layer (after it's loaded) shouldn't be any slower than a regular DLL - // call. - unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) { - let mut module: Vec = module.utf16_units().collect(); - module.push(0); - symbol.with_c_str(|symbol| { - let handle = GetModuleHandleW(module.as_ptr()); - let func: uint = transmute(GetProcAddress(handle, symbol)); - atomic_store_relaxed(ptr, if func == 0 { - fallback - } else { - func - }) - }) - } - - /// Macro for creating a compatibility fallback for a Windows function - /// - /// # Example - /// ``` - /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) { - /// // Fallback implementation - /// }) - /// ``` - /// - /// Note that arguments unused by the fallback implementation should not be called `_` as - /// they are used to be passed to the real function if available. - macro_rules! compat_fn( - ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty $fallback:block) => ( - #[inline(always)] - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { - static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk; - - extern "system" fn thunk($($argname: $argtype),*) -> $rettype { - unsafe { - ::io::c::compat::store_func(&mut ptr as *mut _ as *mut uint, - stringify!($module), - stringify!($symbol), - fallback as uint); - ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) - } - } - - extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback - - ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) - } - ); - - ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => ( - compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback) - ) - ) - - /// Compatibility layer for functions in `kernel32.dll` - /// - /// Latest versions of Windows this is needed for: - /// - /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003 - /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003 - pub mod kernel32 { - use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE}; - use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED; - - extern "system" { - fn SetLastError(dwErrCode: DWORD); - } - - compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, - _lpTargetFileName: LPCWSTR, - _dwFlags: DWORD) -> BOOLEAN { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } - 0 - }) - - compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE, - _lpszFilePath: LPCWSTR, - _cchFilePath: DWORD, - _dwFlags: DWORD) -> DWORD { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } - 0 - }) - } -} - -extern "system" { - // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL - pub fn ReadConsoleW(hConsoleInput: libc::HANDLE, - lpBuffer: libc::LPVOID, - nNumberOfCharsToRead: libc::DWORD, - lpNumberOfCharsRead: libc::LPDWORD, - pInputControl: libc::LPVOID) -> libc::BOOL; - - pub fn WriteConsoleW(hConsoleOutput: libc::HANDLE, - lpBuffer: libc::types::os::arch::extra::LPCVOID, - nNumberOfCharsToWrite: libc::DWORD, - lpNumberOfCharsWritten: libc::LPDWORD, - lpReserved: libc::LPVOID) -> libc::BOOL; - - pub fn GetConsoleMode(hConsoleHandle: libc::HANDLE, - lpMode: libc::LPDWORD) -> libc::BOOL; - - pub fn SetConsoleMode(hConsoleHandle: libc::HANDLE, - lpMode: libc::DWORD) -> libc::BOOL; -} diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 954f7bbc59a..90f8f6c214e 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -73,9 +73,6 @@ pub mod pipe; #[path = "tty_windows.rs"] mod tty; -#[cfg(unix)] #[path = "c_unix.rs"] mod c; -#[cfg(windows)] #[path = "c_windows.rs"] mod c; - fn unimpl() -> IoError { #[cfg(unix)] use libc::ENOSYS as ERROR; #[cfg(windows)] use libc::ERROR_CALL_NOT_IMPLEMENTED as ERROR; diff --git a/src/libnative/io/util.rs b/src/libnative/io/util.rs deleted file mode 100644 index 5f69ec00cdd..00000000000 --- a/src/libnative/io/util.rs +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use libc; -use std::cmp; -use std::mem; -use std::os; -use std::ptr; -use std::rt::rtio::{IoResult, IoError}; - -use super::c; -use super::net; -use super::{retry, last_error}; - -#[deriving(Show)] -pub enum SocketStatus { - Readable, - Writable, -} - -pub fn timeout(desc: &'static str) -> IoError { - #[cfg(unix)] use libc::ETIMEDOUT as ERROR; - #[cfg(windows)] use libc::ERROR_OPERATION_ABORTED as ERROR; - IoError { - code: ERROR as uint, - extra: 0, - detail: Some(desc.to_string()), - } -} - -pub fn short_write(n: uint, desc: &'static str) -> IoError { - #[cfg(unix)] use libc::EAGAIN as ERROR; - #[cfg(windows)] use libc::ERROR_OPERATION_ABORTED as ERROR; - IoError { - code: ERROR as uint, - extra: n, - detail: Some(desc.to_string()), - } -} - -pub fn eof() -> IoError { - IoError { - code: libc::EOF as uint, - extra: 0, - detail: None, - } -} - -#[cfg(windows)] -pub fn ms_to_timeval(ms: u64) -> libc::timeval { - libc::timeval { - tv_sec: (ms / 1000) as libc::c_long, - tv_usec: ((ms % 1000) * 1000) as libc::c_long, - } -} -#[cfg(not(windows))] -pub fn ms_to_timeval(ms: u64) -> libc::timeval { - libc::timeval { - tv_sec: (ms / 1000) as libc::time_t, - tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t, - } -} - -#[cfg(unix)] -pub fn wouldblock() -> bool { - let err = os::errno(); - err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int -} - -#[cfg(windows)] -pub fn wouldblock() -> bool { - let err = os::errno(); - err == libc::WSAEWOULDBLOCK as uint -} - -#[cfg(unix)] -pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> { - let set = nb as libc::c_int; - super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) })) -} - -#[cfg(windows)] -pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> { - let mut set = nb as libc::c_ulong; - if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } { - Err(last_error()) - } else { - Ok(()) - } -} - -// See http://developerweb.net/viewtopic.php?id=3196 for where this is -// derived from. -pub fn connect_timeout(fd: net::sock_t, - addrp: *const libc::sockaddr, - len: libc::socklen_t, - timeout_ms: u64) -> IoResult<()> { - use std::os; - #[cfg(unix)] use libc::EINPROGRESS as INPROGRESS; - #[cfg(windows)] use libc::WSAEINPROGRESS as INPROGRESS; - #[cfg(unix)] use libc::EWOULDBLOCK as WOULDBLOCK; - #[cfg(windows)] use libc::WSAEWOULDBLOCK as WOULDBLOCK; - - // Make sure the call to connect() doesn't block - try!(set_nonblocking(fd, true)); - - let ret = match unsafe { libc::connect(fd, addrp, len) } { - // If the connection is in progress, then we need to wait for it to - // finish (with a timeout). The current strategy for doing this is - // to use select() with a timeout. - -1 if os::errno() as int == INPROGRESS as int || - os::errno() as int == WOULDBLOCK as int => { - let mut set: c::fd_set = unsafe { mem::zeroed() }; - c::fd_set(&mut set, fd); - match await(fd, &mut set, timeout_ms) { - 0 => Err(timeout("connection timed out")), - -1 => Err(last_error()), - _ => { - let err: libc::c_int = try!( - net::getsockopt(fd, libc::SOL_SOCKET, libc::SO_ERROR)); - if err == 0 { - Ok(()) - } else { - Err(IoError { - code: err as uint, - extra: 0, - detail: Some(os::error_string(err as uint)), - }) - } - } - } - } - - -1 => Err(last_error()), - _ => Ok(()), - }; - - // be sure to turn blocking I/O back on - try!(set_nonblocking(fd, false)); - return ret; - - #[cfg(unix)] - fn await(fd: net::sock_t, set: &mut c::fd_set, - timeout: u64) -> libc::c_int { - let start = ::io::timer::now(); - retry(|| unsafe { - // Recalculate the timeout each iteration (it is generally - // undefined what the value of the 'tv' is after select - // returns EINTR). - let mut tv = ms_to_timeval(timeout - (::io::timer::now() - start)); - c::select(fd + 1, ptr::null_mut(), set as *mut _, - ptr::null_mut(), &mut tv) - }) - } - #[cfg(windows)] - fn await(_fd: net::sock_t, set: &mut c::fd_set, - timeout: u64) -> libc::c_int { - let mut tv = ms_to_timeval(timeout); - unsafe { c::select(1, ptr::null_mut(), set, ptr::null_mut(), &mut tv) } - } -} - -pub fn await(fds: &[net::sock_t], deadline: Option, - status: SocketStatus) -> IoResult<()> { - let mut set: c::fd_set = unsafe { mem::zeroed() }; - let mut max = 0; - for &fd in fds.iter() { - c::fd_set(&mut set, fd); - max = cmp::max(max, fd + 1); - } - if cfg!(windows) { - max = fds.len() as net::sock_t; - } - - let (read, write) = match status { - Readable => (&mut set as *mut _, ptr::null_mut()), - Writable => (ptr::null_mut(), &mut set as *mut _), - }; - let mut tv: libc::timeval = unsafe { mem::zeroed() }; - - match retry(|| { - let now = ::io::timer::now(); - let tvp = match deadline { - None => ptr::null_mut(), - Some(deadline) => { - // If we're past the deadline, then pass a 0 timeout to - // select() so we can poll the status - let ms = if deadline < now {0} else {deadline - now}; - tv = ms_to_timeval(ms); - &mut tv as *mut _ - } - }; - let r = unsafe { - c::select(max as libc::c_int, read, write, ptr::null_mut(), tvp) - }; - r - }) { - -1 => Err(last_error()), - 0 => Err(timeout("timed out")), - _ => Ok(()), - } -} diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index c404741b7c3..78abbb9f80d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -236,8 +236,7 @@ use os; use boxed::Box; use result::{Ok, Err, Result}; use rt::rtio; -use slice::{AsSlice, SlicePrelude}; -use str::{Str, StrPrelude}; +use sys; use str; use string::String; use uint; @@ -312,91 +311,10 @@ impl IoError { /// struct is filled with an allocated string describing the error /// in more detail, retrieved from the operating system. pub fn from_errno(errno: uint, detail: bool) -> IoError { - - #[cfg(windows)] - fn get_err(errno: i32) -> (IoErrorKind, &'static str) { - match errno { - libc::EOF => (EndOfFile, "end of file"), - libc::ERROR_NO_DATA => (BrokenPipe, "the pipe is being closed"), - libc::ERROR_FILE_NOT_FOUND => (FileNotFound, "file not found"), - libc::ERROR_INVALID_NAME => (InvalidInput, "invalid file name"), - libc::WSAECONNREFUSED => (ConnectionRefused, "connection refused"), - libc::WSAECONNRESET => (ConnectionReset, "connection reset"), - libc::ERROR_ACCESS_DENIED | libc::WSAEACCES => - (PermissionDenied, "permission denied"), - libc::WSAEWOULDBLOCK => { - (ResourceUnavailable, "resource temporarily unavailable") - } - libc::WSAENOTCONN => (NotConnected, "not connected"), - libc::WSAECONNABORTED => (ConnectionAborted, "connection aborted"), - libc::WSAEADDRNOTAVAIL => (ConnectionRefused, "address not available"), - libc::WSAEADDRINUSE => (ConnectionRefused, "address in use"), - libc::ERROR_BROKEN_PIPE => (EndOfFile, "the pipe has ended"), - libc::ERROR_OPERATION_ABORTED => - (TimedOut, "operation timed out"), - libc::WSAEINVAL => (InvalidInput, "invalid argument"), - libc::ERROR_CALL_NOT_IMPLEMENTED => - (IoUnavailable, "function not implemented"), - libc::ERROR_INVALID_HANDLE => - (MismatchedFileTypeForOperation, - "invalid handle provided to function"), - libc::ERROR_NOTHING_TO_TERMINATE => - (InvalidInput, "no process to kill"), - - // libuv maps this error code to EISDIR. we do too. if it is found - // to be incorrect, we can add in some more machinery to only - // return this message when ERROR_INVALID_FUNCTION after certain - // Windows calls. - libc::ERROR_INVALID_FUNCTION => (InvalidInput, - "illegal operation on a directory"), - - _ => (OtherIoError, "unknown error") - } - } - - #[cfg(not(windows))] - fn get_err(errno: i32) -> (IoErrorKind, &'static str) { - // FIXME: this should probably be a bit more descriptive... - match errno { - libc::EOF => (EndOfFile, "end of file"), - libc::ECONNREFUSED => (ConnectionRefused, "connection refused"), - libc::ECONNRESET => (ConnectionReset, "connection reset"), - libc::EPERM | libc::EACCES => - (PermissionDenied, "permission denied"), - libc::EPIPE => (BrokenPipe, "broken pipe"), - libc::ENOTCONN => (NotConnected, "not connected"), - libc::ECONNABORTED => (ConnectionAborted, "connection aborted"), - libc::EADDRNOTAVAIL => (ConnectionRefused, "address not available"), - libc::EADDRINUSE => (ConnectionRefused, "address in use"), - libc::ENOENT => (FileNotFound, "no such file or directory"), - libc::EISDIR => (InvalidInput, "illegal operation on a directory"), - libc::ENOSYS => (IoUnavailable, "function not implemented"), - libc::EINVAL => (InvalidInput, "invalid argument"), - libc::ENOTTY => - (MismatchedFileTypeForOperation, - "file descriptor is not a TTY"), - libc::ETIMEDOUT => (TimedOut, "operation timed out"), - libc::ECANCELED => (TimedOut, "operation aborted"), - - // These two constants can have the same value on some systems, - // but different values on others, so we can't use a match - // clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => - (ResourceUnavailable, "resource temporarily unavailable"), - - _ => (OtherIoError, "unknown error") - } - } - - let (kind, desc) = get_err(errno as i32); - IoError { - kind: kind, - desc: desc, - detail: if detail && kind == OtherIoError { - Some(os::error_string(errno).as_slice().chars().map(|c| c.to_lowercase()).collect()) - } else { - None - }, + let mut err = sys::decode_error(errno as i32); + if detail && err.kind == OtherIoError { + err.detail = Some(os::error_string(errno).as_slice().chars() + .map(|c| c.to_lowercase()).collect()) } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f10a1d5e5ed..7eac455f97f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -242,6 +242,13 @@ pub mod io; pub mod path; pub mod fmt; +#[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; + // FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable' // but name resolution doesn't work without it being pub. pub mod rt; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 0042a3ae205..175e23bf819 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -34,7 +34,7 @@ use clone::Clone; use error::{FromError, Error}; use fmt; -use io::{IoResult, IoError}; +use io::IoResult; use iter::Iterator; use libc::{c_void, c_int}; use libc; @@ -43,6 +43,7 @@ use ops::Drop; use option::{Some, None, Option}; use os; use path::{Path, GenericPath, BytesContainer}; +use sys::os as os_imp; use ptr::RawPtr; use ptr; use result::{Err, Ok, Result}; @@ -905,59 +906,9 @@ pub fn change_dir(p: &Path) -> bool { } } -#[cfg(unix)] -/// Returns the platform-specific value of errno -pub fn errno() -> int { - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd"))] - fn errno_location() -> *const c_int { - extern { - fn __error() -> *const c_int; - } - unsafe { - __error() - } - } - - #[cfg(target_os = "dragonfly")] - fn errno_location() -> *const c_int { - extern { - fn __dfly_error() -> *const c_int; - } - unsafe { - __dfly_error() - } - } - - #[cfg(any(target_os = "linux", target_os = "android"))] - fn errno_location() -> *const c_int { - extern { - fn __errno_location() -> *const c_int; - } - unsafe { - __errno_location() - } - } - - unsafe { - (*errno_location()) as int - } -} - -#[cfg(windows)] /// Returns the platform-specific value of errno pub fn errno() -> uint { - use libc::types::os::arch::extra::DWORD; - - #[link_name = "kernel32"] - extern "system" { - fn GetLastError() -> DWORD; - } - - unsafe { - GetLastError() as uint - } + os_imp::errno() as uint } /// Return the string corresponding to an `errno()` value of `errnum`. @@ -969,105 +920,7 @@ pub fn errno() -> uint { /// println!("{}", os::error_string(os::errno() as uint)); /// ``` pub fn error_string(errnum: uint) -> String { - return strerror(errnum); - - #[cfg(unix)] - fn strerror(errnum: uint) -> String { - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly"))] - fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) - -> c_int { - extern { - fn strerror_r(errnum: c_int, buf: *mut c_char, - buflen: libc::size_t) -> c_int; - } - unsafe { - strerror_r(errnum, buf, buflen) - } - } - - // GNU libc provides a non-compliant version of strerror_r by default - // and requires macros to instead use the POSIX compliant variant. - // So we just use __xpg_strerror_r which is always POSIX compliant - #[cfg(target_os = "linux")] - fn strerror_r(errnum: c_int, buf: *mut c_char, - buflen: libc::size_t) -> c_int { - extern { - fn __xpg_strerror_r(errnum: c_int, - buf: *mut c_char, - buflen: libc::size_t) - -> c_int; - } - unsafe { - __xpg_strerror_r(errnum, buf, buflen) - } - } - - let mut buf = [0 as c_char, ..TMPBUF_SZ]; - - let p = buf.as_mut_ptr(); - unsafe { - if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 { - panic!("strerror_r failure"); - } - - ::string::raw::from_buf(p as *const u8) - } - } - - #[cfg(windows)] - fn strerror(errnum: uint) -> String { - use libc::types::os::arch::extra::DWORD; - use libc::types::os::arch::extra::LPWSTR; - use libc::types::os::arch::extra::LPVOID; - use libc::types::os::arch::extra::WCHAR; - - #[link_name = "kernel32"] - extern "system" { - fn FormatMessageW(flags: DWORD, - lpSrc: LPVOID, - msgId: DWORD, - langId: DWORD, - buf: LPWSTR, - nsize: DWORD, - args: *const c_void) - -> DWORD; - } - - static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; - static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; - - // This value is calculated from the macro - // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) - let langId = 0x0800 as DWORD; - - let mut buf = [0 as WCHAR, ..TMPBUF_SZ]; - - unsafe { - let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - ptr::null_mut(), - errnum as DWORD, - langId, - buf.as_mut_ptr(), - buf.len() as DWORD, - ptr::null()); - if res == 0 { - // Sometimes FormatMessageW can fail e.g. system doesn't like langId, - let fm_err = errno(); - return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err); - } - - let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf)); - match msg { - Some(msg) => format!("OS Error {}: {}", errnum, msg), - None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum), - } - } - } + return os_imp::error_string(errnum as i32); } /// Get a string representing the platform-dependent last error diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs new file mode 100644 index 00000000000..402c62bb35e --- /dev/null +++ b/src/libstd/sys/common/mod.rs @@ -0,0 +1,91 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(missing_doc)] +#![allow(dead_code)] + +use io::{mod, IoError, IoResult}; +use prelude::*; +use num; +use sys::{last_error, retry, fs}; +use c_str::CString; +use path::BytesContainer; +use collections; + +pub mod net; + +// common error constructors + +pub fn eof() -> IoError { + IoError { + kind: io::EndOfFile, + desc: "end of file", + detail: None, + } +} + +pub fn timeout(desc: &'static str) -> IoError { + IoError { + kind: io::TimedOut, + desc: desc, + detail: None, + } +} + +pub fn short_write(n: uint, desc: &'static str) -> IoError { + IoError { + kind: if n == 0 { io::TimedOut } else { io::ShortWrite(n) }, + desc: desc, + detail: None, + } +} + +// unix has nonzero values as errors +pub fn mkerr_libc(ret: Int) -> IoResult<()> { + if !ret.is_zero() { + Err(last_error()) + } else { + Ok(()) + } +} + +pub fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 { + let origamt = data.len(); + let mut data = data.as_ptr(); + let mut amt = origamt; + while amt > 0 { + let ret = retry(|| f(data, amt)); + if ret == 0 { + break + } else if ret != -1 { + amt -= ret as uint; + data = unsafe { data.offset(ret as int) }; + } else { + return ret; + } + } + return (origamt - amt) as i64; +} + +// traits for extracting representations from + +pub trait AsFileDesc { + fn as_fd(&self) -> &fs::FileDesc; +} + +pub trait ProcessConfig { + fn program(&self) -> &CString; + fn args(&self) -> &[CString]; + fn env(&self) -> Option<&collections::HashMap>; + fn cwd(&self) -> Option<&CString>; + fn uid(&self) -> Option; + fn gid(&self) -> Option; + fn detach(&self) -> bool; +} diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs new file mode 100644 index 00000000000..e76f2a2b872 --- /dev/null +++ b/src/libstd/sys/unix/c.rs @@ -0,0 +1,262 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! C definitions used by libnative that don't belong in liblibc + +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +pub use self::select::fd_set; +pub use self::signal::{sigaction, siginfo, sigset_t}; +pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP}; +pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD}; + +use libc; + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub const FIONBIO: libc::c_ulong = 0x8004667e; +#[cfg(any(all(target_os = "linux", + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm")), + target_os = "android"))] +pub const FIONBIO: libc::c_ulong = 0x5421; +#[cfg(all(target_os = "linux", + any(target_arch = "mips", target_arch = "mipsel")))] +pub const FIONBIO: libc::c_ulong = 0x667e; + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub const FIOCLEX: libc::c_ulong = 0x20006601; +#[cfg(any(all(target_os = "linux", + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm")), + target_os = "android"))] +pub const FIOCLEX: libc::c_ulong = 0x5451; +#[cfg(all(target_os = "linux", + any(target_arch = "mips", target_arch = "mipsel")))] +pub const FIOCLEX: libc::c_ulong = 0x6601; + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub const MSG_DONTWAIT: libc::c_int = 0x80; +#[cfg(any(target_os = "linux", target_os = "android"))] +pub const MSG_DONTWAIT: libc::c_int = 0x40; + +pub const WNOHANG: libc::c_int = 1; + +extern { + pub fn gettimeofday(timeval: *mut libc::timeval, + tzp: *mut libc::c_void) -> libc::c_int; + pub fn select(nfds: libc::c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut libc::timeval) -> libc::c_int; + pub fn getsockopt(sockfd: libc::c_int, + level: libc::c_int, + optname: libc::c_int, + optval: *mut libc::c_void, + optlen: *mut libc::socklen_t) -> libc::c_int; + pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int; + + + pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int, + options: libc::c_int) -> libc::pid_t; + + pub fn sigaction(signum: libc::c_int, + act: *const sigaction, + oldact: *mut sigaction) -> libc::c_int; + + pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; + pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; + pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int; +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod select { + pub const FD_SETSIZE: uint = 1024; + + #[repr(C)] + pub struct fd_set { + fds_bits: [i32, ..(FD_SETSIZE / 32)] + } + + pub fn fd_set(set: &mut fd_set, fd: i32) { + set.fds_bits[(fd / 32) as uint] |= 1 << ((fd % 32) as uint); + } +} + +#[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux"))] +mod select { + use uint; + use libc; + + pub const FD_SETSIZE: uint = 1024; + + #[repr(C)] + pub struct fd_set { + // FIXME: shouldn't this be a c_ulong? + fds_bits: [libc::uintptr_t, ..(FD_SETSIZE / uint::BITS)] + } + + pub fn fd_set(set: &mut fd_set, fd: i32) { + let fd = fd as uint; + set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS); + } +} + +#[cfg(any(all(target_os = "linux", + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm")), + target_os = "android"))] +mod signal { + use libc; + + pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; + pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002; + pub const SA_NODEFER: libc::c_ulong = 0x40000000; + pub const SA_ONSTACK: libc::c_ulong = 0x08000000; + pub const SA_RESETHAND: libc::c_ulong = 0x80000000; + pub const SA_RESTART: libc::c_ulong = 0x10000000; + pub const SA_SIGINFO: libc::c_ulong = 0x00000004; + pub const SIGCHLD: libc::c_int = 17; + + // This definition is not as accurate as it could be, {pid, uid, status} is + // actually a giant union. Currently we're only interested in these fields, + // however. + #[repr(C)] + pub struct siginfo { + si_signo: libc::c_int, + si_errno: libc::c_int, + si_code: libc::c_int, + pub pid: libc::pid_t, + pub uid: libc::uid_t, + pub status: libc::c_int, + } + + #[repr(C)] + pub struct sigaction { + pub sa_handler: extern fn(libc::c_int), + pub sa_mask: sigset_t, + pub sa_flags: libc::c_ulong, + sa_restorer: *mut libc::c_void, + } + + #[repr(C)] + #[cfg(target_word_size = "32")] + pub struct sigset_t { + __val: [libc::c_ulong, ..32], + } + + #[repr(C)] + #[cfg(target_word_size = "64")] + pub struct sigset_t { + __val: [libc::c_ulong, ..16], + } +} + +#[cfg(all(target_os = "linux", + any(target_arch = "mips", target_arch = "mipsel")))] +mod signal { + use libc; + + pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; + pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000; + pub const SA_NODEFER: libc::c_ulong = 0x40000000; + pub const SA_ONSTACK: libc::c_ulong = 0x08000000; + pub const SA_RESETHAND: libc::c_ulong = 0x80000000; + pub const SA_RESTART: libc::c_ulong = 0x10000000; + pub const SA_SIGINFO: libc::c_ulong = 0x00000008; + pub const SIGCHLD: libc::c_int = 18; + + // This definition is not as accurate as it could be, {pid, uid, status} is + // actually a giant union. Currently we're only interested in these fields, + // however. + #[repr(C)] + pub struct siginfo { + si_signo: libc::c_int, + si_code: libc::c_int, + si_errno: libc::c_int, + pub pid: libc::pid_t, + pub uid: libc::uid_t, + pub status: libc::c_int, + } + + #[repr(C)] + pub struct sigaction { + pub sa_flags: libc::c_uint, + pub sa_handler: extern fn(libc::c_int), + pub sa_mask: sigset_t, + sa_restorer: *mut libc::c_void, + sa_resv: [libc::c_int, ..1], + } + + #[repr(C)] + pub struct sigset_t { + __val: [libc::c_ulong, ..32], + } +} + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +mod signal { + use libc; + + pub const SA_ONSTACK: libc::c_int = 0x0001; + pub const SA_RESTART: libc::c_int = 0x0002; + pub const SA_RESETHAND: libc::c_int = 0x0004; + pub const SA_NOCLDSTOP: libc::c_int = 0x0008; + pub const SA_NODEFER: libc::c_int = 0x0010; + pub const SA_NOCLDWAIT: libc::c_int = 0x0020; + pub const SA_SIGINFO: libc::c_int = 0x0040; + pub const SIGCHLD: libc::c_int = 20; + + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub type sigset_t = u32; + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[repr(C)] + pub struct sigset_t { + bits: [u32, ..4], + } + + // This structure has more fields, but we're not all that interested in + // them. + #[repr(C)] + pub struct siginfo { + pub si_signo: libc::c_int, + pub si_errno: libc::c_int, + pub si_code: libc::c_int, + pub pid: libc::pid_t, + pub uid: libc::uid_t, + pub status: libc::c_int, + } + + #[repr(C)] + pub struct sigaction { + pub sa_handler: extern fn(libc::c_int), + pub sa_flags: libc::c_int, + pub sa_mask: sigset_t, + } +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs new file mode 100644 index 00000000000..ad5de2dad48 --- /dev/null +++ b/src/libstd/sys/unix/mod.rs @@ -0,0 +1,92 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate libc; + +use num; +use prelude::*; +use io::{mod, IoResult, IoError}; + +pub mod fs; +pub mod os; +pub mod c; + +pub type sock_t = io::file::fd_t; +pub type wrlen = libc::size_t; +pub unsafe fn close_sock(sock: sock_t) { let _ = libc::close(sock); } + +pub fn last_error() -> IoError { + let errno = os::errno() as i32; + let mut err = decode_error(errno); + err.detail = Some(os::error_string(errno)); + err +} + +/// Convert an `errno` value into a high-level error variant and description. +pub fn decode_error(errno: i32) -> IoError { + // FIXME: this should probably be a bit more descriptive... + let (kind, desc) = match errno { + libc::EOF => (io::EndOfFile, "end of file"), + libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"), + libc::ECONNRESET => (io::ConnectionReset, "connection reset"), + libc::EPERM | libc::EACCES => + (io::PermissionDenied, "permission denied"), + libc::EPIPE => (io::BrokenPipe, "broken pipe"), + libc::ENOTCONN => (io::NotConnected, "not connected"), + libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"), + libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), + libc::EADDRINUSE => (io::ConnectionRefused, "address in use"), + libc::ENOENT => (io::FileNotFound, "no such file or directory"), + libc::EISDIR => (io::InvalidInput, "illegal operation on a directory"), + libc::ENOSYS => (io::IoUnavailable, "function not implemented"), + libc::EINVAL => (io::InvalidInput, "invalid argument"), + libc::ENOTTY => + (io::MismatchedFileTypeForOperation, + "file descriptor is not a TTY"), + libc::ETIMEDOUT => (io::TimedOut, "operation timed out"), + libc::ECANCELED => (io::TimedOut, "operation aborted"), + + // These two constants can have the same value on some systems, + // but different values on others, so we can't use a match + // clause + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => + (io::ResourceUnavailable, "resource temporarily unavailable"), + + _ => (io::OtherIoError, "unknown error") + }; + IoError { kind: kind, desc: desc, detail: None } +} + +#[inline] +pub fn retry> (f: || -> I) -> I { + let minus_one = -num::one::(); + loop { + let n = f(); + if n == minus_one && os::errno() == libc::EINTR as int { } + else { return n } + } +} + +pub fn ms_to_timeval(ms: u64) -> libc::timeval { + libc::timeval { + tv_sec: (ms / 1000) as libc::time_t, + tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t, + } +} + +pub fn wouldblock() -> bool { + let err = os::errno(); + err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int +} + +pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> { + let set = nb as libc::c_int; + super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) })) +} diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs new file mode 100644 index 00000000000..34699eb27c1 --- /dev/null +++ b/src/libstd/sys/unix/os.rs @@ -0,0 +1,101 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc; +use libc::{c_int, c_char}; +use prelude::*; + +use os::TMPBUF_SZ; + +/// Returns the platform-specific value of errno +pub fn errno() -> int { + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd"))] + fn errno_location() -> *const c_int { + extern { + fn __error() -> *const c_int; + } + unsafe { + __error() + } + } + + #[cfg(target_os = "dragonfly")] + fn errno_location() -> *const c_int { + extern { + fn __dfly_error() -> *const c_int; + } + unsafe { + __dfly_error() + } + } + + #[cfg(any(target_os = "linux", target_os = "android"))] + fn errno_location() -> *const c_int { + extern { + fn __errno_location() -> *const c_int; + } + unsafe { + __errno_location() + } + } + + unsafe { + (*errno_location()) as int + } +} + +/// Get a detailed string description for the given error number +pub fn error_string(errno: i32) -> String { + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "freebsd", + target_os = "dragonfly"))] + fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) + -> c_int { + extern { + fn strerror_r(errnum: c_int, buf: *mut c_char, + buflen: libc::size_t) -> c_int; + } + unsafe { + strerror_r(errnum, buf, buflen) + } + } + + // GNU libc provides a non-compliant version of strerror_r by default + // and requires macros to instead use the POSIX compliant variant. + // So we just use __xpg_strerror_r which is always POSIX compliant + #[cfg(target_os = "linux")] + fn strerror_r(errnum: c_int, buf: *mut c_char, + buflen: libc::size_t) -> c_int { + extern { + fn __xpg_strerror_r(errnum: c_int, + buf: *mut c_char, + buflen: libc::size_t) + -> c_int; + } + unsafe { + __xpg_strerror_r(errnum, buf, buflen) + } + } + + let mut buf = [0 as c_char, ..TMPBUF_SZ]; + + let p = buf.as_mut_ptr(); + unsafe { + if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 { + panic!("strerror_r failure"); + } + + ::string::raw::from_buf(p as *const u8) + } +} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs new file mode 100644 index 00000000000..b8e9b1dca3a --- /dev/null +++ b/src/libstd/sys/windows/c.rs @@ -0,0 +1,250 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! C definitions used by libnative that don't belong in liblibc + +#![allow(overflowing_literals)] +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +use libc; +use prelude::*; + +pub const WSADESCRIPTION_LEN: uint = 256; +pub const WSASYS_STATUS_LEN: uint = 128; +pub const FIONBIO: libc::c_long = 0x8004667e; +pub const FD_SETSIZE: uint = 64; +pub const MSG_DONTWAIT: libc::c_int = 0; +pub const ERROR_ILLEGAL_CHARACTER: libc::c_int = 582; +pub const ENABLE_ECHO_INPUT: libc::DWORD = 0x4; +pub const ENABLE_EXTENDED_FLAGS: libc::DWORD = 0x80; +pub const ENABLE_INSERT_MODE: libc::DWORD = 0x20; +pub const ENABLE_LINE_INPUT: libc::DWORD = 0x2; +pub const ENABLE_PROCESSED_INPUT: libc::DWORD = 0x1; +pub const ENABLE_QUICK_EDIT_MODE: libc::DWORD = 0x40; +pub const WSA_INVALID_EVENT: WSAEVENT = 0 as WSAEVENT; + +pub const FD_ACCEPT: libc::c_long = 0x08; +pub const FD_MAX_EVENTS: uint = 10; +pub const WSA_INFINITE: libc::DWORD = libc::INFINITE; +pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT; +pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0; +pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED; + +#[repr(C)] +#[cfg(target_arch = "x86")] +pub struct WSADATA { + pub wVersion: libc::WORD, + pub wHighVersion: libc::WORD, + pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], + pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: *mut u8, +} +#[repr(C)] +#[cfg(target_arch = "x86_64")] +pub struct WSADATA { + pub wVersion: libc::WORD, + pub wHighVersion: libc::WORD, + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: *mut u8, + pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], + pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], +} + +pub type LPWSADATA = *mut WSADATA; + +#[repr(C)] +pub struct WSANETWORKEVENTS { + pub lNetworkEvents: libc::c_long, + pub iErrorCode: [libc::c_int, ..FD_MAX_EVENTS], +} + +pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS; + +pub type WSAEVENT = libc::HANDLE; + +#[repr(C)] +pub struct fd_set { + fd_count: libc::c_uint, + fd_array: [libc::SOCKET, ..FD_SETSIZE], +} + +pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) { + set.fd_array[set.fd_count as uint] = s; + set.fd_count += 1; +} + +#[link(name = "ws2_32")] +extern "system" { + pub fn WSAStartup(wVersionRequested: libc::WORD, + lpWSAData: LPWSADATA) -> libc::c_int; + pub fn WSAGetLastError() -> libc::c_int; + pub fn WSACloseEvent(hEvent: WSAEVENT) -> libc::BOOL; + pub fn WSACreateEvent() -> WSAEVENT; + pub fn WSAEventSelect(s: libc::SOCKET, + hEventObject: WSAEVENT, + lNetworkEvents: libc::c_long) -> libc::c_int; + pub fn WSASetEvent(hEvent: WSAEVENT) -> libc::BOOL; + pub fn WSAWaitForMultipleEvents(cEvents: libc::DWORD, + lphEvents: *const WSAEVENT, + fWaitAll: libc::BOOL, + dwTimeout: libc::DWORD, + fAltertable: libc::BOOL) -> libc::DWORD; + pub fn WSAEnumNetworkEvents(s: libc::SOCKET, + hEventObject: WSAEVENT, + lpNetworkEvents: LPWSANETWORKEVENTS) + -> libc::c_int; + + pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long, + argp: *mut libc::c_ulong) -> libc::c_int; + pub fn select(nfds: libc::c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + exceptfds: *mut fd_set, + timeout: *mut libc::timeval) -> libc::c_int; + pub fn getsockopt(sockfd: libc::SOCKET, + level: libc::c_int, + optname: libc::c_int, + optval: *mut libc::c_char, + optlen: *mut libc::c_int) -> libc::c_int; + + pub fn SetEvent(hEvent: libc::HANDLE) -> libc::BOOL; + pub fn WaitForMultipleObjects(nCount: libc::DWORD, + lpHandles: *const libc::HANDLE, + bWaitAll: libc::BOOL, + dwMilliseconds: libc::DWORD) -> libc::DWORD; + + pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL; + pub fn CancelIoEx(hFile: libc::HANDLE, + lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; +} + +pub mod compat { + use intrinsics::{atomic_store_relaxed, transmute}; + use iter::Iterator; + use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; + use prelude::*; + + extern "system" { + fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; + fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; + } + + // store_func() is idempotent, so using relaxed ordering for the atomics + // should be enough. This way, calling a function in this compatibility + // layer (after it's loaded) shouldn't be any slower than a regular DLL + // call. + unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) { + let mut module: Vec = module.utf16_units().collect(); + module.push(0); + symbol.with_c_str(|symbol| { + let handle = GetModuleHandleW(module.as_ptr()); + let func: uint = transmute(GetProcAddress(handle, symbol)); + atomic_store_relaxed(ptr, if func == 0 { + fallback + } else { + func + }) + }) + } + + /// Macro for creating a compatibility fallback for a Windows function + /// + /// # Example + /// ``` + /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) { + /// // Fallback implementation + /// }) + /// ``` + /// + /// Note that arguments unused by the fallback implementation should not be called `_` as + /// they are used to be passed to the real function if available. + macro_rules! compat_fn( + ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) + -> $rettype:ty $fallback:block) => ( + #[inline(always)] + pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { + static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk; + + extern "system" fn thunk($($argname: $argtype),*) -> $rettype { + unsafe { + ::sys::c::compat::store_func(&mut ptr as *mut _ as *mut uint, + stringify!($module), + stringify!($symbol), + fallback as uint); + ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) + } + } + + extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback + + ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) + } + ); + + ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => ( + compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback) + ) + ) + + /// Compatibility layer for functions in `kernel32.dll` + /// + /// Latest versions of Windows this is needed for: + /// + /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003 + /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003 + pub mod kernel32 { + use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE}; + use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED; + + extern "system" { + fn SetLastError(dwErrCode: DWORD); + } + + compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, + _lpTargetFileName: LPCWSTR, + _dwFlags: DWORD) -> BOOLEAN { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } + 0 + }) + + compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE, + _lpszFilePath: LPCWSTR, + _cchFilePath: DWORD, + _dwFlags: DWORD) -> DWORD { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } + 0 + }) + } +} + +extern "system" { + // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL + pub fn ReadConsoleW(hConsoleInput: libc::HANDLE, + lpBuffer: libc::LPVOID, + nNumberOfCharsToRead: libc::DWORD, + lpNumberOfCharsRead: libc::LPDWORD, + pInputControl: libc::LPVOID) -> libc::BOOL; + + pub fn WriteConsoleW(hConsoleOutput: libc::HANDLE, + lpBuffer: libc::types::os::arch::extra::LPCVOID, + nNumberOfCharsToWrite: libc::DWORD, + lpNumberOfCharsWritten: libc::LPDWORD, + lpReserved: libc::LPVOID) -> libc::BOOL; + + pub fn GetConsoleMode(hConsoleHandle: libc::HANDLE, + lpMode: libc::LPDWORD) -> libc::BOOL; + + pub fn SetConsoleMode(hConsoleHandle: libc::HANDLE, + lpMode: libc::DWORD) -> libc::BOOL; +} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs new file mode 100644 index 00000000000..5f4129c1484 --- /dev/null +++ b/src/libstd/sys/windows/mod.rs @@ -0,0 +1,178 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(missing_doc)] +#![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: ::rt::mutex::NATIVE_MUTEX_INIT, + chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, + signal: ::cell::UnsafeCell { value: 0 }, + initialized: ::cell::UnsafeCell { value: false }, + }; +) ) + +pub mod fs; +pub mod os; +pub mod c; + +pub type sock_t = libc::SOCKET; +pub type wrlen = libc::c_int; +pub unsafe fn close_sock(sock: sock_t) { let _ = libc::closesocket(sock); } + +// windows has zero values as errors +fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> { + if ret == 0 { + Err(last_error()) + } else { + Ok(()) + } +} + +pub fn last_error() -> IoError { + let errno = os::errno() as i32; + let mut err = decode_error(errno); + err.detail = Some(os::error_string(errno)); + err +} + +pub fn last_net_error() -> IoError { + let errno = unsafe { c::WSAGetLastError() as i32 }; + let mut err = decode_error(errno); + err.detail = Some(os::error_string(errno)); + err +} + +pub fn last_gai_error(_errno: i32) -> IoError { + last_net_error() +} + +/// Convert an `errno` value into a high-level error variant and description. +pub fn decode_error(errno: i32) -> IoError { + let (kind, desc) = match errno { + libc::EOF => (io::EndOfFile, "end of file"), + libc::ERROR_NO_DATA => (io::BrokenPipe, "the pipe is being closed"), + libc::ERROR_FILE_NOT_FOUND => (io::FileNotFound, "file not found"), + libc::ERROR_INVALID_NAME => (io::InvalidInput, "invalid file name"), + libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"), + libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"), + libc::ERROR_ACCESS_DENIED | libc::WSAEACCES => + (io::PermissionDenied, "permission denied"), + libc::WSAEWOULDBLOCK => { + (io::ResourceUnavailable, "resource temporarily unavailable") + } + libc::WSAENOTCONN => (io::NotConnected, "not connected"), + libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"), + libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"), + libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"), + libc::ERROR_BROKEN_PIPE => (io::EndOfFile, "the pipe has ended"), + libc::ERROR_OPERATION_ABORTED => + (io::TimedOut, "operation timed out"), + libc::WSAEINVAL => (io::InvalidInput, "invalid argument"), + libc::ERROR_CALL_NOT_IMPLEMENTED => + (io::IoUnavailable, "function not implemented"), + libc::ERROR_INVALID_HANDLE => + (io::MismatchedFileTypeForOperation, + "invalid handle provided to function"), + libc::ERROR_NOTHING_TO_TERMINATE => + (io::InvalidInput, "no process to kill"), + + // libuv maps this error code to EISDIR. we do too. if it is found + // to be incorrect, we can add in some more machinery to only + // return this message when ERROR_INVALID_FUNCTION after certain + // Windows calls. + libc::ERROR_INVALID_FUNCTION => (io::InvalidInput, + "illegal operation on a directory"), + + _ => (io::OtherIoError, "unknown error") + }; + IoError { kind: kind, desc: desc, detail: None } +} + +pub fn decode_error_detailed(errno: i32) -> IoError { + let mut err = decode_error(errno); + err.detail = Some(os::error_string(errno)); + err +} + +#[inline] +pub fn retry (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020 + +pub fn ms_to_timeval(ms: u64) -> libc::timeval { + libc::timeval { + tv_sec: (ms / 1000) as libc::c_long, + tv_usec: ((ms % 1000) * 1000) as libc::c_long, + } +} + +pub fn wouldblock() -> bool { + let err = os::errno(); + err == libc::WSAEWOULDBLOCK as uint +} + +pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> { + let mut set = nb as libc::c_ulong; + if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } { + Err(last_error()) + } else { + Ok(()) + } +} + +// FIXME: call this +pub fn init_net() { + unsafe { + static START: Once = ONCE_INIT; + + START.doit(|| { + let mut data: c::WSADATA = mem::zeroed(); + let ret = c::WSAStartup(0x202, // version 2.2 + &mut data); + assert_eq!(ret, 0); + }); + } +} + +pub fn unimpl() -> IoError { + IoError { + kind: io::IoUnavailable, + desc: "operation is not implemented", + detail: None, + } +} + +pub fn to_utf16(s: Option<&str>) -> IoResult> { + match s { + Some(s) => Ok({ + let mut s = s.utf16_units().collect::>(); + s.push(0); + s + }), + None => Err(IoError { + kind: io::InvalidInput, + desc: "valid unicode input required", + detail: None + }) + } +} diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs new file mode 100644 index 00000000000..aaa1aaf6327 --- /dev/null +++ b/src/libstd/sys/windows/os.rs @@ -0,0 +1,103 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// FIXME: move various extern bindings from here into liblibc or +// something similar + +use libc; +use libc::{c_int, c_char, c_void}; +use prelude::*; +use io::{IoResult, IoError}; +use sys::fs::FileDesc; +use ptr; + +use os::TMPBUF_SZ; + +pub fn errno() -> uint { + use libc::types::os::arch::extra::DWORD; + + #[link_name = "kernel32"] + extern "system" { + fn GetLastError() -> DWORD; + } + + unsafe { + GetLastError() as uint + } +} + +/// Get a detailed string description for the given error number +pub fn error_string(errnum: i32) -> String { + use libc::types::os::arch::extra::DWORD; + use libc::types::os::arch::extra::LPWSTR; + use libc::types::os::arch::extra::LPVOID; + use libc::types::os::arch::extra::WCHAR; + + #[link_name = "kernel32"] + extern "system" { + fn FormatMessageW(flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const c_void) + -> DWORD; + } + + static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; + static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; + + // This value is calculated from the macro + // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) + let langId = 0x0800 as DWORD; + + let mut buf = [0 as WCHAR, ..TMPBUF_SZ]; + + unsafe { + let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + ptr::null_mut(), + errnum as DWORD, + langId, + buf.as_mut_ptr(), + buf.len() as DWORD, + ptr::null()); + if res == 0 { + // Sometimes FormatMessageW can fail e.g. system doesn't like langId, + let fm_err = errno(); + return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err); + } + + let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf)); + match msg { + Some(msg) => format!("OS Error {}: {}", errnum, msg), + None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum), + } + } +} + +pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { + // Windows pipes work subtly differently than unix pipes, and their + // inheritance has to be handled in a different way that I do not + // fully understand. Here we explicitly make the pipe non-inheritable, + // which means to pass it to a subprocess they need to be duplicated + // first, as in std::run. + let mut fds = [0, ..2]; + match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint, + (libc::O_BINARY | libc::O_NOINHERIT) as c_int) { + 0 => { + assert!(fds[0] != -1 && fds[0] != 0); + assert!(fds[1] != -1 && fds[1] != 0); + Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true))) + } + _ => Err(IoError::last_error()), + } +} -- cgit 1.4.1-3-g733a5