<commit_before>use super::swarm::Swarm;
use super::messaging::{Message, Actor, Individual, Packet, Recipient};
use super::inbox::Inbox;
use super::type_registry::TypeRegistry;
use std::intrinsics::{type_id, type_name};
use core::nonzero::NonZero;

/// The single, global actor system for the whole program
pub static mut THE_SYSTEM: *mut ActorSystem = 0 as *mut ActorSystem;

/// The ID used to specify a specific object within the actor system
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ID {
    /// The sequentially numbered type ID of the actor within the actor system
    pub type_id: NonZero<u16>,
    /// The "generation" of the actor, to help debugging as instance_IDs can be reused
    pub version: u8,
    /// The instance of the type used to address a specific actor
    /// Is broadcast if equal to `u32::max_value()`
    /// Is swarm if equal to `u32::max_value() -1`
    pub instance_id: u32
}

impl ID {
    pub fn individual(individual_type_id: usize) -> ID {
        ID {type_id: unsafe {NonZero::new(individual_type_id as u16)}, version: 0, instance_id: 0}
    }

    /// Construct a broadcast ID to the type
    pub fn broadcast(type_id: usize) -> ID {
        ID {type_id: unsafe {NonZero::new(type_id as u16)}, version: 0, instance_id: u32::max_value()}
    }

    /// Construct an ID which points to an actor instance in a swarm
    pub fn instance(type_id: usize, instance_id_and_version: (usize, usize)) -> ID {
        ID {type_id: unsafe {NonZero::new(type_id as u16)}, version: instance_id_and_version.1 as u8, instance_id: instance_id_and_version.0 as u32}
    }

    /// Checks if ID is a broadcast ID
    pub fn is_broadcast(&self) -> bool {
        self.instance_id == u32::max_value()
    }

    /// Created swarm ID with type ID specified
    pub fn swarm(type_id: usize) -> ID {
        ID {type_id: unsafe {NonZero::new(type_id as u16)}, version: 0, instance_id: u32::max_value() - 1}
    }

    /// Checks if ID is a swarm ID
    pub fn is_swarm(&self) -> bool {
        self.instance_id == u32::max_value() - 1
    }
}

impl Default for ID {
    fn default() -> Self {
        ID{type_id: unsafe{NonZero::new(0)}, version: 0, instance_id: 0} //equal to None
    }
}

impl ::std::fmt::Debug for ID {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "ID {}_{}_{}", *(self.type_id), self.version, self.instance_id)
    }
}

impl<M: Message> ::std::ops::Shl<M> for ID {
    type Output = ();
    /// The shift left operator is overloaded to use to send messages
    /// e.g. recipient_ID << message
    fn shl(self, rhs: M) {
        unsafe {(*THE_SYSTEM).send(self, rhs);}
    }
}

const MAX_RECIPIENT_TYPES : usize = 64;
const MAX_MESSAGE_TYPES_PER_RECIPIENT: usize = 32;

#[derive(Clone)]
struct InboxMap {
    /// Amount of valid entries in the InboxMap
    length: usize,
    /// Entry consists of TypeID of Message type and pointer to inbox
    entries: [Option<(u64, *mut u8)>; MAX_MESSAGE_TYPES_PER_RECIPIENT]
}

impl InboxMap {
    /// Creates an empty InboxMap
    fn new() -> InboxMap {
        InboxMap{length: 0, entries: [None; MAX_MESSAGE_TYPES_PER_RECIPIENT]}
    }

    /// Adds new message type to the InboxMap
    fn add_new<M: Message>(&mut self, pointer: *mut Inbox<M>) {
        let message_type_id = unsafe{type_id::<M>()};
        let entry_is_for_id = |entry: &&Option<(u64, *mut u8)>| {
            entry.is_some() && entry.unwrap().0 == message_type_id
        };
        assert!(self.entries.iter().find(entry_is_for_id).is_none());
        self.entries[self.length] = Some((message_type_id, pointer as *mut u8));
        self.length += 1;
    }

    /// Gets the inbox pointer of the type specified if there is one
    fn get<M: Message>(&self) -> Option<*mut Inbox<M>> {
        let message_type_id = unsafe{type_id::<M>()};
        for entry in &self.entries {if let Some((id, pointer)) = *entry {
            if id == message_type_id {return Some(pointer as *mut Inbox<M>)}
        }}
        None
    }
}

pub struct ActorSystem {
    /// Stores the inboxes of all the individuals
    routing: [Option<InboxMap>; MAX_RECIPIENT_TYPES],
    /// Stores the rust TypeID to internal ID and type name mapping
    recipient_registry: TypeRegistry,
    /// Stores all individuals
    individuals: [Option<*mut u8>; MAX_RECIPIENT_TYPES],
    /// Closures to process and clear messages
    update_callbacks: Vec<Box<Fn()>>,
    /// Closures to clear messages
    clear_callbacks: Vec<Box<Fn()>>,
}

macro_rules! make_array {
    ($n:expr, $constructor:expr) => {{
        let mut items: [_; $n] = ::std::mem::uninitialized();
        for (i, place) in items.iter_mut().enumerate() {
            ::std::ptr::write(place, $constructor(i));
        }
        items
    }}
}

impl ActorSystem {
    pub fn new() -> ActorSystem {
        ActorSystem {
            routing: unsafe{make_array!(MAX_RECIPIENT_TYPES, |_| None)},
            recipient_registry: TypeRegistry::new(),
            individuals: [None; MAX_RECIPIENT_TYPES],
            update_callbacks: Vec::new(),
            clear_callbacks: Vec::new()
        }
    }

    /// Registers a type for use as an actor in the actor system
    pub fn add_individual<I: Individual>(&mut self, individual: I) {
        // Register type in recipient_registry, and return the short ID of the type (sequential ID starting from 0)
        let recipient_id = self.recipient_registry.register_new::<I>();

        assert!(self.routing[recipient_id].is_none());

        self.routing[recipient_id] = Some(InboxMap::new());

        // Store pointer to the individual
        self.individuals[recipient_id] = Some(Box::into_raw(Box::new(individual)) as *mut u8);
    }

    /// Add a inbox for a given message type to a individual
    pub fn add_inbox<M: Message, I: Individual + Recipient<M>> (&mut self) {
        self.add_inbox_helper::<M, I>(true);
    }

    /// Add an unclearable inbox for a given message type to a individual
    pub fn add_unclearable_inbox<M: Message, I: Individual + Recipient<M>> (&mut self) {
        self.add_inbox_helper::<M, I>(false);
    }

    fn add_inbox_helper<M: Message, I: Individual + Recipient<M>> (&mut self, clearable: bool) {
        let inbox = Inbox::<M>::new();

        // Gets short ID of individual
        let recipient_id = self.recipient_registry.get::<I>();

        let inbox_ptr = self.store_inbox(inbox, recipient_id);
        let individual_ptr = self.individuals[recipient_id].unwrap() as *mut I;

        // Create closure to process messages
        self.update_callbacks.push(Box::new(move || {
            unsafe {
                for packet in (*inbox_ptr).empty() {
                    (*individual_ptr).receive_packet(packet);
                }
            }
        }));

        // Create closure to empty messages without processing
        if clearable {
            self.clear_callbacks.push(Box::new(move || {
                unsafe {
                    for _packet in (*inbox_ptr).empty() {
                    }
                }
            }));
        }
    }

    pub fn individual_id<I: Individual>(&mut self) -> ID {
        ID::individual(self.recipient_registry.get::<I>())
    }

    pub fn broadcast_id<A: Actor>(&mut self) -> ID {
        ID::broadcast(self.recipient_registry.get::<Swarm<A>>())
    }

    pub fn instance_id<A: Actor>(&mut self, instance_id_and_version: (usize, usize)) -> ID {
        ID::instance(self.recipient_registry.get::<Swarm<A>>(), instance_id_and_version)
    }

    /// Store the inbox pointer of a given type into the routing array
    fn store_inbox<M: Message>(&mut self, inbox: Inbox<M>, recipient_type_id: usize) -> *mut Inbox<M> {
        let inbox_ptr = Box::into_raw(Box::new(inbox));
        // TODO: deallocate inbox at the end of times
        self.routing[recipient_type_id].as_mut().unwrap().add_new(inbox_ptr);
        inbox_ptr
    }

    /// Get the inbox pointer of a given type from the routing array
    pub fn inbox_for<M: Message>(&mut self, packet: &Packet<M>) -> &mut Inbox<M> {
        if let Some(inbox_ptr) = self.routing[*(packet.recipient_id.expect("Recipient ID not set").type_id) as usize].as_ref()
            .expect("Recipient not found")
            .get::<M>() {
                unsafe{&mut *inbox_ptr}
        } else {
            panic!("Inbox for {} not found for {}",
                unsafe{type_name::<M>()},
                self.recipient_registry.get_name(*(packet.recipient_id.expect("Recipient ID not set").type_id) as usize))
        }
    }

    /// Places message into the inbox of a given type
    fn send<M: Message>(&mut self, recipient: ID, message: M) {
        let packet = Packet{
            recipient_id: Some(recipient),
            message: message
        };
        self.inbox_for(&packet).put(packet);
    }

    /// Process all messages and clears all inboxes
    pub fn process_messages(&mut self) {
        for callback in &self.update_callbacks {
            callback();
        }
    }

    /// Clear all inboxes without processing
    pub fn clear_all_clearable_messages(&mut self) {
        for callback in &self.clear_callbacks {
            callback();
        }
    }

