Turn std_detect into a no_std crate (#1005)

This commit is contained in:
Amanieu d'Antras 2021-02-14 22:14:37 +00:00 committed by GitHub
parent b7acc2e1da
commit f32f7cb899
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 165 additions and 95 deletions

View file

@ -3,9 +3,9 @@
#![allow(dead_code)] // not used on all platforms
use crate::sync::atomic::Ordering;
use core::sync::atomic::Ordering;
use crate::sync::atomic::AtomicUsize;
use core::sync::atomic::AtomicUsize;
/// Sets the `bit` of `x`.
#[inline]
@ -125,9 +125,16 @@ cfg_if::cfg_if! {
if #[cfg(feature = "std_detect_env_override")] {
#[inline]
fn initialize(mut value: Initializer) -> Initializer {
if let Ok(disable) = crate::env::var("RUST_STD_DETECT_UNSTABLE") {
for v in disable.split(" ") {
let _ = super::Feature::from_str(v).map(|v| value.unset(v as u32));
let env = unsafe {
libc::getenv(b"RUST_STD_DETECT_UNSTABLE\0".as_ptr() as *const libc::c_char)
};
if !env.is_null() {
let len = unsafe { libc::strlen(env) };
let env = unsafe { core::slice::from_raw_parts(env as *const u8, len) };
if let Ok(disable) = core::str::from_utf8(env) {
for v in disable.split(" ") {
let _ = super::Feature::from_str(v).map(|v| value.unset(v as u32));
}
}
}
do_initialize(value);

View file

@ -98,10 +98,10 @@ cfg_if! {
// On x86/x86_64 no OS specific functionality is required.
#[path = "os/x86.rs"]
mod os;
} else if #[cfg(all(target_os = "linux", feature = "use_std"))] {
} else if #[cfg(all(target_os = "linux", feature = "libc"))] {
#[path = "os/linux/mod.rs"]
mod os;
} else if #[cfg(all(target_os = "freebsd", feature = "use_std"))] {
} else if #[cfg(all(target_os = "freebsd", feature = "libc"))] {
#[cfg(target_arch = "aarch64")]
#[path = "os/aarch64.rs"]
mod aarch64;
@ -140,7 +140,7 @@ pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
target_arch = "mips64",
))] {
(0_u8..Feature::_last as u8).map(|discriminant: u8| {
let f: Feature = unsafe { crate::mem::transmute(discriminant) };
let f: Feature = unsafe { core::mem::transmute(discriminant) };
let name: &'static str = f.to_str();
let enabled: bool = check_for(f);
(name, enabled)

View file

@ -42,7 +42,7 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
/// Tries to read the `key` from the auxiliary vector.
fn archauxv(key: usize) -> Result<usize, ()> {
use crate::mem;
use core::mem;
#[derive(Copy, Clone)]
#[repr(C)]

View file

@ -5,18 +5,18 @@ mod auxvec;
cfg_if::cfg_if! {
if #[cfg(target_arch = "aarch64")] {
mod aarch64;
pub use self::aarch64::check_for;
pub(crate) use self::aarch64::detect_features;
} else if #[cfg(target_arch = "arm")] {
mod arm;
pub use self::arm::check_for;
pub(crate) use self::arm::detect_features;
} else if #[cfg(target_arch = "powerpc64")] {
mod powerpc;
pub use self::powerpc::check_for;
pub(crate) use self::powerpc::detect_features;
} else {
use crate::arch::detect::Feature;
use crate::detect::cache;
/// Performs run-time feature detection.
pub fn check_for(_x: Feature) -> bool {
false
pub(crate) fn detect_features() -> cache::Initializer {
cache::Initializer::default()
}
}
}

View file

@ -1,6 +1,6 @@
//! Run-time feature detection for Aarch64 on Linux.
use super::{auxvec, cpuinfo};
use super::auxvec;
use crate::detect::{bit, cache, Feature};
/// Try to read the features from the auxiliary vector, and if that fails, try
@ -10,7 +10,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
let hwcap: AtHwcap = auxv.into();
return hwcap.cache();
}
if let Ok(c) = cpuinfo::CpuInfo::new() {
#[cfg(feature = "std_detect_file_io")]
if let Ok(c) = super::cpuinfo::CpuInfo::new() {
let hwcap: AtHwcap = c.into();
return hwcap.cache();
}
@ -77,9 +78,10 @@ impl From<auxvec::AuxVec> for AtHwcap {
}
}
impl From<cpuinfo::CpuInfo> for AtHwcap {
#[cfg(feature = "std_detect_file_io")]
impl From<super::cpuinfo::CpuInfo> for AtHwcap {
/// Reads AtHwcap from /proc/cpuinfo .
fn from(c: cpuinfo::CpuInfo) -> Self {
fn from(c: super::cpuinfo::CpuInfo) -> Self {
let f = &c.field("Features");
AtHwcap {
// 64-bit names. FIXME: In 32-bit compatibility mode /proc/cpuinfo will

View file

@ -1,6 +1,6 @@
//! Run-time feature detection for ARM on Linux.
use super::{auxvec, cpuinfo};
use super::auxvec;
use crate::detect::{bit, cache, Feature};
/// Try to read the features from the auxiliary vector, and if that fails, try
@ -31,7 +31,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
return value;
}
if let Ok(c) = cpuinfo::CpuInfo::new() {
#[cfg(feature = "std_detect_file_io")]
if let Ok(c) = super::cpuinfo::CpuInfo::new() {
enable_feature(
&mut value,
Feature::neon,
@ -55,7 +56,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
/// Is the CPU known to have a broken NEON unit?
///
/// See https://crbug.com/341598.
fn has_broken_neon(cpuinfo: &cpuinfo::CpuInfo) -> bool {
#[cfg(feature = "std_detect_file_io")]
fn has_broken_neon(cpuinfo: &super::cpuinfo::CpuInfo) -> bool {
cpuinfo.field("CPU implementer") == "0x51"
&& cpuinfo.field("CPU architecture") == "7"
&& cpuinfo.field("CPU variant") == "0x1"

View file

@ -1,13 +1,16 @@
//! Parses ELF auxiliary vectors.
#![cfg_attr(not(target_arch = "aarch64"), allow(dead_code))]
#[cfg(feature = "std_detect_file_io")]
use crate::{fs::File, io::Read};
pub(crate) const AT_NULL: usize = 0;
/// Key to access the CPU Hardware capabilities bitfield.
pub(crate) const AT_HWCAP: usize = 16;
/// Key to access the CPU Hardware capabilities 2 bitfield.
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
pub(crate) const AT_HWCAP2: usize = 26;
/// Cache HWCAP bitfields of the ELF Auxiliary Vector.
@ -17,7 +20,11 @@ pub(crate) const AT_HWCAP2: usize = 26;
#[derive(Debug, Copy, Clone)]
pub(crate) struct AuxVec {
pub hwcap: usize,
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
pub hwcap2: usize,
}
@ -64,7 +71,11 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
}
// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
if let Ok(hwcap2) = getauxval(AT_HWCAP2) {
if hwcap != 0 && hwcap2 != 0 {
@ -74,21 +85,11 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
}
drop(hwcap);
}
#[cfg(feature = "std_detect_file_io")]
{
// If calling getauxval fails, try to read the auxiliary vector from
// its file:
auxv_from_file("/proc/self/auxv")
}
#[cfg(not(feature = "std_detect_file_io"))]
{
Err(())
}
}
#[cfg(not(feature = "std_detect_dlsym_getauxval"))]
{
let hwcap = unsafe { ffi_getauxval(AT_HWCAP) };
let hwcap = unsafe { libc::getauxval(AT_HWCAP) };
// Targets with only AT_HWCAP:
#[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))]
@ -99,14 +100,29 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
}
// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
let hwcap2 = unsafe { ffi_getauxval(AT_HWCAP2) };
let hwcap2 = unsafe { libc::getauxval(AT_HWCAP2) };
if hwcap != 0 && hwcap2 != 0 {
return Ok(AuxVec { hwcap, hwcap2 });
}
}
}
#[cfg(feature = "std_detect_file_io")]
{
// If calling getauxval fails, try to read the auxiliary vector from
// its file:
auxv_from_file("/proc/self/auxv")
}
#[cfg(not(feature = "std_detect_file_io"))]
{
Err(())
}
}
/// Tries to read the `key` from the auxiliary vector by calling the
@ -122,7 +138,7 @@ fn getauxval(key: usize) -> Result<usize, ()> {
return Err(());
}
let ffi_getauxval: F = mem::transmute(ptr);
let ffi_getauxval: F = core::mem::transmute(ptr);
Ok(ffi_getauxval(key))
}
}
@ -131,7 +147,7 @@ fn getauxval(key: usize) -> Result<usize, ()> {
/// function returns `Err`.
#[cfg(feature = "std_detect_file_io")]
fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
let mut file = File::open(file).map_err(|_| ())?;
let file = super::read_file(file)?;
// See <https://github.com/torvalds/linux/blob/v3.19/include/uapi/linux/auxvec.h>.
//
@ -139,10 +155,11 @@ fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
// `AT_EXECFN = 31` to `AT_NULL = 0`. That is, a buffer of
// 2*32 `usize` elements is enough to read the whole vector.
let mut buf = [0_usize; 64];
{
let raw: &mut [u8; 64 * mem::size_of::<usize>()] = unsafe { mem::transmute(&mut buf) };
file.read(raw).map_err(|_| ())?;
let len = core::mem::size_of_val(&buf).max(file.len());
unsafe {
core::ptr::copy_nonoverlapping(file.as_ptr(), buf.as_mut_ptr() as *mut u8, len);
}
auxv_from_buf(&buf)
}
@ -155,18 +172,24 @@ fn auxv_from_buf(buf: &[usize; 64]) -> Result<AuxVec, ()> {
{
for el in buf.chunks(2) {
match el[0] {
AT_NULL => break,
AT_HWCAP => return Ok(AuxVec { hwcap: el[1] }),
_ => (),
}
}
}
// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
let mut hwcap = None;
let mut hwcap2 = None;
for el in buf.chunks(2) {
match el[0] {
AT_NULL => break,
AT_HWCAP => hwcap = Some(el[1]),
AT_HWCAP2 => hwcap2 = Some(el[1]),
_ => (),
@ -214,7 +237,12 @@ mod tests {
// FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv
// does not always contain the AT_HWCAP key under qemu.
#[cfg(not(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc")))]
#[cfg(any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
#[test]
fn auxv_crate() {
let v = auxv();
@ -224,7 +252,11 @@ mod tests {
}
// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
if let Some(hwcap2) = auxv_crate_getauxval(AT_HWCAP2) {
let rt_hwcap2 = v.expect("failed to find hwcap2 key").hwcap2;
@ -243,7 +275,7 @@ mod tests {
}
#[cfg(feature = "std_detect_file_io")]
cfg_if! {
cfg_if::cfg_if! {
if #[cfg(target_arch = "arm")] {
#[test]
fn linux_rpi3() {
@ -264,6 +296,7 @@ mod tests {
// want to fall back to /proc/cpuinfo in this case, so
// reading should fail. assert_eq!(v.hwcap, 126614527);
// assert_eq!(v.hwcap2, 0);
let _ = v;
}
} else if #[cfg(target_arch = "aarch64")] {
#[test]
@ -286,7 +319,14 @@ mod tests {
}
}
#[cfg(any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
#[test]
#[cfg(feature = "std_detect_file_io")]
fn auxv_crate_procfs() {
let v = auxv();
if let Some(hwcap) = auxv_crate_getprocfs(AT_HWCAP) {
@ -294,7 +334,11 @@ mod tests {
}
// Targets with AT_HWCAP and AT_HWCAP2:
#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "powerpc64"
))]
{
if let Some(hwcap2) = auxv_crate_getprocfs(AT_HWCAP2) {
assert_eq!(v.unwrap().hwcap2, hwcap2);

View file

@ -1,8 +1,7 @@
//! Parses /proc/cpuinfo
#![cfg_attr(not(target_arch = "arm"), allow(dead_code))]
extern crate std;
use self::std::{fs::File, io, io::Read, prelude::v1::*};
use alloc::string::String;
/// cpuinfo
pub(crate) struct CpuInfo {
@ -11,11 +10,11 @@ pub(crate) struct CpuInfo {
impl CpuInfo {
/// Reads /proc/cpuinfo into CpuInfo.
pub(crate) fn new() -> Result<Self, io::Error> {
let mut file = File::open("/proc/cpuinfo")?;
let mut cpui = Self { raw: String::new() };
file.read_to_string(&mut cpui.raw)?;
Ok(cpui)
pub(crate) fn new() -> Result<Self, ()> {
let raw = super::read_file("/proc/cpuinfo")?;
Ok(Self {
raw: String::from_utf8(raw).map_err(|_| ())?,
})
}
/// Returns the value of the cpuinfo `field`.
pub(crate) fn field(&self, field: &str) -> CpuInfoField {
@ -34,7 +33,7 @@ impl CpuInfo {
}
#[cfg(test)]
fn from_str(other: &str) -> Result<Self, ::std::io::Error> {
fn from_str(other: &str) -> Result<Self, ()> {
Ok(Self {
raw: String::from(other),
})

View file

@ -1,28 +1,61 @@
//! Run-time feature detection on Linux
//!
#[cfg(feature = "std_detect_file_io")]
use alloc::vec::Vec;
mod auxvec;
#[cfg(feature = "std_detect_file_io")]
mod cpuinfo;
cfg_if! {
#[cfg(feature = "std_detect_file_io")]
fn read_file(path: &str) -> Result<Vec<u8>, ()> {
let mut path = Vec::from(path.as_bytes());
path.push(0);
unsafe {
let file = libc::open(path.as_ptr() as *const libc::c_char, libc::O_RDONLY);
if file == -1 {
return Err(());
}
let mut data = Vec::new();
loop {
data.reserve(4096);
let spare = data.spare_capacity_mut();
match libc::read(file, spare.as_mut_ptr() as *mut _, spare.len()) {
-1 => {
libc::close(file);
return Err(());
}
0 => break,
n => data.set_len(data.len() + n as usize),
}
}
libc::close(file);
Ok(data)
}
}
cfg_if::cfg_if! {
if #[cfg(target_arch = "aarch64")] {
mod aarch64;
pub use self::aarch64::check_for;
pub(crate) use self::aarch64::detect_features;
} else if #[cfg(target_arch = "arm")] {
mod arm;
pub use self::arm::check_for;
pub(crate) use self::arm::detect_features;
} else if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] {
mod mips;
pub use self::mips::check_for;
pub(crate) use self::mips::detect_features;
} else if #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] {
mod powerpc;
pub use self::powerpc::check_for;
pub(crate) use self::powerpc::detect_features;
} else {
use crate::detect::Feature;
use crate::detect::cache;
/// Performs run-time feature detection.
pub fn check_for(_x: Feature) -> bool {
false
pub(crate) fn detect_features() -> cache::Initializer {
cache::Initializer::default()
}
}
}

View file

@ -1,6 +1,6 @@
//! Run-time feature detection for PowerPC on Linux.
use super::{auxvec, cpuinfo};
use super::auxvec;
use crate::detect::{cache, Feature};
/// Try to read the features from the auxiliary vector, and if that fails, try
@ -27,7 +27,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
// PowerPC's /proc/cpuinfo lacks a proper Feature field,
// but `altivec` support is indicated in the `cpu` field.
if let Ok(c) = cpuinfo::CpuInfo::new() {
#[cfg(feature = "std_detect_file_io")]
if let Ok(c) = super::cpuinfo::CpuInfo::new() {
enable_feature(&mut value, Feature::altivec, c.field("cpu").has("altivec"));
return value;
}

View file

@ -1,11 +1,11 @@
//! x86 run-time feature detection is OS independent.
#[cfg(target_arch = "x86")]
use crate::arch::x86::*;
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use crate::arch::x86_64::*;
use core::arch::x86_64::*;
use crate::mem;
use core::mem;
use crate::detect::{bit, cache, Feature};

View file

@ -15,30 +15,17 @@
#![feature(const_fn, staged_api, stdsimd, doc_cfg, allow_internal_unstable)]
#![allow(clippy::shadow_reuse)]
#![deny(clippy::missing_inline_in_public_items)]
#![cfg_attr(target_os = "linux", feature(linkage))]
#![cfg_attr(all(target_os = "freebsd", target_arch = "aarch64"), feature(llvm_asm))]
#![cfg_attr(test, allow(unused_imports))]
#![cfg_attr(feature = "std_detect_file_io", feature(vec_spare_capacity))]
#![no_std]
cfg_if::cfg_if! {
if #[cfg(any(feature = "std_detect_file_io", feature = "std_detect_env_override"))] {
#[cfg_attr(test, macro_use(println))]
extern crate std;
#[cfg(feature = "std_detect_file_io")]
extern crate alloc;
#[allow(unused_imports)]
use std::{arch, env, fs, io, mem, sync};
} else {
#[cfg(test)]
#[macro_use(println)]
extern crate std;
#[allow(unused_imports)]
use core::{arch, mem, sync};
}
}
#[cfg(feature = "std_detect_dlsym_getauxval")]
extern crate libc;
#[cfg(test)]
#[macro_use]
extern crate std;
#[doc(hidden)]
#[unstable(feature = "stdsimd", issue = "27731")]

View file

@ -1,5 +0,0 @@
//! `std_detect`
#[doc(hidden)] // unstable implementation detail
#[unstable(feature = "stdsimd", issue = "27731")]
pub mod detect;