    /// Process messages, up to 1000 layers of recursion
    pub fn process_all_messages(&mut self) {
        for _i in 0..1000 {
            self.process_messages();
        }
    }
}

impl Default for ActorSystem {
    fn default() -> Self {
        Self::new()
    }
}<commit_msg>No need for Default impl for ID anymore<commit_after>use super::swarm::Swarm;
use super::messaging::{Message, Actor, Individual, Packet, Recipient};
use super::inbox::Inbox;
use super::type_registry::TypeRegistry;
use std::intrinsics::{type_id, type_name};
use core::nonzero::NonZero;

/// The single, global actor system for the whole program
pub static mut THE_SYSTEM: *mut ActorSystem = 0 as *mut ActorSystem;

/// The ID used to specify a specific object within the actor system
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct ID {
    /// The sequentially numbered type ID of the actor within the actor system
    pub type_id: NonZero<u16>,
    /// The "generation" of the ID, to help debugging as instance_IDs can be reused
    pub version: u8,
    /// The instance of the type used to address a specific actor
    /// Is broadcast if equal to `u32::max_value()`
    /// Is swarm if equal to `u32::max_value() -1`
    pub instance_id: u32
}

impl ID {
    pub fn individual(individual_type_id: usize) -> ID {
        ID {type_id: unsafe {NonZero::new(individual_type_id as u16)}, version: 0, instance_id: 0}
    }

    /// Construct a broadcast ID to the type
    pub fn broadcast(type_id: usize) -> ID {
        ID {type_id: unsafe {NonZero::new(type_id as u16)}, version: 0, instance_id: u32::max_value()}
    }

    /// Construct an ID which points to an actor instance in a swarm
    pub fn instance(type_id: usize, instance_id_and_version: (usize, usize)) -> ID {
        ID {type_id: unsafe {NonZero::new(type_id as u16)}, version: instance_id_and_version.1 as u8, instance_id: instance_id_and_version.0 as u32}
    }

    /// Checks if ID is a broadcast ID
    pub fn is_broadcast(&self) -> bool {
        self.instance_id == u32::max_value()
    }

    /// Created swarm ID with type ID specified
    pub fn swarm(type_id: usize) -> ID {
        ID {type_id: unsafe {NonZero::new(type_id as u16)}, version: 0, instance_id: u32::max_value() - 1}
    }

    /// Checks if ID is a swarm ID
    pub fn is_swarm(&self) -> bool {
        self.instance_id == u32::max_value() - 1
    }
}

impl ::std::fmt::Debug for ID {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "ID {}_{}_{}", *(self.type_id), self.version, self.instance_id)
    }
}

impl<M: Message> ::std::ops::Shl<M> for ID {
    type Output = ();
    /// The shift left operator is overloaded to use to send messages
    /// e.g. recipient_ID << message
    fn shl(self, rhs: M) {
        unsafe {(*THE_SYSTEM).send(self, rhs);}
    }
}

const MAX_RECIPIENT_TYPES : usize = 64;
const MAX_MESSAGE_TYPES_PER_RECIPIENT: usize = 32;

#[derive(Clone)]
struct InboxMap {
    /// Amount of valid entries in the InboxMap
    length: usize,
    /// Entry consists of TypeID of Message type and pointer to inbox
    entries: [Option<(u64, *mut u8)>; MAX_MESSAGE_TYPES_PER_RECIPIENT]
}

impl InboxMap {
    /// Creates an empty InboxMap
    fn new() -> InboxMap {
        InboxMap{length: 0, entries: [None; MAX_MESSAGE_TYPES_PER_RECIPIENT]}
    }

    /// Adds new message type to the InboxMap
    fn add_new<M: Message>(&mut self, pointer: *mut Inbox<M>) {
        let message_type_id = unsafe{type_id::<M>()};
        let entry_is_for_id = |entry: &&Option<(u64, *mut u8)>| {
            entry.is_some() && entry.unwrap().0 == message_type_id
        };
        assert!(self.entries.iter().find(entry_is_for_id).is_none());
        self.entries[self.length] = Some((message_type_id, pointer as *mut u8));
        self.length += 1;
    }

    /// Gets the inbox pointer of the type specified if there is one
    fn get<M: Message>(&self) -> Option<*mut Inbox<M>> {
        let message_type_id = unsafe{type_id::<M>()};
        for entry in &self.entries {if let Some((id, pointer)) = *entry {
            if id == message_type_id {return Some(pointer as *mut Inbox<M>)}
        }}
        None
    }
}

pub struct ActorSystem {
    /// Stores the inboxes of all the individuals
    routing: [Option<InboxMap>; MAX_RECIPIENT_TYPES],
    /// Stores the rust TypeID to internal ID and type name mapping
    recipient_registry: TypeRegistry,
    /// Stores all individuals
    individuals: [Option<*mut u8>; MAX_RECIPIENT_TYPES],
    /// Closures to process and clear messages
    update_callbacks: Vec<Box<Fn()>>,
    /// Closures to clear messages
    clear_callbacks: Vec<Box<Fn()>>,
}

macro_rules! make_array {
    ($n:expr, $constructor:expr) => {{
        let mut items: [_; $n] = ::std::mem::uninitialized();
        for (i, place) in items.iter_mut().enumerate() {
            ::std::ptr::write(place, $constructor(i));
        }
        items
    }}
}

impl ActorSystem {
    pub fn new() -> ActorSystem {
        ActorSystem {
            routing: unsafe{make_array!(MAX_RECIPIENT_TYPES, |_| None)},
            recipient_registry: TypeRegistry::new(),
            individuals: [None; MAX_RECIPIENT_TYPES],
            update_callbacks: Vec::new(),
            clear_callbacks: Vec::new()
        }
    }

    /// Registers a type for use as an actor in the actor system
    pub fn add_individual<I: Individual>(&mut self, individual: I) {
        // Register type in recipient_registry, and return the short ID of the type (sequential ID starting from 0)
        let recipient_id = self.recipient_registry.register_new::<I>();

        assert!(self.routing[recipient_id].is_none());

        self.routing[recipient_id] = Some(InboxMap::new());

        // Store pointer to the individual
        self.individuals[recipient_id] = Some(Box::into_raw(Box::new(individual)) as *mut u8);
    }

    /// Add a inbox for a given message type to a individual
    pub fn add_inbox<M: Message, I: Individual + Recipient<M>> (&mut self) {
        self.add_inbox_helper::<M, I>(true);
    }

    /// Add an unclearable inbox for a given message type to a individual
    pub fn add_unclearable_inbox<M: Message, I: Individual + Recipient<M>> (&mut self) {
        self.add_inbox_helper::<M, I>(false);
    }

    fn add_inbox_helper<M: Message, I: Individual + Recipient<M>> (&mut self, clearable: bool) {
        let inbox = Inbox::<M>::new();

        // Gets short ID of individual
        let recipient_id = self.recipient_registry.get::<I>();

        let inbox_ptr = self.store_inbox(inbox, recipient_id);
        let individual_ptr = self.individuals[recipient_id].unwrap() as *mut I;

        // Create closure to process messages
        self.update_callbacks.push(Box::new(move || {
            unsafe {
                for packet in (*inbox_ptr).empty() {
                    (*individual_ptr).receive_packet(packet);
                }
            }
        }));

        // Create closure to empty messages without processing
        if clearable {
            self.clear_callbacks.push(Box::new(move || {
                unsafe {
                    for _packet in (*inbox_ptr).empty() {
                    }
                }
            }));
        }
    }

    pub fn individual_id<I: Individual>(&mut self) -> ID {
        ID::individual(self.recipient_registry.get::<I>())
    }

    pub fn broadcast_id<A: Actor>(&mut self) -> ID {
        ID::broadcast(self.recipient_registry.get::<Swarm<A>>())
    }

    pub fn instance_id<A: Actor>(&mut self, instance_id_and_version: (usize, usize)) -> ID {
        ID::instance(self.recipient_registry.get::<Swarm<A>>(), instance_id_and_version)
    }

    /// Store the inbox pointer of a given type into the routing array
    fn store_inbox<M: Message>(&mut self, inbox: Inbox<M>, recipient_type_id: usize) -> *mut Inbox<M> {
        let inbox_ptr = Box::into_raw(Box::new(inbox));
        // TODO: deallocate inbox at the end of times
        self.routing[recipient_type_id].as_mut().unwrap().add_new(inbox_ptr);
        inbox_ptr
    }

    /// Get the inbox pointer of a given type from the routing array
    pub fn inbox_for<M: Message>(&mut self, packet: &Packet<M>) -> &mut Inbox<M> {
        if let Some(inbox_ptr) = self.routing[*(packet.recipient_id.expect("Recipient ID not set").type_id) as usize].as_ref()
            .expect("Recipient not found")
            .get::<M>() {
                unsafe{&mut *inbox_ptr}
        } else {
            panic!("Inbox for {} not found for {}",
                unsafe{type_name::<M>()},
                self.recipient_registry.get_name(*(packet.recipient_id.expect("Recipient ID not set").type_id) as usize))
        }
    }

    /// Places message into the inbox of a given type
    fn send<M: Message>(&mut self, recipient: ID, message: M) {
        let packet = Packet{
            recipient_id: Some(recipient),
            message: message
        };
        self.inbox_for(&packet).put(packet);
    }

    /// Process all messages and clears all inboxes
    pub fn process_messages(&mut self) {
        for callback in &self.update_callbacks {
            callback();
        }
    }

    /// Clear all inboxes without processing
    pub fn clear_all_clearable_messages(&mut self) {
        for callback in &self.clear_callbacks {
            callback();
        }
    }

    /// Process messages, up to 1000 layers of recursion
    pub fn process_all_messages(&mut self) {
        for _i in 0..1000 {
            self.process_messages();
        }
    }
}

impl Default for ActorSystem {
    fn default() -> Self {
        Self::new()
    }
}<|endoftext|>


<commit_before>// Take a look at the license at the top of the repository in the LICENSE file.

use crate::sys::utils::get_all_data;
use crate::{utils, DiskExt, DiskType};

use libc::statvfs;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::mem;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

macro_rules! cast {
    ($x:expr) => {
        u64::from($x)
    };
}

#[doc = include_str!("../../md_doc/disk.md")]
#[derive(PartialEq, Eq)]
pub struct Disk {
    type_: DiskType,
    device_name: OsString,
    file_system: Vec<u8>,
    mount_point: PathBuf,
    total_space: u64,
    available_space: u64,
    is_removable: bool,
}

impl DiskExt for Disk {
    fn type_(&self) -> DiskType {
        self.type_
    }

    fn name(&self) -> &OsStr {
        &self.device_name
    }

    fn file_system(&self) -> &[u8] {
        &self.file_system
    }

    fn mount_point(&self) -> &Path {
        &self.mount_point
    }

    fn total_space(&self) -> u64 {
        self.total_space
    }

    fn available_space(&self) -> u64 {
        self.available_space
    }

    fn is_removable(&self) -> bool {
        self.is_removable
    }

    fn refresh(&mut self) -> bool {
        unsafe {
            let mut stat: statvfs = mem::zeroed();
            let mount_point_cpath = utils::to_cpath(&self.mount_point);
            if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 {
                let tmp = cast!(stat.f_bsize).saturating_mul(cast!(stat.f_bavail));
                self.available_space = cast!(tmp);
                true
            } else {
                false
            }
        }
    }
}

fn new_disk(
    device_name: &OsStr,
    mount_point: &Path,
    file_system: &[u8],
    removable_entries: &[PathBuf],
) -> Option<Disk> {
    let mount_point_cpath = utils::to_cpath(mount_point);
    let type_ = find_type_for_device_name(device_name);
    let mut total = 0;
    let mut available = 0;
    unsafe {
        let mut stat: statvfs = mem::zeroed();
        if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 {
            let bsize = cast!(stat.f_bsize);
            let blocks = cast!(stat.f_blocks);
            let bavail = cast!(stat.f_bavail);
            total = bsize.saturating_mul(blocks);
            available = bsize.saturating_mul(bavail);
        }
        if total == 0 {
            return None;
        }
        let mount_point = mount_point.to_owned();
        let is_removable = removable_entries
            .iter()
            .any(|e| e.as_os_str() == device_name);
        Some(Disk {
            type_,
            device_name: device_name.to_owned(),
            file_system: file_system.to_owned(),
            mount_point,
            total_space: cast!(total),
            available_space: cast!(available),
            is_removable,
        })
    }
}

#[allow(clippy::manual_range_contains)]
fn find_type_for_device_name(device_name: &OsStr) -> DiskType {
    // The format of devices are as follows:
    //  - device_name is symbolic link in the case of /dev/mapper/
    //     and /dev/root, and the target is corresponding device under
    //     /sys/block/
    //  - In the case of /dev/sd, the format is /dev/sd[a-z][1-9],
    //     corresponding to /sys/block/sd[a-z]
    //  - In the case of /dev/nvme, the format is /dev/nvme[0-9]n[0-9]p[0-9],
    //     corresponding to /sys/block/nvme[0-9]n[0-9]
    //  - In the case of /dev/mmcblk, the format is /dev/mmcblk[0-9]p[0-9],
    //     corresponding to /sys/block/mmcblk[0-9]
    let device_name_path = device_name.to_str().unwrap_or_default();
    let real_path = fs::canonicalize(device_name).unwrap_or_else(|_| PathBuf::from(device_name));
    let mut real_path = real_path.to_str().unwrap_or_default();
    if device_name_path.starts_with("/dev/mapper/") {
        // Recursively solve, for example /dev/dm-0
        if real_path != device_name_path {
            return find_type_for_device_name(OsStr::new(&real_path));
        }
    } else if device_name_path.starts_with("/dev/sd") || device_name_path.starts_with("/dev/vd") {
        // Turn "sda1" into "sda" or "vda1" into "vda"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
    } else if device_name_path.starts_with("/dev/nvme") {
        // Turn "nvme0n1p1" into "nvme0n1"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
        real_path = real_path.trim_end_matches(|c| c == 'p');
    } else if device_name_path.starts_with("/dev/root") {
        // Recursively solve, for example /dev/mmcblk0p1
        if real_path != device_name_path {
            return find_type_for_device_name(OsStr::new(&real_path));
        }
    } else if device_name_path.starts_with("/dev/mmcblk") {
        // Turn "mmcblk0p1" into "mmcblk0"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
        real_path = real_path.trim_end_matches(|c| c == 'p');
    } else {
        // Default case: remove /dev/ and expects the name presents under /sys/block/
        // For example, /dev/dm-0 to dm-0
        real_path = real_path.trim_start_matches("/dev/");
    }

    let trimmed: &OsStr = OsStrExt::from_bytes(real_path.as_bytes());

    let path = Path::new("/sys/block/")
        .to_owned()
        .join(trimmed)
        .join("queue/rotational");
    // Normally, this file only contains '0' or '1' but just in case, we get 8 bytes...
    match get_all_data(path, 8)
        .unwrap_or_default()
        .trim()
        .parse()
        .ok()
    {
        // The disk is marked as rotational so it's a HDD.
        Some(1) => DiskType::HDD,
        // The disk is marked as non-rotational so it's very likely a SSD.
        Some(0) => DiskType::SSD,
        // Normally it shouldn't happen but welcome to the wonderful world of IT! :D
        Some(x) => DiskType::Unknown(x),
        // The information isn't available...
        None => DiskType::Unknown(-1),
    }
}

fn get_all_disks_inner(content: &str) -> Vec<Disk> {
    // The goal of this array is to list all removable devices (the ones whose name starts with
    // "usb-"). Then we check if
    let removable_entries = match fs::read_dir("/dev/disk/by-id/") {
        Ok(r) => r
            .filter_map(|res| Some(res.ok()?.path()))
            .filter_map(|e| {
                if e.file_name()
                    .and_then(|x| Some(x.to_str()?.starts_with("usb-")))
                    .unwrap_or_default()
                {
                    e.canonicalize().ok()
                } else {
                    None
                }
            })
            .collect::<Vec<PathBuf>>(),
        _ => Vec::new(),
    };

    content
        .lines()
        .map(|line| {
            let line = line.trim_start();
            // mounts format
            // http://man7.org/linux/man-pages/man5/fstab.5.html
            // fs_spec<tab>fs_file<tab>fs_vfstype<tab>other fields
            let mut fields = line.split_whitespace();
            let fs_spec = fields.next().unwrap_or("");
            let fs_file = fields
                .next()
                .unwrap_or("")
                .replace("\\134", "\\")
                .replace("\\040", " ")
                .replace("\\011", "\t")
                .replace("\\012", "\n");
            let fs_vfstype = fields.next().unwrap_or("");
            (fs_spec, fs_file, fs_vfstype)
        })
        .filter(|(fs_spec, fs_file, fs_vfstype)| {
            // Check if fs_vfstype is one of our 'ignored' file systems.
            let filtered = matches!(
                *fs_vfstype,
                "rootfs" | // https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt
                "sysfs" | // pseudo file system for kernel objects
                "proc" |  // another pseudo file system
                "tmpfs" |
                "devtmpfs" |
                "cgroup" |
                "cgroup2" |
                "pstore" | // https://www.kernel.org/doc/Documentation/ABI/testing/pstore
                "squashfs" | // squashfs is a compressed read-only file system (for snaps)
                "rpc_pipefs" | // The pipefs pseudo file system service
                "iso9660" // optical media
            );

            !(filtered ||
               fs_file.starts_with("/sys") || // check if fs_file is an 'ignored' mount point
               fs_file.starts_with("/proc") ||
               (fs_file.starts_with("/run") && !fs_file.starts_with("/run/media")) ||
               fs_spec.starts_with("sunrpc"))
        })
        .filter_map(|(fs_spec, fs_file, fs_vfstype)| {
            new_disk(
                fs_spec.as_ref(),
                Path::new(&fs_file),
                fs_vfstype.as_bytes(),
                &removable_entries,
            )
        })
        .collect()
}

pub(crate) fn get_all_disks() -> Vec<Disk> {
    get_all_disks_inner(&get_all_data("/proc/mounts", 16_385).unwrap_or_default())
}

// #[test]
// fn check_all_disks() {
//     let disks = get_all_disks_inner(
//         r#"tmpfs /proc tmpfs rw,seclabel,relatime 0 0
// proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
// systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=29,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=17771 0 0
// tmpfs /sys tmpfs rw,seclabel,relatime 0 0
// sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0
// cgroup2 /sys/fs/cgroup cgroup2 rw,seclabel,nosuid,nodev,noexec,relatime,nsdelegate 0 0
// pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// none /sys/fs/bpf bpf rw,nosuid,nodev,noexec,relatime,mode=700 0 0
// configfs /sys/kernel/config configfs rw,nosuid,nodev,noexec,relatime 0 0
// selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0
// debugfs /sys/kernel/debug debugfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// tmpfs /dev/shm tmpfs rw,seclabel,relatime 0 0
// devpts /dev/pts devpts rw,seclabel,relatime,gid=5,mode=620,ptmxmode=666 0 0
// tmpfs /sys/fs/selinux tmpfs rw,seclabel,relatime 0 0
// /dev/vda2 /proc/filesystems xfs rw,seclabel,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0
// "#,
//     );
//     assert_eq!(disks.len(), 1);
//     assert_eq!(
//         disks[0],
//         Disk {
//             type_: DiskType::Unknown(-1),
//             name: OsString::from("devpts"),
//             file_system: vec![100, 101, 118, 112, 116, 115],
//             mount_point: PathBuf::from("/dev/pts"),
//             total_space: 0,
//             available_space: 0,
//         }
//     );
// }
<commit_msg>fix: got nvme0n when passing device name 'nvme0n1'<commit_after>// Take a look at the license at the top of the repository in the LICENSE file.

use crate::sys::utils::get_all_data;
use crate::{utils, DiskExt, DiskType};

use libc::statvfs;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::mem;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

macro_rules! cast {
    ($x:expr) => {
        u64::from($x)
    };
}

#[doc = include_str!("../../md_doc/disk.md")]
#[derive(PartialEq, Eq)]
pub struct Disk {
    type_: DiskType,
    device_name: OsString,
    file_system: Vec<u8>,
    mount_point: PathBuf,
    total_space: u64,
    available_space: u64,
    is_removable: bool,
}

impl DiskExt for Disk {
    fn type_(&self) -> DiskType {
        self.type_
    }

    fn name(&self) -> &OsStr {
        &self.device_name
    }

    fn file_system(&self) -> &[u8] {
        &self.file_system
    }

    fn mount_point(&self) -> &Path {
        &self.mount_point
    }

    fn total_space(&self) -> u64 {
        self.total_space
    }

    fn available_space(&self) -> u64 {
        self.available_space
    }

    fn is_removable(&self) -> bool {
        self.is_removable
    }

    fn refresh(&mut self) -> bool {
        unsafe {
            let mut stat: statvfs = mem::zeroed();
            let mount_point_cpath = utils::to_cpath(&self.mount_point);
            if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 {
                let tmp = cast!(stat.f_bsize).saturating_mul(cast!(stat.f_bavail));
                self.available_space = cast!(tmp);
                true
            } else {
                false
            }
        }
    }
}

fn new_disk(
    device_name: &OsStr,
    mount_point: &Path,
    file_system: &[u8],
    removable_entries: &[PathBuf],
) -> Option<Disk> {
    let mount_point_cpath = utils::to_cpath(mount_point);
    let type_ = find_type_for_device_name(device_name);
    let mut total = 0;
    let mut available = 0;
    unsafe {
        let mut stat: statvfs = mem::zeroed();
        if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 {
            let bsize = cast!(stat.f_bsize);
            let blocks = cast!(stat.f_blocks);
            let bavail = cast!(stat.f_bavail);
            total = bsize.saturating_mul(blocks);
            available = bsize.saturating_mul(bavail);
        }
        if total == 0 {
            return None;
        }
        let mount_point = mount_point.to_owned();
        let is_removable = removable_entries
            .iter()
            .any(|e| e.as_os_str() == device_name);
        Some(Disk {
            type_,
            device_name: device_name.to_owned(),
            file_system: file_system.to_owned(),
            mount_point,
            total_space: cast!(total),
            available_space: cast!(available),
            is_removable,
        })
    }
}

#[allow(clippy::manual_range_contains)]
fn find_type_for_device_name(device_name: &OsStr) -> DiskType {
    // The format of devices are as follows:
    //  - device_name is symbolic link in the case of /dev/mapper/
    //     and /dev/root, and the target is corresponding device under
    //     /sys/block/
    //  - In the case of /dev/sd, the format is /dev/sd[a-z][1-9],
    //     corresponding to /sys/block/sd[a-z]
    //  - In the case of /dev/nvme, the format is /dev/nvme[0-9]n[0-9]p[0-9],
    //     corresponding to /sys/block/nvme[0-9]n[0-9]
    //  - In the case of /dev/mmcblk, the format is /dev/mmcblk[0-9]p[0-9],
    //     corresponding to /sys/block/mmcblk[0-9]
    let device_name_path = device_name.to_str().unwrap_or_default();
    let real_path = fs::canonicalize(device_name).unwrap_or_else(|_| PathBuf::from(device_name));
    let mut real_path = real_path.to_str().unwrap_or_default();
    if device_name_path.starts_with("/dev/mapper/") {
        // Recursively solve, for example /dev/dm-0
        if real_path != device_name_path {
            return find_type_for_device_name(OsStr::new(&real_path));
        }
    } else if device_name_path.starts_with("/dev/sd") || device_name_path.starts_with("/dev/vd") {
        // Turn "sda1" into "sda" or "vda1" into "vda"
        real_path = real_path.trim_start_matches("/dev/");
        real_path = real_path.trim_end_matches(|c| c >= '0' && c <= '9');
    } else if device_name_path.starts_with("/dev/nvme") {
        // Turn "nvme0n1p1" into "nvme0n1"
        real_path = match real_path.find('p') {
            Some(idx) => &real_path["/dev/".len()..idx],
            None => &real_path["/dev/".len()..],
        };
    } else if device_name_path.starts_with("/dev/root") {
        // Recursively solve, for example /dev/mmcblk0p1
        if real_path != device_name_path {
            return find_type_for_device_name(OsStr::new(&real_path));
        }
    } else if device_name_path.starts_with("/dev/mmcblk") {
        // Turn "mmcblk0p1" into "mmcblk0"
        real_path = match real_path.find('p') {
            Some(idx) => &real_path["/dev/".len()..idx],
            None => &real_path["/dev/".len()..],
        };
    } else {
        // Default case: remove /dev/ and expects the name presents under /sys/block/
        // For example, /dev/dm-0 to dm-0
        real_path = real_path.trim_start_matches("/dev/");
    }

    let trimmed: &OsStr = OsStrExt::from_bytes(real_path.as_bytes());

    let path = Path::new("/sys/block/")
        .to_owned()
        .join(trimmed)
        .join("queue/rotational");
    // Normally, this file only contains '0' or '1' but just in case, we get 8 bytes...
    match get_all_data(path, 8)
        .unwrap_or_default()
        .trim()
        .parse()
        .ok()
    {
        // The disk is marked as rotational so it's a HDD.
        Some(1) => DiskType::HDD,
        // The disk is marked as non-rotational so it's very likely a SSD.
        Some(0) => DiskType::SSD,
        // Normally it shouldn't happen but welcome to the wonderful world of IT! :D
        Some(x) => DiskType::Unknown(x),
        // The information isn't available...
        None => DiskType::Unknown(-1),
    }
}

fn get_all_disks_inner(content: &str) -> Vec<Disk> {
    // The goal of this array is to list all removable devices (the ones whose name starts with
    // "usb-"). Then we check if
    let removable_entries = match fs::read_dir("/dev/disk/by-id/") {
        Ok(r) => r
            .filter_map(|res| Some(res.ok()?.path()))
            .filter_map(|e| {
                if e.file_name()
                    .and_then(|x| Some(x.to_str()?.starts_with("usb-")))
                    .unwrap_or_default()
                {
                    e.canonicalize().ok()
                } else {
                    None
                }
            })
            .collect::<Vec<PathBuf>>(),
        _ => Vec::new(),
    };

    content
        .lines()
        .map(|line| {
            let line = line.trim_start();
            // mounts format
            // http://man7.org/linux/man-pages/man5/fstab.5.html
            // fs_spec<tab>fs_file<tab>fs_vfstype<tab>other fields
            let mut fields = line.split_whitespace();
            let fs_spec = fields.next().unwrap_or("");
            let fs_file = fields
                .next()
                .unwrap_or("")
                .replace("\\134", "\\")
                .replace("\\040", " ")
                .replace("\\011", "\t")
                .replace("\\012", "\n");
            let fs_vfstype = fields.next().unwrap_or("");
            (fs_spec, fs_file, fs_vfstype)
        })
        .filter(|(fs_spec, fs_file, fs_vfstype)| {
            // Check if fs_vfstype is one of our 'ignored' file systems.
            let filtered = matches!(
                *fs_vfstype,
                "rootfs" | // https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt
                "sysfs" | // pseudo file system for kernel objects
                "proc" |  // another pseudo file system
                "tmpfs" |
                "devtmpfs" |
                "cgroup" |
                "cgroup2" |
                "pstore" | // https://www.kernel.org/doc/Documentation/ABI/testing/pstore
                "squashfs" | // squashfs is a compressed read-only file system (for snaps)
                "rpc_pipefs" | // The pipefs pseudo file system service
                "iso9660" // optical media
            );

            !(filtered ||
               fs_file.starts_with("/sys") || // check if fs_file is an 'ignored' mount point
               fs_file.starts_with("/proc") ||
               (fs_file.starts_with("/run") && !fs_file.starts_with("/run/media")) ||
               fs_spec.starts_with("sunrpc"))
        })
        .filter_map(|(fs_spec, fs_file, fs_vfstype)| {
            new_disk(
                fs_spec.as_ref(),
                Path::new(&fs_file),
                fs_vfstype.as_bytes(),
                &removable_entries,
            )
        })
        .collect()
}

pub(crate) fn get_all_disks() -> Vec<Disk> {
    get_all_disks_inner(&get_all_data("/proc/mounts", 16_385).unwrap_or_default())
}

// #[test]
// fn check_all_disks() {
//     let disks = get_all_disks_inner(
//         r#"tmpfs /proc tmpfs rw,seclabel,relatime 0 0
// proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
// systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=29,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=17771 0 0
// tmpfs /sys tmpfs rw,seclabel,relatime 0 0
// sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0
// cgroup2 /sys/fs/cgroup cgroup2 rw,seclabel,nosuid,nodev,noexec,relatime,nsdelegate 0 0
// pstore /sys/fs/pstore pstore rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// none /sys/fs/bpf bpf rw,nosuid,nodev,noexec,relatime,mode=700 0 0
// configfs /sys/kernel/config configfs rw,nosuid,nodev,noexec,relatime 0 0
// selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0
// debugfs /sys/kernel/debug debugfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
// tmpfs /dev/shm tmpfs rw,seclabel,relatime 0 0
// devpts /dev/pts devpts rw,seclabel,relatime,gid=5,mode=620,ptmxmode=666 0 0
// tmpfs /sys/fs/selinux tmpfs rw,seclabel,relatime 0 0
// /dev/vda2 /proc/filesystems xfs rw,seclabel,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0
// "#,
//     );
//     assert_eq!(disks.len(), 1);
//     assert_eq!(
//         disks[0],
//         Disk {
//             type_: DiskType::Unknown(-1),
//             name: OsString::from("devpts"),
//             file_system: vec![100, 101, 118, 112, 116, 115],
//             mount_point: PathBuf::from("/dev/pts"),
//             total_space: 0,
//             available_space: 0,
//         }
//     );
// }
<|endoftext|>


<commit_before>use std::io::TcpStream;
use little_rust_tcp::data::Data;
use std::collections::ring_buf::RingBuf;
use std::sync::{Arc, Mutex};
use std::string::String;

pub enum GameState
{
    GatherClients,
    ActiveGame,
    Idle
}

pub struct DataAnalyzerStruct
{
    unprocessed_data: RingBuf<String>,
    server_data: Arc<Mutex<RingBuf<String>>>,
    game_state: GameState
}

pub trait DataAnalyzer
{
    fn new(new_server_data: Arc<Mutex<RingBuf<String>>>) -> DataAnalyzerStruct;
    fn interpret_data(&mut self);
    fn alter_state(&mut self, new_state: GameState);
}

trait PrivateDataAnalyzerTrait
{
    fn push_request_to_unprocessed(&mut self);
}

impl PrivateDataAnalyzerTrait for DataAnalyzerStruct
{
    fn push_request_to_unprocessed(&mut self)
    {
        let mut locked_server_data = self.server_data.lock();
        while locked_server_data.len() > 0
        {
            let request_string = locked_server_data.pop_front();
            self.unprocessed_data.push_back(request_string.unwrap());
        }
    }
}

impl DataAnalyzer for DataAnalyzerStruct
{
    fn new(new_server_data: Arc<Mutex<RingBuf<String>>>) -> DataAnalyzerStruct
    {
        let ringbuf = RingBuf::new();
        let state = GameState::Idle;
        return DataAnalyzerStruct{unprocessed_data: ringbuf, server_data: new_server_data, game_state: state};
    }

    fn interpret_data(&mut self)
    {
        if self.unprocessed_data.len() == 0
        {
            self.push_request_to_unprocessed();
        }
        let request_string = self.unprocessed_data.pop_front();
        if request_string != None
        {
            match self.game_state
            {
                // Place Holder
                GameState::Idle => println!("{}", request_string.unwrap()),
                GameState::ActiveGame => println!("ActiveGame"),
                GameState::GatherClients => println!("GatherClients")
            }
        }
    }

    fn alter_state(&mut self, new_state: GameState)
    {
        self.game_state = new_state;
    }
}

pub struct ServerDataStruct
{
    request_buffer: Arc<Mutex<RingBuf<String>>>
}

pub trait ServerDataConstructor
{
    fn new(request_buffer_new: Arc<Mutex<RingBuf<String>>>) -> ServerDataStruct;
}

impl ServerDataConstructor for ServerDataStruct
{
    fn new(request_buffer_new: Arc<Mutex<RingBuf<String>>>) -> ServerDataStruct
    {
        return ServerDataStruct{request_buffer: request_buffer_new};
    }
}

impl Data for ServerDataStruct
{
    fn process_request_data(&mut self, mut request: TcpStream)
    {
        let message = request.read_to_string();
        let someobject = message.ok();
        if someobject != None
        {
            let string = someobject.unwrap();
            if string.len() > 0
            {
                let mut locked_request_buffer = self.request_buffer.lock();
                locked_request_buffer.push_back(string);
            }
        }
    }
}
<commit_msg>Update server_data.rs<commit_after>use little_rust_tcp::data::Data;
use std::io::TcpStream;
use std::collections::ring_buf::RingBuf;
use std::sync::{Arc, Mutex};
use std::string::String;

pub enum GameState
{
    GatherClients,
    ActiveGame,
    Idle
}

pub struct DataAnalyzerStruct
{
    unprocessed_data: RingBuf<String>,
    server_data: Arc<Mutex<RingBuf<String>>>,
    game_state: GameState
}

pub trait DataAnalyzer
{
    fn new(new_server_data: Arc<Mutex<RingBuf<String>>>) -> DataAnalyzerStruct;
    fn interpret_data(&mut self);
    fn alter_state(&mut self, new_state: GameState);
}

trait PrivateDataAnalyzerTrait
{
    fn push_request_to_unprocessed(&mut self);
}

impl PrivateDataAnalyzerTrait for DataAnalyzerStruct
{
    fn push_request_to_unprocessed(&mut self)
    {
        let mut locked_server_data = self.server_data.lock();
        while locked_server_data.len() > 0
        {
            let request_string = locked_server_data.pop_front();
            self.unprocessed_data.push_back(request_string.unwrap());
        }
    }
}

impl DataAnalyzer for DataAnalyzerStruct
{
    fn new(new_server_data: Arc<Mutex<RingBuf<String>>>) -> DataAnalyzerStruct
    {
        let ringbuf = RingBuf::new();
        let state = GameState::Idle;
        return DataAnalyzerStruct{unprocessed_data: ringbuf, server_data: new_server_data, game_state: state};
    }

    fn interpret_data(&mut self)
    {
        if self.unprocessed_data.len() == 0
        {
            self.push_request_to_unprocessed();
        }
        let request_string = self.unprocessed_data.pop_front();
        if request_string != None
        {
            match self.game_state
            {
                // Place Holder
                GameState::Idle => println!("{}", request_string.unwrap()),
                GameState::ActiveGame => println!("ActiveGame"),
                GameState::GatherClients => println!("GatherClients")
            }
        }
    }

    fn alter_state(&mut self, new_state: GameState)
    {
        self.game_state = new_state;
    }
}

pub struct ServerDataStruct
{
    request_buffer: Arc<Mutex<RingBuf<String>>>
}

pub trait ServerDataConstructor
{
    fn new(request_buffer_new: Arc<Mutex<RingBuf<String>>>) -> ServerDataStruct;
}

impl ServerDataConstructor for ServerDataStruct
{
    fn new(request_buffer_new: Arc<Mutex<RingBuf<String>>>) -> ServerDataStruct
    {
        return ServerDataStruct{request_buffer: request_buffer_new};
    }
}

impl Data for ServerDataStruct
{
    fn process_request_data(&mut self, mut request: TcpStream)
    {
        let message = request.read_to_string();
        let someobject = message.ok();
        if someobject != None
        {
            let string = someobject.unwrap();
            if string.len() > 0
            {
                let mut locked_request_buffer = self.request_buffer.lock();
                locked_request_buffer.push_back(string);
            }
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(any(target_os = "linux", target_os = "android"))]

use crate::sync::atomic::AtomicI32;
use crate::time::Duration;

pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
    let timespec;
    let timespec_ptr = match timeout {
        Some(timeout) => {
            timespec = libc::timespec {
                tv_sec: timeout.as_secs() as _,
                tv_nsec: timeout.subsec_nanos() as _,
            };
            &timespec as *const libc::timespec
        }
        None => crate::ptr::null(),
    };
    unsafe {
        libc::syscall(
            libc::SYS_futex,
            futex as *const AtomicI32,
            libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG,
            expected,
            timespec_ptr,
        );
    }
}

pub fn futex_wake(futex: &AtomicI32) {
    unsafe {
        libc::syscall(
            libc::SYS_futex,
            futex as *const AtomicI32,
            libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
            1,
        );
    }
}
<commit_msg>Check conversion from Duration to timespec in futex_wait.<commit_after>#![cfg(any(target_os = "linux", target_os = "android"))]

use crate::convert::TryInto;
use crate::ptr::null;
use crate::sync::atomic::AtomicI32;
use crate::time::Duration;

pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
    let timespec = timeout.and_then(|d| {
        Some(libc::timespec {
            // Sleep forever if the timeout is longer than fits in a timespec.
            tv_sec: d.as_secs().try_into().ok()?,
            // This conversion never truncates, as subsec_nanos is always <1e9.
            tv_nsec: d.subsec_nanos() as _,
        })
    });
    unsafe {
        libc::syscall(
            libc::SYS_futex,
            futex as *const AtomicI32,
            libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG,
            expected,
            timespec.as_ref().map_or(null(), |d| d as *const libc::timespec),
        );
    }
}

pub fn futex_wake(futex: &AtomicI32) {
    unsafe {
        libc::syscall(
            libc::SYS_futex,
            futex as *const AtomicI32,
            libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
            1,
        );
    }
}
<|endoftext|>


<commit_before>use crate::ty::query::Providers;
use crate::hir::def_id::DefId;
use crate::hir;
use crate::ty::TyCtxt;
use syntax_pos::symbol::{sym, Symbol};
use rustc_target::spec::abi::Abi;
use crate::hir::map::blocks::FnLikeNode;
use syntax::attr;

impl<'tcx> TyCtxt<'tcx> {
    /// Whether the `def_id` counts as const fn in your current crate, considering all active
    /// feature gates
    pub fn is_const_fn(self, def_id: DefId) -> bool {
        self.is_const_fn_raw(def_id) && match self.is_unstable_const_fn(def_id) {
            Some(feature_name) => {
                // has a `rustc_const_unstable` attribute, check whether the user enabled the
                // corresponding feature gate.
                self.features()
                    .declared_lib_features
                    .iter()
                    .any(|&(sym, _)| sym == feature_name)
            },
            // functions without const stability are either stable user written
            // const fn or the user is using feature gates and we thus don't
            // care what they do
            None => true,
        }
    }

    /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
    pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
        if self.is_const_fn_raw(def_id) {
            self.lookup_stability(def_id)?.const_stability
        } else {
            None
        }
    }

    /// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
    /// for being called from stable `const fn`s (`min_const_fn`).
    ///
    /// Adding more intrinsics requires sign-off from @rust-lang/lang.
    fn is_intrinsic_min_const_fn(self, def_id: DefId) -> bool {
        match self.item_name(def_id) {
            | sym::size_of
            | sym::min_align_of
            | sym::needs_drop
            // Arithmetic:
            | sym::add_with_overflow // ~> .overflowing_add
            | sym::sub_with_overflow // ~> .overflowing_sub
            | sym::mul_with_overflow // ~> .overflowing_mul
            | sym::wrapping_add // ~> .wrapping_add
            | sym::wrapping_sub // ~> .wrapping_sub
            | sym::wrapping_mul // ~> .wrapping_mul
            | sym::saturating_add // ~> .saturating_add
            | sym::saturating_sub // ~> .saturating_sub
            | sym::unchecked_shl // ~> .wrapping_shl
            | sym::unchecked_shr // ~> .wrapping_shr
            | sym::rotate_left // ~> .rotate_left
            | sym::rotate_right // ~> .rotate_right
            | sym::ctpop // ~> .count_ones
            | sym::ctlz // ~> .leading_zeros
            | sym::cttz // ~> .trailing_zeros
            | sym::bswap // ~> .swap_bytes
            | sym::bitreverse // ~> .reverse_bits
            => true,
            _ => false,
        }
    }

    /// Returns `true` if this function must conform to `min_const_fn`
    pub fn is_min_const_fn(self, def_id: DefId) -> bool {
        // Bail out if the signature doesn't contain `const`
        if !self.is_const_fn_raw(def_id) {
            return false;
        }
        if let Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
            return self.is_intrinsic_min_const_fn(def_id);
        }

        if self.features().staged_api {
            // in order for a libstd function to be considered min_const_fn
            // it needs to be stable and have no `rustc_const_unstable` attribute
            match self.lookup_stability(def_id) {
                // stable functions with unstable const fn aren't `min_const_fn`
                Some(&attr::Stability { const_stability: Some(_), .. }) => false,
                // unstable functions don't need to conform
                Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
                // everything else needs to conform, because it would be callable from
                // other `min_const_fn` functions
                _ => true,
            }
        } else {
            // users enabling the `const_fn` feature gate can do what they want
            !self.features().const_fn
        }
    }
}

pub fn provide(providers: &mut Providers<'_>) {
    /// Const evaluability whitelist is here to check evaluability at the
    /// top level beforehand.
    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
        match tcx.fn_sig(def_id).abi() {
            Abi::RustIntrinsic |
            Abi::PlatformIntrinsic => {
                match tcx.item_name(def_id) {
                    // Keep this list in the same order as the match patterns in
                    // `librustc_mir/interpret/intrinsics.rs`
                    | sym::caller_location

                    | sym::min_align_of
                    | sym::pref_align_of
                    | sym::needs_drop
                    | sym::size_of
                    | sym::type_id
                    | sym::type_name

                    | sym::ctpop
                    | sym::cttz
                    | sym::cttz_nonzero
                    | sym::ctlz
                    | sym::ctlz_nonzero
                    | sym::bswap
                    | sym::bitreverse

                    | sym::wrapping_add
                    | sym::wrapping_sub
                    | sym::wrapping_mul
                    | sym::add_with_overflow
                    | sym::sub_with_overflow
                    | sym::mul_with_overflow

                    | sym::saturating_add
                    | sym::saturating_sub

                    | sym::unchecked_shl
                    | sym::unchecked_shr

                    | sym::rotate_left
                    | sym::rotate_right

                    | sym::ptr_offset_from

                    | sym::transmute

                    | sym::simd_insert

                    | sym::simd_extract

                    => Some(true),

                    _ => Some(false)
                }
            }
            _ => None
        }
    }

    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
    /// said intrinsic is on the whitelist for being const callable.
    fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        let hir_id = tcx.hir().as_local_hir_id(def_id)
                              .expect("Non-local call to local provider is_const_fn");

        let node = tcx.hir().get(hir_id);

        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
            whitelisted
        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
            fn_like.constness() == hir::Constness::Const
        } else if let hir::Node::Ctor(_) = node {
            true
        } else {
            false
        }
    }

    fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
            Some(stab) => {
                if cfg!(debug_assertions) && stab.promotable {
                    let sig = tcx.fn_sig(def_id);
                    assert_eq!(
                        sig.unsafety(),
                        hir::Unsafety::Normal,
                        "don't mark const unsafe fns as promotable",
                        // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                    );
                }
                stab.promotable
            },
            None => false,
        }
    }

    fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        tcx.is_const_fn(def_id) &&
            tcx.lookup_stability(def_id)
                .map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
    }

    *providers = Providers {
        is_const_fn_raw,
        is_promotable_const_fn,
        const_fn_is_allowed_fn_ptr,
        ..*providers
    };
}
<commit_msg>Explain the difference between the two whitelists<commit_after>use crate::ty::query::Providers;
use crate::hir::def_id::DefId;
use crate::hir;
use crate::ty::TyCtxt;
use syntax_pos::symbol::{sym, Symbol};
use rustc_target::spec::abi::Abi;
use crate::hir::map::blocks::FnLikeNode;
use syntax::attr;

impl<'tcx> TyCtxt<'tcx> {
    /// Whether the `def_id` counts as const fn in your current crate, considering all active
    /// feature gates
    pub fn is_const_fn(self, def_id: DefId) -> bool {
        self.is_const_fn_raw(def_id) && match self.is_unstable_const_fn(def_id) {
            Some(feature_name) => {
                // has a `rustc_const_unstable` attribute, check whether the user enabled the
                // corresponding feature gate.
                self.features()
                    .declared_lib_features
                    .iter()
                    .any(|&(sym, _)| sym == feature_name)
            },
            // functions without const stability are either stable user written
            // const fn or the user is using feature gates and we thus don't
            // care what they do
            None => true,
        }
    }

    /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
    pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
        if self.is_const_fn_raw(def_id) {
            self.lookup_stability(def_id)?.const_stability
        } else {
            None
        }
    }

    /// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
    /// for being called from stable `const fn`s (`min_const_fn`).
    ///
    /// Adding more intrinsics requires sign-off from @rust-lang/lang.
    ///
    /// This list differs from the list in `is_const_intrinsic` in the sense that any item on this
    /// list must be on the `is_const_intrinsic` list, too, because if an intrinsic is callable from
    /// stable, it must be callable at all.
    fn is_intrinsic_min_const_fn(self, def_id: DefId) -> bool {
        match self.item_name(def_id) {
            | sym::size_of
            | sym::min_align_of
            | sym::needs_drop
            // Arithmetic:
            | sym::add_with_overflow // ~> .overflowing_add
            | sym::sub_with_overflow // ~> .overflowing_sub
            | sym::mul_with_overflow // ~> .overflowing_mul
            | sym::wrapping_add // ~> .wrapping_add
            | sym::wrapping_sub // ~> .wrapping_sub
            | sym::wrapping_mul // ~> .wrapping_mul
            | sym::saturating_add // ~> .saturating_add
            | sym::saturating_sub // ~> .saturating_sub
            | sym::unchecked_shl // ~> .wrapping_shl
            | sym::unchecked_shr // ~> .wrapping_shr
            | sym::rotate_left // ~> .rotate_left
            | sym::rotate_right // ~> .rotate_right
            | sym::ctpop // ~> .count_ones
            | sym::ctlz // ~> .leading_zeros
            | sym::cttz // ~> .trailing_zeros
            | sym::bswap // ~> .swap_bytes
            | sym::bitreverse // ~> .reverse_bits
            => true,
            _ => false,
        }
    }

    /// Returns `true` if this function must conform to `min_const_fn`
    pub fn is_min_const_fn(self, def_id: DefId) -> bool {
        // Bail out if the signature doesn't contain `const`
        if !self.is_const_fn_raw(def_id) {
            return false;
        }
        if let Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
            return self.is_intrinsic_min_const_fn(def_id);
        }

        if self.features().staged_api {
            // in order for a libstd function to be considered min_const_fn
            // it needs to be stable and have no `rustc_const_unstable` attribute
            match self.lookup_stability(def_id) {
                // stable functions with unstable const fn aren't `min_const_fn`
                Some(&attr::Stability { const_stability: Some(_), .. }) => false,
                // unstable functions don't need to conform
                Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
                // everything else needs to conform, because it would be callable from
                // other `min_const_fn` functions
                _ => true,
            }
        } else {
            // users enabling the `const_fn` feature gate can do what they want
            !self.features().const_fn
        }
    }
}

pub fn provide(providers: &mut Providers<'_>) {
    /// Const evaluability whitelist is here to check evaluability at the
    /// top level beforehand.
    fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option<bool> {
        match tcx.fn_sig(def_id).abi() {
            Abi::RustIntrinsic |
            Abi::PlatformIntrinsic => {
                match tcx.item_name(def_id) {
                    // Keep this list in the same order as the match patterns in
                    // `librustc_mir/interpret/intrinsics.rs`

                    // This whitelist is a list of intrinsics that have a miri-engine implementation
                    // and can thus be called when enabling enough feature gates. The similar
                    // whitelist in `is_intrinsic_min_const_fn` (in this file), exists for allowing
                    // the intrinsics to be transitively called by stable const fns.
                    | sym::caller_location

                    | sym::min_align_of
                    | sym::pref_align_of
                    | sym::needs_drop
                    | sym::size_of
                    | sym::type_id
                    | sym::type_name

                    | sym::ctpop
                    | sym::cttz
                    | sym::cttz_nonzero
                    | sym::ctlz
                    | sym::ctlz_nonzero
                    | sym::bswap
                    | sym::bitreverse

                    | sym::wrapping_add
                    | sym::wrapping_sub
                    | sym::wrapping_mul
                    | sym::add_with_overflow
                    | sym::sub_with_overflow
                    | sym::mul_with_overflow

                    | sym::saturating_add
                    | sym::saturating_sub

                    | sym::unchecked_shl
                    | sym::unchecked_shr

                    | sym::rotate_left
                    | sym::rotate_right

                    | sym::ptr_offset_from

                    | sym::transmute

                    | sym::simd_insert

                    | sym::simd_extract

                    => Some(true),

                    _ => Some(false)
                }
            }
            _ => None
        }
    }

    /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
    /// said intrinsic is on the whitelist for being const callable.
    fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        let hir_id = tcx.hir().as_local_hir_id(def_id)
                              .expect("Non-local call to local provider is_const_fn");

        let node = tcx.hir().get(hir_id);

        if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) {
            whitelisted
        } else if let Some(fn_like) = FnLikeNode::from_node(node) {
            fn_like.constness() == hir::Constness::Const
        } else if let hir::Node::Ctor(_) = node {
            true
        } else {
            false
        }
    }

    fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
            Some(stab) => {
                if cfg!(debug_assertions) && stab.promotable {
                    let sig = tcx.fn_sig(def_id);
                    assert_eq!(
                        sig.unsafety(),
                        hir::Unsafety::Normal,
                        "don't mark const unsafe fns as promotable",
                        // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                    );
                }
                stab.promotable
            },
            None => false,
        }
    }

    fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
        tcx.is_const_fn(def_id) &&
            tcx.lookup_stability(def_id)
                .map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
    }

    *providers = Providers {
        is_const_fn_raw,
        is_promotable_const_fn,
        const_fn_is_allowed_fn_ptr,
        ..*providers
    };
}
<|endoftext|>


<commit_before>// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <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.

//! Handles translation of callees as well as other call-related
//! things.  Callees are a superset of normal rust values and sometimes
//! have different representations.  In particular, top-level fn items
//! and methods are represented as just a fn ptr and not a full
//! closure.

use attributes;
use common::{self, CrateContext};
use consts;
use declare;
use llvm::{self, ValueRef};
use monomorphize::Instance;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TypeFoldable};
use rustc::traits;
use rustc::ty::subst::Substs;
use type_of;

/// Translates a reference to a fn/method item, monomorphizing and
/// inlining as it goes.
///
/// # Parameters
///
/// - `ccx`: the crate context
/// - `instance`: the instance to be instantiated
pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                        instance: Instance<'tcx>)
                        -> ValueRef
{
    let tcx = ccx.tcx();

    debug!("get_fn(instance={:?})", instance);

    assert!(!instance.substs.needs_infer());
    assert!(!instance.substs.has_escaping_regions());
    assert!(!instance.substs.has_param_types());

    let fn_ty = common::instance_ty(ccx.tcx(), &instance);
    if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
        return llfn;
    }

    let sym = tcx.symbol_name(instance);
    debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);

    // Create a fn pointer with the substituted signature.
    let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty));
    let llptrty = type_of::type_of(ccx, fn_ptr_ty);

    let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
        // This is subtle and surprising, but sometimes we have to bitcast
        // the resulting fn pointer.  The reason has to do with external
        // functions.  If you have two crates that both bind the same C
        // library, they may not use precisely the same types: for
        // example, they will probably each declare their own structs,
        // which are distinct types from LLVM's point of view (nominal
        // types).
        //
        // Now, if those two crates are linked into an application, and
        // they contain inlined code, you can wind up with a situation
        // where both of those functions wind up being loaded into this
        // application simultaneously. In that case, the same function
        // (from LLVM's point of view) requires two types. But of course
        // LLVM won't allow one function to have two types.
        //
        // What we currently do, therefore, is declare the function with
        // one of the two types (whichever happens to come first) and then
        // bitcast as needed when the function is referenced to make sure
        // it has the type we expect.
        //
        // This can occur on either a crate-local or crate-external
        // reference. It also occurs when testing libcore and in some
        // other weird situations. Annoying.
        if common::val_ty(llfn) != llptrty {
            debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
            consts::ptrcast(llfn, llptrty)
        } else {
            debug!("get_fn: not casting pointer!");
            llfn
        }
    } else {
        let llfn = declare::declare_fn(ccx, &sym, fn_ty);
        assert_eq!(common::val_ty(llfn), llptrty);
        debug!("get_fn: not casting pointer!");

        if common::is_inline_instance(tcx, &instance) {
            attributes::inline(llfn, attributes::InlineAttr::Hint);
        }
        let attrs = instance.def.attrs(ccx.tcx());
        attributes::from_fn_attrs(ccx, &attrs, llfn);

        let instance_def_id = instance.def_id();

        // Perhaps questionable, but we assume that anything defined
        // *in Rust code* may unwind. Foreign items like `extern "C" {
        // fn foo(); }` are assumed not to unwind **unless** they have
        // a `#[unwind]` attribute.
        if !tcx.is_foreign_item(instance_def_id) {
            attributes::unwind(llfn, true);
        }

        // Apply an appropriate linkage/visibility value to our item that we
        // just declared.
        //
        // This is sort of subtle. Inside our codegen unit we started off
        // compilation by predefining all our own `TransItem` instances. That
        // is, everything we're translating ourselves is already defined. That
        // means that anything we're actually translating ourselves will have
        // hit the above branch in `get_declared_value`. As a result, we're
        // guaranteed here that we're declaring a symbol that won't get defined,
        // or in other words we're referencing a foreign value.
        //
        // So because this is a foreign value we blanket apply an external
        // linkage directive because it's coming from a different object file.
        // The visibility here is where it gets tricky. This symbol could be
        // referencing some foreign crate or foreign library (an `extern`
        // block) in which case we want to leave the default visibility. We may
        // also, though, have multiple codegen units.
        //
        // In the situation of multiple codegen units this function may be
        // referencing a function from another codegen unit. If we're
        // indeed referencing a symbol in another codegen unit then we're in one
        // of two cases:
        //
        //  * This is a symbol defined in a foreign crate and we're just
        //    monomorphizing in another codegen unit. In this case this symbols
        //    is for sure not exported, so both codegen units will be using
        //    hidden visibility. Hence, we apply a hidden visibility here.
        //
        //  * This is a symbol defined in our local crate. If the symbol in the
        //    other codegen unit is also not exported then like with the foreign
        //    case we apply a hidden visibility. If the symbol is exported from
        //    the foreign object file, however, then we leave this at the
        //    default visibility as we'll just import it naturally.
        unsafe {
            llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);

            if ccx.tcx().is_translated_function(instance_def_id) {
                if instance_def_id.is_local() {
                    if !ccx.tcx().is_exported_symbol(instance_def_id) {
                        llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                    }
                } else {
                    llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                }
            }
        }

        // FIXME(#42293) we should actually track this, but fails too many tests
        // today.
        tcx.dep_graph.with_ignore(|| {
            if ccx.use_dll_storage_attrs() &&
                tcx.is_dllimport_foreign_item(instance_def_id)
            {
                unsafe {
                    llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
                }
            }
        });
        llfn
    };

    ccx.instances().borrow_mut().insert(instance, llfn);

    llfn
}

pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                    def_id: DefId,
                                    substs: &'tcx Substs<'tcx>)
                                    -> ValueRef
{
    get_fn(
        ccx,
        ty::Instance::resolve(
            ccx.tcx(),
            ty::ParamEnv::empty(traits::Reveal::All),
            def_id,
            substs,
        ).unwrap()
    )
}
<commit_msg>stray comma<commit_after>// Copyright 2012 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <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.

//! Handles translation of callees as well as other call-related
//! things.  Callees are a superset of normal rust values and sometimes
//! have different representations.  In particular, top-level fn items
//! and methods are represented as just a fn ptr and not a full
//! closure.

use attributes;
use common::{self, CrateContext};
use consts;
use declare;
use llvm::{self, ValueRef};
use monomorphize::Instance;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TypeFoldable};
use rustc::traits;
use rustc::ty::subst::Substs;
use type_of;

/// Translates a reference to a fn/method item, monomorphizing and
/// inlining as it goes.
///
/// # Parameters
///
/// - `ccx`: the crate context
/// - `instance`: the instance to be instantiated
pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                        instance: Instance<'tcx>)
                        -> ValueRef
{
    let tcx = ccx.tcx();

    debug!("get_fn(instance={:?})", instance);

    assert!(!instance.substs.needs_infer());
    assert!(!instance.substs.has_escaping_regions());
    assert!(!instance.substs.has_param_types());

    let fn_ty = common::instance_ty(ccx.tcx(), &instance);
    if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
        return llfn;
    }

    let sym = tcx.symbol_name(instance);
    debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);

    // Create a fn pointer with the substituted signature.
    let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty));
    let llptrty = type_of::type_of(ccx, fn_ptr_ty);

    let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
        // This is subtle and surprising, but sometimes we have to bitcast
        // the resulting fn pointer.  The reason has to do with external
        // functions.  If you have two crates that both bind the same C
        // library, they may not use precisely the same types: for
        // example, they will probably each declare their own structs,
        // which are distinct types from LLVM's point of view (nominal
        // types).
        //
        // Now, if those two crates are linked into an application, and
        // they contain inlined code, you can wind up with a situation
        // where both of those functions wind up being loaded into this
        // application simultaneously. In that case, the same function
        // (from LLVM's point of view) requires two types. But of course
        // LLVM won't allow one function to have two types.
        //
        // What we currently do, therefore, is declare the function with
        // one of the two types (whichever happens to come first) and then
        // bitcast as needed when the function is referenced to make sure
        // it has the type we expect.
        //
        // This can occur on either a crate-local or crate-external
        // reference. It also occurs when testing libcore and in some
        // other weird situations. Annoying.
        if common::val_ty(llfn) != llptrty {
            debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
            consts::ptrcast(llfn, llptrty)
        } else {
            debug!("get_fn: not casting pointer!");
            llfn
        }
    } else {
        let llfn = declare::declare_fn(ccx, &sym, fn_ty);
        assert_eq!(common::val_ty(llfn), llptrty);
        debug!("get_fn: not casting pointer!");

        if common::is_inline_instance(tcx, &instance) {
            attributes::inline(llfn, attributes::InlineAttr::Hint);
        }
        let attrs = instance.def.attrs(ccx.tcx());
        attributes::from_fn_attrs(ccx, &attrs, llfn);

        let instance_def_id = instance.def_id();

        // Perhaps questionable, but we assume that anything defined
        // *in Rust code* may unwind. Foreign items like `extern "C" {
        // fn foo(); }` are assumed not to unwind **unless** they have
        // a `#[unwind]` attribute.
        if !tcx.is_foreign_item(instance_def_id) {
            attributes::unwind(llfn, true);
        }

        // Apply an appropriate linkage/visibility value to our item that we
        // just declared.
        //
        // This is sort of subtle. Inside our codegen unit we started off
        // compilation by predefining all our own `TransItem` instances. That
        // is, everything we're translating ourselves is already defined. That
        // means that anything we're actually translating ourselves will have
        // hit the above branch in `get_declared_value`. As a result, we're
        // guaranteed here that we're declaring a symbol that won't get defined,
        // or in other words we're referencing a foreign value.
        //
        // So because this is a foreign value we blanket apply an external
        // linkage directive because it's coming from a different object file.
        // The visibility here is where it gets tricky. This symbol could be
        // referencing some foreign crate or foreign library (an `extern`
        // block) in which case we want to leave the default visibility. We may
        // also, though, have multiple codegen units.
        //
        // In the situation of multiple codegen units this function may be
        // referencing a function from another codegen unit. If we're
        // indeed referencing a symbol in another codegen unit then we're in one
        // of two cases:
        //
        //  * This is a symbol defined in a foreign crate and we're just
        //    monomorphizing in another codegen unit. In this case this symbols
        //    is for sure not exported, so both codegen units will be using
        //    hidden visibility. Hence, we apply a hidden visibility here.
        //
        //  * This is a symbol defined in our local crate. If the symbol in the
        //    other codegen unit is also not exported then like with the foreign
        //    case we apply a hidden visibility. If the symbol is exported from
        //    the foreign object file, however, then we leave this at the
        //    default visibility as we'll just import it naturally.
        unsafe {
            llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);

            if ccx.tcx().is_translated_function(instance_def_id) {
                if instance_def_id.is_local() {
                    if !ccx.tcx().is_exported_symbol(instance_def_id) {
                        llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                    }
                } else {
                    llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                }
            }
        }

        // FIXME(#42293) we should actually track this, but fails too many tests
        // today.
        tcx.dep_graph.with_ignore(|| {
            if ccx.use_dll_storage_attrs() &&
                tcx.is_dllimport_foreign_item(instance_def_id)
            {
                unsafe {
                    llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
                }
            }
        });
        llfn
    };

    ccx.instances().borrow_mut().insert(instance, llfn);

    llfn
}

pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                    def_id: DefId,
                                    substs: &'tcx Substs<'tcx>)
                                    -> ValueRef
{
    get_fn(
        ccx,
        ty::Instance::resolve(
            ccx.tcx(),
            ty::ParamEnv::empty(traits::Reveal::All),
            def_id,
            substs
        ).unwrap()
    )
}
<|endoftext|>


<commit_before>// Copyright 2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <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.

//! Android-specific raw type definitions

use os::raw::{c_uint, c_uchar, c_ulonglong, c_longlong, c_ulong};
use os::unix::raw::{uid_t, gid_t};

pub type blkcnt_t = u32;
pub type blksize_t = u32;
pub type dev_t = u32;
pub type ino_t = u32;
pub type mode_t = u16;
pub type nlink_t = u16;
pub type off_t = i32;
pub type time_t = i32;

#[repr(C)]
pub struct stat {
    pub st_dev: c_ulonglong,
    pub __pad0: [c_uchar; 4],
    pub __st_ino: ino_t,
    pub st_mode: c_uint,
    pub st_nlink: c_uint,
    pub st_uid: uid_t,
    pub st_gid: gid_t,
    pub st_rdev: c_ulonglong,
    pub __pad3: [c_uchar; 4],
    pub st_size: c_longlong,
    pub st_blksize: blksize_t,
    pub st_blocks: c_ulonglong,
    pub st_atime: time_t,
    pub st_atime_nsec: c_ulong,
    pub st_mtime: time_t,
    pub st_mtime_nsec: c_ulong,
    pub st_ctime: time_t,
    pub st_ctime_nsec: c_ulong,
    pub st_ino: c_ulonglong,
}
<commit_msg>support aarch64-android raw type definitions<commit_after>// Copyright 2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <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.

//! Android-specific raw type definitions

#[doc(inline)]
pub use self::arch::{dev_t, mode_t, blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};

#[cfg(target_arch = "arm")]
mod arch {
    use os::raw::{c_uint, c_uchar, c_ulonglong, c_longlong, c_ulong};
    use os::unix::raw::{uid_t, gid_t};

    pub type dev_t = u32;
    pub type mode_t = u16;

    pub type blkcnt_t = u32;
    pub type blksize_t = u32;
    pub type ino_t = u32;
    pub type nlink_t = u16;
    pub type off_t = i32;
    pub type time_t = i32;

    #[repr(C)]
    pub struct stat {
        pub st_dev: c_ulonglong,
        pub __pad0: [c_uchar; 4],
        pub __st_ino: ino_t,
        pub st_mode: c_uint,
        pub st_nlink: c_uint,
        pub st_uid: uid_t,
        pub st_gid: gid_t,
        pub st_rdev: c_ulonglong,
        pub __pad3: [c_uchar; 4],
        pub st_size: c_longlong,
        pub st_blksize: blksize_t,
        pub st_blocks: c_ulonglong,
        pub st_atime: time_t,
        pub st_atime_nsec: c_ulong,
        pub st_mtime: time_t,
        pub st_mtime_nsec: c_ulong,
        pub st_ctime: time_t,
        pub st_ctime_nsec: c_ulong,
        pub st_ino: c_ulonglong,
    }

}

#[cfg(target_arch = "aarch64")]
mod arch {
    use os::raw::{c_uchar, c_ulong};
    use os::unix::raw::{uid_t, gid_t};

    pub type dev_t = u64;
    pub type mode_t = u32;

    pub type blkcnt_t = u64;
    pub type blksize_t = u32;
    pub type ino_t = u64;
    pub type nlink_t = u32;
    pub type off_t = i64;
    pub type time_t = i64;

    #[repr(C)]
    pub struct stat {
        pub st_dev: dev_t,
        pub __pad0: [c_uchar; 4],
        pub __st_ino: ino_t,
        pub st_mode: mode_t,
        pub st_nlink: nlink_t,
        pub st_uid: uid_t,
        pub st_gid: gid_t,
        pub st_rdev: dev_t,
        pub __pad3: [c_uchar; 4],
        pub st_size: off_t,
        pub st_blksize: blksize_t,
        pub st_blocks: blkcnt_t,
        pub st_atime: time_t,
        pub st_atime_nsec: c_ulong,
        pub st_mtime: time_t,
        pub st_mtime_nsec: c_ulong,
        pub st_ctime: time_t,
        pub st_ctime_nsec: c_ulong,
        pub st_ino: ino_t,
    }

}
<|endoftext|>