<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! ## Summary
//! One of CITA's core components that processing blocks and transaction storage,
//! provides queries, caches query records, and more.
//!
//! ### Message queuing situation
//!
//! 1. Subscribe channel
//!
//!     | Queue   | PubModule   | Message Type     |
//!     | ------- | ----------- | ---------------- |
//!     | chain   | Net         | SyncResponse     |
//!     | chain   | Net         | SyncRequest      |
//!     | chain   | Consensus   | BlockWithProof   |
//!     | chain   | Jsonrpc     | Request          |
//!     | chain   | Auth        | BlockTxHashesReq |
//!     | chain   | Executor    | ExecutedResult   |
//!     | chain   | Snapshot    | SnapshotReq      |
//!     | chain   | Executor    | StateSignal      |
//!
//! 2. Publish channel
//!
//!     | Queue | PubModule | SubModule     | Message Type  |
//!     | ----- | --------- | ------------- | ------------- |
//!     | chain | Chain     | Auth          | BlockTxHashes |
//!     | chain | Chain     | Net           | Status        |
//!     | chain | Chain     | Executor      | Request       |
//!     | chain | Chain     | Executor      | StateSignal   |
//!     | chain | Chain     | Jsonrpc       | Response      |
//!     | chain | Chain     | Net           | SyncResponse  |
//!     | chain | Chain     | Snapshot      | SnapshotResp  |
//!     | chain | Chain     | Executor      | LocalSync     |
//!     | chain | Chain     | Consensus     | RichStatus    |
//!     | chain | Chain     | Executor      | RichStatus    |
//!
//! ### Key behavior
//!
//! the key struct:
//!
//! - [`Chain`]
//! - `Forward`: `forward::Forward`
//! - `BlockProcessor`: `block_processor::BlockProcessor`
//!
//! Construct a caching mechanism with `RowLock<Vec<.. >>` or `RowLock<HashMap<.. >>` and clean it regularly.
//!
//! `Forward` listen to the message bus, handle read commands or forward write commands according to message key.
//!
//! `BlockProcessor` processing according to the forwarded information.
//!
//! [`Chain`]: ../core/libchain/chain/struct.Chain.html
//!

extern crate byteorder;
extern crate cita_types;
extern crate clap;
extern crate common_types as types;
extern crate core;
extern crate dotenv;
extern crate error;
extern crate jsonrpc_types;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate proof;
extern crate pubsub;
extern crate serde_json;
#[macro_use]
extern crate util;
extern crate cita_directories;
extern crate db as cita_db;

mod block_processor;
mod forward;

use block_processor::BlockProcessor;
use cita_db::kvdb::{Database, DatabaseConfig};
use cita_directories::DataPath;
use clap::App;
use core::db;
use core::libchain;
use forward::Forward;
use libproto::router::{MsgType, RoutingKey, SubModules};
use pubsub::{channel, start_pubsub};
use std::sync::Arc;
use std::thread;
use std::time;
use std::time::Duration;
use util::set_panic_handler;

include!(concat!(env!("OUT_DIR"), "/build_info.rs"));

fn main() {
    micro_service_init!("cita-chain", "CITA:chain");
    info!("Version: {}", get_build_info_str(true));

    let matches = App::new("chain")
        .version(get_build_info_str(true))
        .long_version(get_build_info_str(false))
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .arg_from_usage("-c, --config=[FILE] 'Sets a chain config file'")
        .get_matches();

    let config_path = matches.value_of("config").unwrap_or("chain.toml");

    let (tx, rx) = channel::unbounded();
    let (ctx_pub, crx_pub) = channel::unbounded();
    start_pubsub(
        "chain",
        routing_key!([
            Net >> SyncResponse,
            Net >> SyncRequest,
            Consensus >> BlockWithProof,
            Jsonrpc >> Request,
            Auth >> BlockTxHashesReq,
            Executor >> ExecutedResult,
            Executor >> StateSignal,
            Snapshot >> SnapshotReq,
        ]),
        tx,
        crx_pub,
    );

    let nosql_path = DataPath::nosql_path();
    trace!("nosql_path is {:?}", nosql_path);
    let db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS);
    let db = Database::open(&db_config, &nosql_path).unwrap();

    let chain_config = libchain::chain::Config::new(config_path);
    let chain = Arc::new(libchain::chain::Chain::init_chain(
        Arc::new(db),
        &chain_config,
    ));

    let (write_sender, write_receiver) = channel::unbounded();
    let forward = Forward::new(Arc::clone(&chain), ctx_pub.clone(), write_sender);

    let block_processor = BlockProcessor::new(Arc::clone(&chain), ctx_pub);

    //chain 读写分离
    //chain 读数据 => 查询数据
    thread::spawn(move || loop {
        if let Ok((key, msg)) = rx.recv() {
            forward.dispatch_msg(&key, &msg);
        }
    });

    //chain 写数据 => 添加块
    thread::spawn(move || {
        let mut timeout_factor = 0u8;
        loop {
            if let Ok(einfo) = write_receiver
                .recv_timeout(Duration::new(18 * (2u64.pow(u32::from(timeout_factor))), 0))
            {
                block_processor.set_executed_result(&einfo);
                timeout_factor = 0;
            } else if !*block_processor.chain.is_snapshot.read() {
                // Here will be these status:
                // 1. Executor process restarts, lost cached block information.
                // 2. Executor encountered an invalid block and cleared the block map.
                // 3. Bft restarted, lost chain status information, unable to consensus, unable to generate block.
                //
                // This will trigger:
                // 1. Network retransmits block information or initiates a synchronization request,
                //    and then the executor will receive a block message
                // 2. Bft will receive the latest status of chain
                info!("Chain enters the timeout retransmission phase");
                block_processor.reset_max_store_height();
                block_processor.signal_to_executor();
                block_processor.broadcast_current_status();
                if timeout_factor < 6 {
                    timeout_factor += 1
                }
            }
        }
    });

    //garbage collect
    loop {
        thread::sleep(time::Duration::from_millis(1000));
        if chain.cache_size().total() > chain_config.cache_size.unwrap() / 2 {
            trace!("cache_manager begin collect garbage...");
            chain.collect_garbage();
        }
    }
}
<commit_msg>update comment<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! ## Summary
//! One of CITA's core components that processing blocks and transaction storage,
//! provides queries, caches query records, and more.
//!
//! ### Message queuing situation
//!
//! 1. Subscribe channel
//!
//!     | Queue   | PubModule   | Message Type     |
//!     | ------- | ----------- | ---------------- |
//!     | chain   | Net         | SyncResponse     |
//!     | chain   | Net         | SyncRequest      |
//!     | chain   | Consensus   | BlockWithProof   |
//!     | chain   | Jsonrpc     | Request          |
//!     | chain   | Auth        | BlockTxHashesReq |
//!     | chain   | Executor    | ExecutedResult   |
//!     | chain   | Snapshot    | SnapshotReq      |
//!     | chain   | Executor    | StateSignal      |
//!
//! 2. Publish channel
//!
//!     | Queue | PubModule | SubModule     | Message Type  |
//!     | ----- | --------- | ------------- | ------------- |
//!     | chain | Chain     | Auth          | BlockTxHashes |
//!     | chain | Chain     | Net           | Status        |
//!     | chain | Chain     | Executor      | Request       |
//!     | chain | Chain     | Executor      | StateSignal   |
//!     | chain | Chain     | Jsonrpc       | Response      |
//!     | chain | Chain     | Net           | SyncResponse  |
//!     | chain | Chain     | Snapshot      | SnapshotResp  |
//!     | chain | Chain     | Executor      | LocalSync     |
//!     | chain | Chain     | Consensus     | RichStatus    |
//!     | chain | Chain     | Executor      | RichStatus    |
//!
//! ### Key behavior
//!
//! the key struct:
//!
//! - [`Chain`]
//! - `Forward`: `forward::Forward`
//! - `BlockProcessor`: `block_processor::BlockProcessor`
//!
//! Construct a caching mechanism with `RowLock<Vec<.. >>` or `RowLock<HashMap<.. >>` and clean it regularly.
//!
//! `Forward` listen to the message bus, handle read commands or forward write commands according to message key.
//!
//! `BlockProcessor` processing according to the forwarded information.
//!
//! [`Chain`]: ../core/libchain/chain/struct.Chain.html
//!

extern crate byteorder;
extern crate cita_types;
extern crate clap;
extern crate common_types as types;
extern crate core;
extern crate dotenv;
extern crate error;
extern crate jsonrpc_types;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate proof;
extern crate pubsub;
extern crate serde_json;
#[macro_use]
extern crate util;
extern crate cita_directories;
extern crate db as cita_db;

mod block_processor;
mod forward;

use block_processor::BlockProcessor;
use cita_db::kvdb::{Database, DatabaseConfig};
use cita_directories::DataPath;
use clap::App;
use core::db;
use core::libchain;
use forward::Forward;
use libproto::router::{MsgType, RoutingKey, SubModules};
use pubsub::{channel, start_pubsub};
use std::sync::Arc;
use std::thread;
use std::time;
use std::time::Duration;
use util::set_panic_handler;

include!(concat!(env!("OUT_DIR"), "/build_info.rs"));

fn main() {
    micro_service_init!("cita-chain", "CITA:chain");
    info!("Version: {}", get_build_info_str(true));

    let matches = App::new("chain")
        .version(get_build_info_str(true))
        .long_version(get_build_info_str(false))
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .arg_from_usage("-c, --config=[FILE] 'Sets a chain config file'")
        .get_matches();

    let config_path = matches.value_of("config").unwrap_or("chain.toml");

    let (tx, rx) = channel::unbounded();
    let (ctx_pub, crx_pub) = channel::unbounded();
    start_pubsub(
        "chain",
        routing_key!([
            Net >> SyncResponse,
            Net >> SyncRequest,
            Consensus >> BlockWithProof,
            Jsonrpc >> Request,
            Auth >> BlockTxHashesReq,
            Executor >> ExecutedResult,
            Executor >> StateSignal,
            Snapshot >> SnapshotReq,
        ]),
        tx,
        crx_pub,
    );

    let nosql_path = DataPath::nosql_path();
    trace!("nosql_path is {:?}", nosql_path);
    let db_config = DatabaseConfig::with_columns(db::NUM_COLUMNS);
    let db = Database::open(&db_config, &nosql_path).unwrap();

    let chain_config = libchain::chain::Config::new(config_path);
    let chain = Arc::new(libchain::chain::Chain::init_chain(
        Arc::new(db),
        &chain_config,
    ));

    let (write_sender, write_receiver) = channel::unbounded();
    let forward = Forward::new(Arc::clone(&chain), ctx_pub.clone(), write_sender);

    let block_processor = BlockProcessor::new(Arc::clone(&chain), ctx_pub);

    // Two threads, one for reading, one for writing
    // Read: dispatch msg
    thread::spawn(move || loop {
        if let Ok((key, msg)) = rx.recv() {
            forward.dispatch_msg(&key, &msg);
        }
    });

    // Write: add block
    thread::spawn(move || {
        let mut timeout_factor = 0u8;
        loop {
            if let Ok(einfo) = write_receiver
                .recv_timeout(Duration::new(18 * (2u64.pow(u32::from(timeout_factor))), 0))
            {
                block_processor.set_executed_result(&einfo);
                timeout_factor = 0;
            } else if !*block_processor.chain.is_snapshot.read() {
                // Here will be these status:
                // 1. Executor process restarts, lost cached block information.
                // 2. Executor encountered an invalid block and cleared the block map.
                // 3. Bft restarted, lost chain status information, unable to consensus, unable to generate block.
                //
                // This will trigger:
                // 1. Network retransmits block information or initiates a synchronization request,
                //    and then the executor will receive a block message
                // 2. Bft will receive the latest status of chain
                info!("Chain enters the timeout retransmission phase");
                block_processor.reset_max_store_height();
                block_processor.signal_to_executor();
                block_processor.broadcast_current_status();
                if timeout_factor < 6 {
                    timeout_factor += 1
                }
            }
        }
    });

    //garbage collect
    loop {
        thread::sleep(time::Duration::from_millis(1000));
        if chain.cache_size().total() > chain_config.cache_size.unwrap() / 2 {
            trace!("cache_manager begin collect garbage...");
            chain.collect_garbage();
        }
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::path::{Path, PathBuf};

use devicemapper::{Bytes, DmDevice, DmName, DM, IEC, SECTOR_SIZE, Sectors, ThinDev, ThinDevId,
                   ThinStatus, ThinPoolDev};

use mnt::{MountParam, MountIter};
use nix::sys::statvfs::statvfs;
use nix::sys::statvfs::vfs::Statvfs;
use nix::mount::{mount, MsFlags, umount};
use tempdir::TempDir;

use super::super::super::engine::{Filesystem, HasName, HasUuid};
use super::super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::super::types::FilesystemUuid;

use super::super::serde_structs::{FilesystemSave, Recordable};

use super::util::{create_fs, set_uuid, xfs_growfs};

/// TODO: confirm that 256 MiB leaves enough time for stratisd to respond and extend before
/// the filesystem is out of space.
pub const FILESYSTEM_LOWATER: Sectors = Sectors(256 * IEC::Mi / (SECTOR_SIZE as u64)); // = 256 MiB

#[derive(Debug)]
pub struct StratFilesystem {
    fs_id: FilesystemUuid,
    name: String,
    thin_dev: ThinDev,
}

pub enum FilesystemStatus {
    Good,
    XfsGrowFailed,
    ThinDevExtendFailed,
    Failed,
}

impl StratFilesystem {
    /// Create a StratFilesystem on top of the given ThinDev.
    pub fn initialize(fs_id: FilesystemUuid,
                      name: &str,
                      thin_dev: ThinDev)
                      -> EngineResult<StratFilesystem> {
        let fs = StratFilesystem::setup(fs_id, name, thin_dev);

        create_fs(&fs.devnode(), fs_id)?;
        Ok(fs)
    }

    /// Build a StratFilesystem that includes the ThinDev and related info.
    pub fn setup(fs_id: FilesystemUuid, name: &str, thin_dev: ThinDev) -> StratFilesystem {
        StratFilesystem {
            fs_id: fs_id,
            name: name.to_owned(),
            thin_dev: thin_dev,
        }
    }

    /// Create a snapshot of the filesystem. Return the resulting filesystem/ThinDev
    /// to the caller.  Use snapshot_name for the Stratis filesytem name.  Use
    /// snapshot_dmname for the new name of the ThinDev allocated for the snapshot.
    /// Mounting a filesytem with a duplicate UUID would require special handling,
    /// so snapshot_fs_uuid is used to update the new snapshot filesystem so it has
    /// a unique UUID.
    pub fn snapshot(&self,
                    dm: &DM,
                    thin_pool: &ThinPoolDev,
                    snapshot_name: &str,
                    snapshot_dmname: &DmName,
                    snapshot_fs_uuid: FilesystemUuid,
                    snapshot_thin_id: ThinDevId)
                    -> EngineResult<StratFilesystem> {

        match self.thin_dev
                  .snapshot(dm, thin_pool, snapshot_dmname, snapshot_thin_id) {
            Ok(thin_dev) => {
                // If the source is mounted, XFS puts a dummy record in the
                // log to enforce replay of the snapshot to deal with any
                // orphaned inodes. The dummy record put the log in a dirty
                // state. xfs_admin won't allow a filesystem UUID
                // to be updated when the log is dirty.  To clear the log
                // we mount/unmount the filesystem before updating the UUID.
                //
                // If the source is unmounted the XFS log will be clean so
                // we can skip the mount/unmount.
                if self.get_mount_point()?.is_some() {
                    let tmp_dir = TempDir::new("stratis_mp_")?;
                    // Mount the snapshot with the "nouuid" option. mount
                    // will fail due to duplicate UUID otherwise.
                    mount(Some(&thin_dev.devnode()),
                          tmp_dir.path(),
                          Some("xfs"),
                          MsFlags::empty(),
                          Some("nouuid"))?;
                    umount(tmp_dir.path())?;
                }
                set_uuid(&thin_dev.devnode(), snapshot_fs_uuid)?;
                Ok(StratFilesystem::setup(snapshot_fs_uuid, snapshot_name, thin_dev))
            }
            Err(e) => {
                Err(EngineError::Engine(ErrorEnum::Error,
                                        format!("failed to create {} snapshot for {} - {}",
                                                snapshot_name,
                                                self.name,
                                                e)))
            }
        }
    }

    /// check if filesystem is getting full and needs to be extended
    /// TODO: deal with the thindev in a Fail state.
    pub fn check(&mut self, dm: &DM) -> EngineResult<FilesystemStatus> {
        match self.thin_dev.status(dm)? {
            ThinStatus::Working(_) => {
                if let Some(mount_point) = self.get_mount_point()? {
                    let (fs_total_bytes, fs_total_used_bytes) = fs_usage(&mount_point)?;
                    let free_bytes = fs_total_bytes - fs_total_used_bytes;
                    if free_bytes.sectors() < FILESYSTEM_LOWATER {
                        let extend_size = self.extend_size(self.thin_dev.size());
                        if self.thin_dev.extend(dm, extend_size).is_err() {
                            return Ok(FilesystemStatus::ThinDevExtendFailed);
                        }
                        if xfs_growfs(&mount_point).is_err() {
                            return Ok(FilesystemStatus::XfsGrowFailed);
                        }
                    }
                }
                // TODO: do anything when filesystem is not mounted?
                // TODO: periodically kick off fstrim?
            }
            ThinStatus::Fail => return Ok(FilesystemStatus::Failed),
        }
        Ok(FilesystemStatus::Good)
    }

    /// The thin id for the thin device that backs this filesystem.
    #[cfg(test)]
    pub fn thin_id(&self) -> ThinDevId {
        self.thin_dev.id()
    }

    /// Return an extend size for the thindev under the filesystem
    /// TODO: returning the current size will double the space provisoned to
    /// the thin device.  We should determine if this is a reasonable value.
    fn extend_size(&self, current_size: Sectors) -> Sectors {
        current_size
    }

    /// Get one (non-deterministic in the presence of errors) of the mount_point(s) for the file
    /// system that is contained on the block device referred to as self.devnode(), i.e. the device
    /// node, while ignoring parse errors as long as at least one mount point is found.
    pub fn get_mount_point(&self) -> EngineResult<Option<PathBuf>> {
        let device_node = self.devnode();
        let search = device_node.to_str().ok_or_else(|| EngineError::Engine(ErrorEnum::Error,
                                    format!("Unable to represent devnode as string {:?}", *self)))?;

        let m_iter = MountIter::new_from_proc()
            .map_err(|e| {
                         EngineError::Engine(ErrorEnum::Error,
                                             format!("Error reading /proc/mounts {:?}", e))
                     })?;

        let mut last_error: Option<String> = None;
        for mp in m_iter {
            match mp {
                Ok(mount) => {
                    if mount.contains(&MountParam::Spec(search)) {
                        return Ok(Some(mount.file));
                    }
                }
                Err(e) => {
                    last_error = Some(format!("Error during parsing {:?} {:?}", *self, e));
                }
            }
        }

        last_error.map_or(Ok(None), |e| Err(EngineError::Engine(ErrorEnum::Error, e)))
    }

    /// Tear down the filesystem.
    pub fn teardown(self, dm: &DM) -> EngineResult<()> {
        Ok(self.thin_dev.teardown(dm)?)
    }

    /// Set the name of this filesystem to name.
    pub fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    /// Destroy the filesystem.
    pub fn destroy(self, dm: &DM, thin_pool: &ThinPoolDev) -> EngineResult<()> {
        Ok(self.thin_dev.destroy(dm, thin_pool)?)
    }
}

impl HasName for StratFilesystem {
    fn name(&self) -> &str {
        &self.name
    }
}

impl HasUuid for StratFilesystem {
    fn uuid(&self) -> FilesystemUuid {
        self.fs_id
    }
}

impl Filesystem for StratFilesystem {
    fn devnode(&self) -> PathBuf {
        self.thin_dev.devnode()
    }
}

impl Recordable<FilesystemSave> for StratFilesystem {
    fn record(&self) -> FilesystemSave {
        FilesystemSave {
            name: self.name.clone(),
            uuid: self.fs_id,
            thin_id: self.thin_dev.id(),
            size: self.thin_dev.size(),
        }
    }
}

/// Return total bytes allocated to the filesystem, total bytes used by data/metadata
pub fn fs_usage(mount_point: &Path) -> EngineResult<(Bytes, Bytes)> {
    let mut stat = Statvfs::default();
    statvfs(mount_point, &mut stat)?;
    Ok((Bytes(stat.f_bsize * stat.f_blocks), Bytes(stat.f_bsize * (stat.f_blocks - stat.f_bfree))))
}
<commit_msg>cast stat.f_bsize to u64<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::path::{Path, PathBuf};

use devicemapper::{Bytes, DmDevice, DmName, DM, IEC, SECTOR_SIZE, Sectors, ThinDev, ThinDevId,
                   ThinStatus, ThinPoolDev};

use mnt::{MountParam, MountIter};
use nix::sys::statvfs::statvfs;
use nix::sys::statvfs::vfs::Statvfs;
use nix::mount::{mount, MsFlags, umount};
use tempdir::TempDir;

use super::super::super::engine::{Filesystem, HasName, HasUuid};
use super::super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::super::types::FilesystemUuid;

use super::super::serde_structs::{FilesystemSave, Recordable};

use super::util::{create_fs, set_uuid, xfs_growfs};

/// TODO: confirm that 256 MiB leaves enough time for stratisd to respond and extend before
/// the filesystem is out of space.
pub const FILESYSTEM_LOWATER: Sectors = Sectors(256 * IEC::Mi / (SECTOR_SIZE as u64)); // = 256 MiB

#[derive(Debug)]
pub struct StratFilesystem {
    fs_id: FilesystemUuid,
    name: String,
    thin_dev: ThinDev,
}

pub enum FilesystemStatus {
    Good,
    XfsGrowFailed,
    ThinDevExtendFailed,
    Failed,
}

impl StratFilesystem {
    /// Create a StratFilesystem on top of the given ThinDev.
    pub fn initialize(fs_id: FilesystemUuid,
                      name: &str,
                      thin_dev: ThinDev)
                      -> EngineResult<StratFilesystem> {
        let fs = StratFilesystem::setup(fs_id, name, thin_dev);

        create_fs(&fs.devnode(), fs_id)?;
        Ok(fs)
    }

    /// Build a StratFilesystem that includes the ThinDev and related info.
    pub fn setup(fs_id: FilesystemUuid, name: &str, thin_dev: ThinDev) -> StratFilesystem {
        StratFilesystem {
            fs_id: fs_id,
            name: name.to_owned(),
            thin_dev: thin_dev,
        }
    }

    /// Create a snapshot of the filesystem. Return the resulting filesystem/ThinDev
    /// to the caller.  Use snapshot_name for the Stratis filesytem name.  Use
    /// snapshot_dmname for the new name of the ThinDev allocated for the snapshot.
    /// Mounting a filesytem with a duplicate UUID would require special handling,
    /// so snapshot_fs_uuid is used to update the new snapshot filesystem so it has
    /// a unique UUID.
    pub fn snapshot(&self,
                    dm: &DM,
                    thin_pool: &ThinPoolDev,
                    snapshot_name: &str,
                    snapshot_dmname: &DmName,
                    snapshot_fs_uuid: FilesystemUuid,
                    snapshot_thin_id: ThinDevId)
                    -> EngineResult<StratFilesystem> {

        match self.thin_dev
                  .snapshot(dm, thin_pool, snapshot_dmname, snapshot_thin_id) {
            Ok(thin_dev) => {
                // If the source is mounted, XFS puts a dummy record in the
                // log to enforce replay of the snapshot to deal with any
                // orphaned inodes. The dummy record put the log in a dirty
                // state. xfs_admin won't allow a filesystem UUID
                // to be updated when the log is dirty.  To clear the log
                // we mount/unmount the filesystem before updating the UUID.
                //
                // If the source is unmounted the XFS log will be clean so
                // we can skip the mount/unmount.
                if self.get_mount_point()?.is_some() {
                    let tmp_dir = TempDir::new("stratis_mp_")?;
                    // Mount the snapshot with the "nouuid" option. mount
                    // will fail due to duplicate UUID otherwise.
                    mount(Some(&thin_dev.devnode()),
                          tmp_dir.path(),
                          Some("xfs"),
                          MsFlags::empty(),
                          Some("nouuid"))?;
                    umount(tmp_dir.path())?;
                }
                set_uuid(&thin_dev.devnode(), snapshot_fs_uuid)?;
                Ok(StratFilesystem::setup(snapshot_fs_uuid, snapshot_name, thin_dev))
            }
            Err(e) => {
                Err(EngineError::Engine(ErrorEnum::Error,
                                        format!("failed to create {} snapshot for {} - {}",
                                                snapshot_name,
                                                self.name,
                                                e)))
            }
        }
    }

    /// check if filesystem is getting full and needs to be extended
    /// TODO: deal with the thindev in a Fail state.
    pub fn check(&mut self, dm: &DM) -> EngineResult<FilesystemStatus> {
        match self.thin_dev.status(dm)? {
            ThinStatus::Working(_) => {
                if let Some(mount_point) = self.get_mount_point()? {
                    let (fs_total_bytes, fs_total_used_bytes) = fs_usage(&mount_point)?;
                    let free_bytes = fs_total_bytes - fs_total_used_bytes;
                    if free_bytes.sectors() < FILESYSTEM_LOWATER {
                        let extend_size = self.extend_size(self.thin_dev.size());
                        if self.thin_dev.extend(dm, extend_size).is_err() {
                            return Ok(FilesystemStatus::ThinDevExtendFailed);
                        }
                        if xfs_growfs(&mount_point).is_err() {
                            return Ok(FilesystemStatus::XfsGrowFailed);
                        }
                    }
                }
                // TODO: do anything when filesystem is not mounted?
                // TODO: periodically kick off fstrim?
            }
            ThinStatus::Fail => return Ok(FilesystemStatus::Failed),
        }
        Ok(FilesystemStatus::Good)
    }

    /// The thin id for the thin device that backs this filesystem.
    #[cfg(test)]
    pub fn thin_id(&self) -> ThinDevId {
        self.thin_dev.id()
    }

    /// Return an extend size for the thindev under the filesystem
    /// TODO: returning the current size will double the space provisoned to
    /// the thin device.  We should determine if this is a reasonable value.
    fn extend_size(&self, current_size: Sectors) -> Sectors {
        current_size
    }

    /// Get one (non-deterministic in the presence of errors) of the mount_point(s) for the file
    /// system that is contained on the block device referred to as self.devnode(), i.e. the device
    /// node, while ignoring parse errors as long as at least one mount point is found.
    pub fn get_mount_point(&self) -> EngineResult<Option<PathBuf>> {
        let device_node = self.devnode();
        let search = device_node.to_str().ok_or_else(|| EngineError::Engine(ErrorEnum::Error,
                                    format!("Unable to represent devnode as string {:?}", *self)))?;

        let m_iter = MountIter::new_from_proc()
            .map_err(|e| {
                         EngineError::Engine(ErrorEnum::Error,
                                             format!("Error reading /proc/mounts {:?}", e))
                     })?;

        let mut last_error: Option<String> = None;
        for mp in m_iter {
            match mp {
                Ok(mount) => {
                    if mount.contains(&MountParam::Spec(search)) {
                        return Ok(Some(mount.file));
                    }
                }
                Err(e) => {
                    last_error = Some(format!("Error during parsing {:?} {:?}", *self, e));
                }
            }
        }

        last_error.map_or(Ok(None), |e| Err(EngineError::Engine(ErrorEnum::Error, e)))
    }

    /// Tear down the filesystem.
    pub fn teardown(self, dm: &DM) -> EngineResult<()> {
        Ok(self.thin_dev.teardown(dm)?)
    }

    /// Set the name of this filesystem to name.
    pub fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    /// Destroy the filesystem.
    pub fn destroy(self, dm: &DM, thin_pool: &ThinPoolDev) -> EngineResult<()> {
        Ok(self.thin_dev.destroy(dm, thin_pool)?)
    }
}

impl HasName for StratFilesystem {
    fn name(&self) -> &str {
        &self.name
    }
}

impl HasUuid for StratFilesystem {
    fn uuid(&self) -> FilesystemUuid {
        self.fs_id
    }
}

impl Filesystem for StratFilesystem {
    fn devnode(&self) -> PathBuf {
        self.thin_dev.devnode()
    }
}

impl Recordable<FilesystemSave> for StratFilesystem {
    fn record(&self) -> FilesystemSave {
        FilesystemSave {
            name: self.name.clone(),
            uuid: self.fs_id,
            thin_id: self.thin_dev.id(),
            size: self.thin_dev.size(),
        }
    }
}

/// Return total bytes allocated to the filesystem, total bytes used by data/metadata
pub fn fs_usage(mount_point: &Path) -> EngineResult<(Bytes, Bytes)> {
    let mut stat = Statvfs::default();
    statvfs(mount_point, &mut stat)?;

    // stat.f_bsize is type c_ulong, which is 32 bits on some archs. Upcast.
    let f_bsize = stat.f_bsize as u64;

    Ok((Bytes(f_bsize * stat.f_blocks), Bytes(f_bsize * (stat.f_blocks - stat.f_bfree))))
}
<|endoftext|>


<commit_before>use std::mem;

use super::cartridge::Cartridge;
use super::sound::Sound;
use super::lcd::Lcd;
use super::constants::*;

use num::FromPrimitive;
use std::io;
use std::collections::VecDeque;

use std::fs::File;
use std::io::Write;

#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Bus {
    pub cartridge: Cartridge,
    // TODO: Expose in better way
    pub lcd: Lcd,
    pub sound: Sound,
    wram: Vec<u8>,
    hram: Vec<u8>,
    pub io: IoPorts,
}

enum_from_primitive! {
#[derive(Debug,PartialEq)]
enum IoAddress {
    Joypad = 0xff00,
    Sb = 0xff01,
    Sc = 0xff02,
    Div = 0xff04,
    Tima = 0xff05,
    Tma = 0xff06,
    Tac = 0xff07,
    If = 0xff0f,
    Ie = 0xffff
}
}

#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Timers {
    div: u8,
    tima: u8,
    tma: u8,
    tac: u8,

    div_counter: isize,
    tima_counter: isize,
    tima_running: bool,
}

impl Timers {
    fn new() -> Timers {
        let mut timers = Timers {
            div: 0,
            tima: 0,
            tma: 0,
            tac: 0,
            div_counter: 0,
            tima_counter: 0,
            tima_running: false,
        };
        timers.write_tac(0);
        timers
    }

    pub fn tick(&mut self, cycles: usize) -> u8 {
        let mut interrupt = 0u8;

        if cycles > 12 {
            interrupt |= self.tick(12);
            interrupt |= self.tick(cycles - 12);
            return interrupt;
        }

        self.div_counter -= cycles as isize;
        if self.div_counter <= 0 {
            self.div_counter += (CPU_FREQ / 16384) as isize;
            self.div = self.div.wrapping_add(1);
        }

        if self.tima_running {
            self.tima_counter -= cycles as isize;
            if self.tima_counter <= 0 {
                self.tima_counter += (CPU_FREQ / self.get_tac_freq()) as isize;
                self.tima = self.tima.wrapping_add(1);
                if self.tima == 0 {
                    interrupt |= INT_MASK_TIMER;
                    self.tima = self.tma;
                }
            }
        }
        interrupt
    }

    fn get_tac_freq(&self) -> usize {
        match self.tac & 0x03 {
            0b00 => 4096,
            0b01 => 262144,
            0b10 => 65536,
            0b11 => 16384,
            _ => unreachable!(),
        }
    }
    fn write_div(&mut self) {
        self.div = 0;
        self.div_counter = 0;
    }
    fn write_tima(&mut self, value: u8) {
        self.tima = value;
        // self.tima_counter = (CPU_FREQ / self.get_tac_freq()) as isize - 4;
    }
    fn write_tma(&mut self, value: u8) {
        self.tma = value;
    }
    fn write_tac(&mut self, value: u8) {
        self.tac = value & 0x07;
        self.tima_running = (self.tac & 0x04) != 0;
        trace!("Setting tima freq to {}", self.get_tac_freq());
    }
}

#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct IoPorts {
    joypad: u8,
    serial_data: u8,
    serial_transfer_control: u8,
    pub timers: Timers,

    // TODO expose through other means
    pub interrupt_enable: u8,
    pub interrupt_flags: u8,

    pub joypad_all_buttons: u8,

    pub serial_out: VecDeque<u8>,
}

impl IoPorts {
    fn new() -> IoPorts {
        IoPorts {
            joypad: 0xff,
            serial_data: 0,
            serial_transfer_control: 0,
            timers: Timers::new(),
            interrupt_enable: 0,
            interrupt_flags: 0,
            joypad_all_buttons: 0xff,
            serial_out: VecDeque::new()
        }
    }

    fn write(&mut self, addr: u16, value: u8) {
        match IoAddress::from_u16(addr) {
            Some(x) => {
                trace!("Writing 0x{:02X} to {:?} (0x{:04X})", value, x, addr);
                match x {
                    IoAddress::Joypad => {
                        self.joypad = value | !0x30;
                    }
                    IoAddress::Sb => self.serial_data = value,
                    IoAddress::Sc => {
                        if value & 0x80 == 0x80 {
                            self.serial_out.push_back(self.serial_data);
                        }
                    }
                    IoAddress::Div => self.timers.write_div(),
                    IoAddress::Tima => self.timers.write_tima(value),
                    IoAddress::Tma => self.timers.write_tma(value),
                    IoAddress::Tac => self.timers.write_tac(value),
                    IoAddress::Ie => self.interrupt_enable = value & 0x1f,
                    IoAddress::If => self.interrupt_flags = value & 0x1f,
                }
            }
            None => {
                debug!("WRITE 0x{:02X} to IOPORT 0x{:04X} not recognized (ignoring)",
                       value,
                       addr);
            }
        }
    }

    fn read(&self, addr: u16) -> u8 {
        match IoAddress::from_u16(addr) {
            Some(x) => {
                let value = match x {
                    IoAddress::Sb => self.serial_data,
                    IoAddress::Joypad => {
                        (if self.joypad & 0x10 == 0 {
                            self.joypad_all_buttons & 0xf
                        } else {
                            0
                        }) |
                        (if self.joypad & 0x20 == 0 {
                            self.joypad_all_buttons >> 4
                        } else {
                            0
                        }) | self.joypad & 0xf0
                    }
                    IoAddress::Sc => self.serial_transfer_control,
                    IoAddress::Div => self.timers.div,
                    IoAddress::Tima => self.timers.tima,
                    IoAddress::Tma => self.timers.tma,
                    IoAddress::Tac => self.timers.tac,
                    IoAddress::Ie => self.interrupt_enable,
                    IoAddress::If => self.interrupt_flags,
                    // _ => panic!("IOPORT {:02X} NOT MAPPED FOR READING", addr)
                };
                value
            }
            None => {
                warn!("READ from IOPORT 0x{:04X} not recognized (ignoring)", addr);
                0
            }
        }
    }
}

impl Bus {
    pub fn new(cartridge: Cartridge) -> Bus {
        Bus {
            hram: vec![0u8; 0x7f],
            wram: vec![0u8; 0x2000],
            lcd: Lcd::new(),
            sound: Sound::new(),
            cartridge: cartridge,
            io: IoPorts::new(),
        }
    }

    pub fn dequeue_samples(&mut self) -> Vec<(i8, i8)> {
        self.sound.dump_audio()
    }

    pub fn dump_wram(&mut self) -> io::Result<()> {
        let mut f = try!(File::create("wram.dump"));
        try!(f.write_all(&self.wram));
        Ok(())
    }

    pub fn read(&self, addr: u16) -> u8 {
        let value = match addr {
            MEM_LCD_IO_DMA => 0xff,
            MEM_CARTRIDGE_ROM_START...MEM_CARTRIDGE_ROM_END =>
                self.cartridge.read(addr),
            MEM_LCD_VRAM_START...MEM_LCD_VRAM_END => self.lcd.read(addr),
            MEM_CARTRIDGE_RAM_START...MEM_CARTRIDGE_RAM_END =>
                self.cartridge.read(addr),
            0xc000...0xdfff => self.wram[(addr - 0xc000) as usize],
            0xe000...0xfdff => self.wram[(addr - 0xe000) as usize],
            MEM_LCD_OAM_START...MEM_LCD_OAM_END => self.lcd.read(addr),
            0xff10...0xff27 => self.sound.read(addr),
            MEM_LCD_IO_START...MEM_LCD_IO_END => self.lcd.read(addr),
            0xff00...0xff09 | 0xff28...0xff7f | 0xffff => self.io.read(addr),
            0xff80...0xfffe => self.hram[(addr - 0xff80) as usize],
            _ => {
                trace!("Reading unmapped {:x}, just returning 0xff", addr);
                0xff
            }
        };
        value
    }
    pub fn read16(&self, addr: u16) -> u16 {
        self.read(addr) as u16 | (self.read(addr + 1) as u16) << 8
    }
    pub fn write16(&mut self, addr: u16, value: u16) {
        self.write(addr, value as u8);
        self.write(addr + 1, (value >> 8) as u8);
    }
    pub fn write(&mut self, addr: u16, value: u8) {
        trace!("Writing {:02x} to {:04x}", value, addr);
        match addr {
            MEM_LCD_IO_DMA => {
                // TODO Refactor stuff in IoPorts to Bus
                // TODO This should not be needed before sprites are implemented
                let src_addr = (value as u16) << 8;
                let dst_addr = 0xfe00;
                for i in 0x00..0x9f {
                    let d = self.read(src_addr + i);
                    self.write(dst_addr + i, d);
                }
            }
            MEM_CARTRIDGE_ROM_START...MEM_CARTRIDGE_ROM_END =>
                self.cartridge.write(addr, value),
            MEM_LCD_VRAM_START...MEM_LCD_VRAM_END => self.lcd.write(addr, value),
            MEM_CARTRIDGE_RAM_START...MEM_CARTRIDGE_RAM_END =>
                self.cartridge.write(addr, value),
            0xc000...0xdfff => self.wram[(addr - 0xc000) as usize] = value,
            0xe000...0xfdff => self.wram[(addr - 0xe000) as usize] = value,
            MEM_LCD_OAM_START...MEM_LCD_OAM_END => self.lcd.write(addr, value),
            0xff10...0xff27 => self.sound.write(addr, value),
            MEM_LCD_IO_START...MEM_LCD_IO_END => self.lcd.write(addr, value),
            0xff00...0xff09 | 0xff28...0xff7f | 0xffff => self.io.write(addr, value),
            0xff80...0xfffe => self.hram[(addr - 0xff80) as usize] = value,
            _ => trace!("NOT MAPPED FOR WRITE {:x} (value 0b{:05b})", addr, value),
        }
    }
}
<commit_msg>Fixed io reg mapping bug<commit_after>use std::mem;

use super::cartridge::Cartridge;
use super::sound::Sound;
use super::lcd::Lcd;
use super::constants::*;

use num::FromPrimitive;
use std::io;
use std::collections::VecDeque;

use std::fs::File;
use std::io::Write;

#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Bus {
    pub cartridge: Cartridge,
    // TODO: Expose in better way
    pub lcd: Lcd,
    pub sound: Sound,
    wram: Vec<u8>,
    hram: Vec<u8>,
    pub io: IoPorts,
}

enum_from_primitive! {
#[derive(Debug,PartialEq)]
enum IoAddress {
    Joypad = 0xff00,
    Sb = 0xff01,
    Sc = 0xff02,
    Div = 0xff04,
    Tima = 0xff05,
    Tma = 0xff06,
    Tac = 0xff07,
    If = 0xff0f,
    Ie = 0xffff
}
}

#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Timers {
    div: u8,
    tima: u8,
    tma: u8,
    tac: u8,

    div_counter: isize,
    tima_counter: isize,
    tima_running: bool,
}

impl Timers {
    fn new() -> Timers {
        let mut timers = Timers {
            div: 0,
            tima: 0,
            tma: 0,
            tac: 0,
            div_counter: 0,
            tima_counter: 0,
            tima_running: false,
        };
        timers.write_tac(0);
        timers
    }

    pub fn tick(&mut self, cycles: usize) -> u8 {
        let mut interrupt = 0u8;

        if cycles > 12 {
            interrupt |= self.tick(12);
            interrupt |= self.tick(cycles - 12);
            return interrupt;
        }

        self.div_counter -= cycles as isize;
        if self.div_counter <= 0 {
            self.div_counter += (CPU_FREQ / 16384) as isize;
            self.div = self.div.wrapping_add(1);
        }

        if self.tima_running {
            self.tima_counter -= cycles as isize;
            if self.tima_counter <= 0 {
                self.tima_counter += (CPU_FREQ / self.get_tac_freq()) as isize;
                self.tima = self.tima.wrapping_add(1);
                if self.tima == 0 {
                    interrupt |= INT_MASK_TIMER;
                    self.tima = self.tma;
                }
            }
        }
        interrupt
    }

    fn get_tac_freq(&self) -> usize {
        match self.tac & 0x03 {
            0b00 => 4096,
            0b01 => 262144,
            0b10 => 65536,
            0b11 => 16384,
            _ => unreachable!(),
        }
    }
    fn write_div(&mut self) {
        self.div = 0;
        self.div_counter = 0;
    }
    fn write_tima(&mut self, value: u8) {
        self.tima = value;
        // self.tima_counter = (CPU_FREQ / self.get_tac_freq()) as isize - 4;
    }
    fn write_tma(&mut self, value: u8) {
        self.tma = value;
    }
    fn write_tac(&mut self, value: u8) {
        self.tac = value & 0x07;
        self.tima_running = (self.tac & 0x04) != 0;
        trace!("Setting tima freq to {}", self.get_tac_freq());
    }
}

#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct IoPorts {
    joypad: u8,
    serial_data: u8,
    serial_transfer_control: u8,
    pub timers: Timers,

    // TODO expose through other means
    pub interrupt_enable: u8,
    pub interrupt_flags: u8,

    pub joypad_all_buttons: u8,

    pub serial_out: VecDeque<u8>,
}

impl IoPorts {
    fn new() -> IoPorts {
        IoPorts {
            joypad: 0xff,
            serial_data: 0,
            serial_transfer_control: 0,
            timers: Timers::new(),
            interrupt_enable: 0,
            interrupt_flags: 0,
            joypad_all_buttons: 0xff,
            serial_out: VecDeque::new()
        }
    }

    fn write(&mut self, addr: u16, value: u8) {
        match IoAddress::from_u16(addr) {
            Some(x) => {
                trace!("Writing 0x{:02X} to {:?} (0x{:04X})", value, x, addr);
                match x {
                    IoAddress::Joypad => {
                        self.joypad = value | !0x30;
                    }
                    IoAddress::Sb => self.serial_data = value,
                    IoAddress::Sc => {
                        if value & 0x80 == 0x80 {
                            self.serial_out.push_back(self.serial_data);
                        }
                    }
                    IoAddress::Div => self.timers.write_div(),
                    IoAddress::Tima => self.timers.write_tima(value),
                    IoAddress::Tma => self.timers.write_tma(value),
                    IoAddress::Tac => self.timers.write_tac(value),
                    IoAddress::Ie => self.interrupt_enable = value & 0x1f,
                    IoAddress::If => self.interrupt_flags = value & 0x1f,
                }
            }
            None => {
                debug!("WRITE 0x{:02X} to IOPORT 0x{:04X} not recognized (ignoring)",
                       value,
                       addr);
            }
        }
    }

    fn read(&self, addr: u16) -> u8 {
        match IoAddress::from_u16(addr) {
            Some(x) => {
                let value = match x {
                    IoAddress::Sb => self.serial_data,
                    IoAddress::Joypad => {
                        (if self.joypad & 0x10 == 0 {
                            self.joypad_all_buttons & 0xf
                        } else {
                            0
                        }) |
                        (if self.joypad & 0x20 == 0 {
                            self.joypad_all_buttons >> 4
                        } else {
                            0
                        }) | self.joypad & 0xf0
                    }
                    IoAddress::Sc => self.serial_transfer_control,
                    IoAddress::Div => self.timers.div,
                    IoAddress::Tima => self.timers.tima,
                    IoAddress::Tma => self.timers.tma,
                    IoAddress::Tac => self.timers.tac,
                    IoAddress::Ie => self.interrupt_enable,
                    IoAddress::If => self.interrupt_flags,
                    // _ => panic!("IOPORT {:02X} NOT MAPPED FOR READING", addr)
                };
                value
            }
            None => {
                warn!("READ from IOPORT 0x{:04X} not recognized (ignoring)", addr);
                0
            }
        }
    }
}

impl Bus {
    pub fn new(cartridge: Cartridge) -> Bus {
        Bus {
            hram: vec![0u8; 0x7f],
            wram: vec![0u8; 0x2000],
            lcd: Lcd::new(),
            sound: Sound::new(),
            cartridge: cartridge,
            io: IoPorts::new(),
        }
    }

    pub fn dequeue_samples(&mut self) -> Vec<(i8, i8)> {
        self.sound.dump_audio()
    }

    pub fn dump_wram(&mut self) -> io::Result<()> {
        let mut f = try!(File::create("wram.dump"));
        try!(f.write_all(&self.wram));
        Ok(())
    }

    pub fn read(&self, addr: u16) -> u8 {
        let value = match addr {
            MEM_LCD_IO_DMA => 0xff,
            MEM_CARTRIDGE_ROM_START...MEM_CARTRIDGE_ROM_END =>
                self.cartridge.read(addr),
            MEM_LCD_VRAM_START...MEM_LCD_VRAM_END => self.lcd.read(addr),
            MEM_CARTRIDGE_RAM_START...MEM_CARTRIDGE_RAM_END =>
                self.cartridge.read(addr),
            0xc000...0xdfff => self.wram[(addr - 0xc000) as usize],
            0xe000...0xfdff => self.wram[(addr - 0xe000) as usize],
            MEM_LCD_OAM_START...MEM_LCD_OAM_END => self.lcd.read(addr),
            0xff10...0xff27 => self.sound.read(addr),
            MEM_LCD_IO_START...MEM_LCD_IO_END => self.lcd.read(addr),
            0xff00...0xff0f | 0xff28...0xff7f | 0xffff => self.io.read(addr),
            0xff80...0xfffe => self.hram[(addr - 0xff80) as usize],
            _ => {
                trace!("Reading unmapped {:x}, just returning 0xff", addr);
                0xff
            }
        };
        value
    }
    pub fn read16(&self, addr: u16) -> u16 {
        self.read(addr) as u16 | (self.read(addr + 1) as u16) << 8
    }
    pub fn write16(&mut self, addr: u16, value: u16) {
        self.write(addr, value as u8);
        self.write(addr + 1, (value >> 8) as u8);
    }
    pub fn write(&mut self, addr: u16, value: u8) {
        trace!("Writing {:02x} to {:04x}", value, addr);
        match addr {
            MEM_LCD_IO_DMA => {
                // TODO Refactor stuff in IoPorts to Bus
                // TODO This should not be needed before sprites are implemented
                let src_addr = (value as u16) << 8;
                let dst_addr = 0xfe00;
                for i in 0x00..0x9f {
                    let d = self.read(src_addr + i);
                    self.write(dst_addr + i, d);
                }
            }
            MEM_CARTRIDGE_ROM_START...MEM_CARTRIDGE_ROM_END =>
                self.cartridge.write(addr, value),
            MEM_LCD_VRAM_START...MEM_LCD_VRAM_END => self.lcd.write(addr, value),
            MEM_CARTRIDGE_RAM_START...MEM_CARTRIDGE_RAM_END =>
                self.cartridge.write(addr, value),
            0xc000...0xdfff => self.wram[(addr - 0xc000) as usize] = value,
            0xe000...0xfdff => self.wram[(addr - 0xe000) as usize] = value,
            MEM_LCD_OAM_START...MEM_LCD_OAM_END => self.lcd.write(addr, value),
            0xff10...0xff27 => self.sound.write(addr, value),
            MEM_LCD_IO_START...MEM_LCD_IO_END => self.lcd.write(addr, value),
            0xff00...0xff0f | 0xff28...0xff7f | 0xffff => self.io.write(addr, value),
            0xff80...0xfffe => self.hram[(addr - 0xff80) as usize] = value,
            _ => trace!("NOT MAPPED FOR WRITE {:x} (value 0b{:05b})", addr, value),
        }
    }
}
<|endoftext|>


<commit_before>/// Parser method generator.
///
/// Invoke inside an impl block. Declare a list of signatures of methods callable on `&mut self`.
/// The macro constructs a `parse(&mut self, input: &str) -> Result<(), String>` method that parses
/// input strings like "method_name 4 foo" into calls of `self.method_name(FromStr::from_str("4")?,
/// FromStr::from_str("foo")?)`.
///
///     # #[macro_use] extern crate calx_alg;
///     # fn main() {
///
///     struct Adder {
///         pub num: u32,
///     }
///
///     impl Adder {
///         fn add(&mut self, amount: u32) {
///             self.num += amount;
///         }
///
///         command_parser!{
///             fn add(&mut self, amount: u32);
///         }
///     }
///
///     let mut a = Adder { num: 1 };
///     a.add(2);
///     assert_eq!(a.num, 3);
///
///     assert!(a.parse("foobie bletch").is_err());
///     assert!(a.parse("add").is_err());       // Too few arguments
///     assert!(a.parse("add derp").is_err());  // Arguments won't parse to unsigned integer.
///     assert!(a.parse("add -1").is_err());
///     assert!(a.parse("add 1.0").is_err());
///
///     // NB: Due to limits of the macro implementation, trailing arguments
///     // are ignored instead of causing an error.
///     // assert!(a.parse("add 1 2").is_err());   // Too many arguments
///
///     assert_eq!(a.num, 3);
///
///     assert!(a.parse("add 3").is_ok());
///     assert_eq!(a.num, 6);
///
///     # }
#[macro_export]
macro_rules! command_parser {
    {
        $(fn $method:ident(&mut self$(, $argname:ident: $argtype:ty)*);)+
    } => {
        fn parse(&mut self, input: &str) -> Result<(), Box<::std::error::Error>> {
            #[derive(Debug)]
            struct ParseError(String);

            impl ::std::fmt::Display for ParseError {
                fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                    self.0.fmt(fmt)
                }
            }

            impl ::std::error::Error for ParseError {
                fn description(&self) -> &str { &self.0 }
            }

            fn parse_err(s: String) -> Result<(), Box<::std::error::Error>> {
                Err(Box::new(ParseError(s)))
            }

            use ::std::str::FromStr;
            let mut elts = input.split(" ");
            let cmd = elts.next();
            if let Some(cmd) = cmd {
                match cmd {
                    $(
                    stringify!($method) => {
                        self.$method(
                            $({
                                if let Some(arg) = elts.next() {
                                    let param: $argtype = FromStr::from_str(arg)?;
                                    param
                                } else {
                                    return parse_err(format!("Too few arguments"));
                                }
                            }),*
                        );
                        Ok(())
                    }
                    )+
                    x => parse_err(format!("Unknown command {}", x)),
                }
            } else {
                return parse_err(format!("No input"));
            }
        }
    }
}
<commit_msg>Don't parse trailing space as argument<commit_after>/// Parser method generator.
///
/// Invoke inside an impl block. Declare a list of signatures of methods callable on `&mut self`.
/// The macro constructs a `parse(&mut self, input: &str) -> Result<(), String>` method that parses
/// input strings like "method_name 4 foo" into calls of `self.method_name(FromStr::from_str("4")?,
/// FromStr::from_str("foo")?)`.
///
///     # #[macro_use] extern crate calx_alg;
///     # fn main() {
///
///     struct Adder {
///         pub num: u32,
///     }
///
///     impl Adder {
///         fn add(&mut self, amount: u32) {
///             self.num += amount;
///         }
///
///         command_parser!{
///             fn add(&mut self, amount: u32);
///         }
///     }
///
///     let mut a = Adder { num: 1 };
///     a.add(2);
///     assert_eq!(a.num, 3);
///
///     assert!(a.parse("foobie bletch").is_err());
///     assert!(a.parse("add").is_err());       // Too few arguments
///     assert!(a.parse("add derp").is_err());  // Arguments won't parse to unsigned integer.
///     assert!(a.parse("add -1").is_err());
///     assert!(a.parse("add 1.0").is_err());
///
///     // NB: Due to limits of the macro implementation, trailing arguments
///     // are ignored instead of causing an error.
///     // assert!(a.parse("add 1 2").is_err());   // Too many arguments
///
///     assert_eq!(a.num, 3);
///
///     assert!(a.parse("add 3").is_ok());
///     assert_eq!(a.num, 6);
///
///     # }
#[macro_export]
macro_rules! command_parser {
    {
        $(fn $method:ident(&mut self$(, $argname:ident: $argtype:ty)*);)+
    } => {
        fn parse(&mut self, input: &str) -> Result<(), Box<::std::error::Error>> {
            #[derive(Debug)]
            struct ParseError(String);

            impl ::std::fmt::Display for ParseError {
                fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                    self.0.fmt(fmt)
                }
            }

            impl ::std::error::Error for ParseError {
                fn description(&self) -> &str { &self.0 }
            }

            fn parse_err(s: String) -> Result<(), Box<::std::error::Error>> {
                Err(Box::new(ParseError(s)))
            }

            use ::std::str::FromStr;
            let input = input.trim_right();
            let mut elts = input.split(" ");
            let cmd = elts.next();
            if let Some(cmd) = cmd {
                match cmd {
                    $(
                    stringify!($method) => {
                        self.$method(
                            $({
                                if let Some(arg) = elts.next() {
                                    let param: $argtype = FromStr::from_str(arg)?;
                                    param
                                } else {
                                    return parse_err(format!("Too few arguments"));
                                }
                            }),*
                        );
                        Ok(())
                    }
                    )+
                    x => parse_err(format!("Unknown command {}", x)),
                }
            } else {
                return parse_err(format!("No input"));
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

use hir::def_id::DefId;
use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
use util::ppaux;

use std::fmt;

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Instance<'tcx> {
    pub def: InstanceDef<'tcx>,
    pub substs: &'tcx Substs<'tcx>,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum InstanceDef<'tcx> {
    Item(DefId),
    Intrinsic(DefId),

    /// <fn() as FnTrait>::call_*
    /// def-id is FnTrait::call_*
    FnPtrShim(DefId, Ty<'tcx>),

    /// <Trait as Trait>::fn
    Virtual(DefId, usize),

    /// <[mut closure] as FnOnce>::call_once
    ClosureOnceShim { call_once: DefId },

    /// drop_in_place::<T>; None for empty drop glue.
    DropGlue(DefId, Option<Ty<'tcx>>),

    ///`<T as Clone>::clone` shim.
    CloneShim(DefId, Ty<'tcx>),
}

impl<'tcx> InstanceDef<'tcx> {
    #[inline]
    pub fn def_id(&self) -> DefId {
        match *self {
            InstanceDef::Item(def_id) |
            InstanceDef::FnPtrShim(def_id, _) |
            InstanceDef::Virtual(def_id, _) |
            InstanceDef::Intrinsic(def_id, ) |
            InstanceDef::ClosureOnceShim { call_once: def_id } |
            InstanceDef::DropGlue(def_id, _) |
            InstanceDef::CloneShim(def_id, _) => def_id
        }
    }

    #[inline]
    pub fn def_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
        tcx.type_of(self.def_id())
    }

    #[inline]
    pub fn attrs<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
        tcx.get_attrs(self.def_id())
    }
}

impl<'tcx> fmt::Display for Instance<'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        ppaux::parameterized(f, self.substs, self.def_id(), &[])?;
        match self.def {
            InstanceDef::Item(_) => Ok(()),
            InstanceDef::Intrinsic(_) => {
                write!(f, " - intrinsic")
            }
            InstanceDef::Virtual(_, num) => {
                write!(f, " - shim(#{})", num)
            }
            InstanceDef::FnPtrShim(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
            InstanceDef::ClosureOnceShim { .. } => {
                write!(f, " - shim")
            }
            InstanceDef::DropGlue(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
            InstanceDef::CloneShim(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
        }
    }
}

impl<'a, 'b, 'tcx> Instance<'tcx> {
    pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
               -> Instance<'tcx> {
        assert!(substs.is_normalized_for_trans() && !substs.has_escaping_regions(),
                "substs of instance {:?} not normalized for trans: {:?}",
                def_id, substs);
        Instance { def: InstanceDef::Item(def_id), substs: substs }
    }

    pub fn mono(tcx: TyCtxt<'a, 'tcx, 'b>, def_id: DefId) -> Instance<'tcx> {
        Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id))
    }

    #[inline]
    pub fn def_id(&self) -> DefId {
        self.def.def_id()
    }
}
<commit_msg>copy resolve() over to librustc<commit_after>// Copyright 2016 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.

use hir::def_id::DefId;
use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
use ty::subst::{Kind, Subst};
use traits;
use syntax::abi::Abi;
use syntax::codemap::DUMMY_SP;
use util::ppaux;

use std::fmt;

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Instance<'tcx> {
    pub def: InstanceDef<'tcx>,
    pub substs: &'tcx Substs<'tcx>,
}

#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum InstanceDef<'tcx> {
    Item(DefId),
    Intrinsic(DefId),

    /// <fn() as FnTrait>::call_*
    /// def-id is FnTrait::call_*
    FnPtrShim(DefId, Ty<'tcx>),

    /// <Trait as Trait>::fn
    Virtual(DefId, usize),

    /// <[mut closure] as FnOnce>::call_once
    ClosureOnceShim { call_once: DefId },

    /// drop_in_place::<T>; None for empty drop glue.
    DropGlue(DefId, Option<Ty<'tcx>>),

    ///`<T as Clone>::clone` shim.
    CloneShim(DefId, Ty<'tcx>),
}

impl<'tcx> InstanceDef<'tcx> {
    #[inline]
    pub fn def_id(&self) -> DefId {
        match *self {
            InstanceDef::Item(def_id) |
            InstanceDef::FnPtrShim(def_id, _) |
            InstanceDef::Virtual(def_id, _) |
            InstanceDef::Intrinsic(def_id, ) |
            InstanceDef::ClosureOnceShim { call_once: def_id } |
            InstanceDef::DropGlue(def_id, _) |
            InstanceDef::CloneShim(def_id, _) => def_id
        }
    }

    #[inline]
    pub fn def_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
        tcx.type_of(self.def_id())
    }

    #[inline]
    pub fn attrs<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
        tcx.get_attrs(self.def_id())
    }
}

impl<'tcx> fmt::Display for Instance<'tcx> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        ppaux::parameterized(f, self.substs, self.def_id(), &[])?;
        match self.def {
            InstanceDef::Item(_) => Ok(()),
            InstanceDef::Intrinsic(_) => {
                write!(f, " - intrinsic")
            }
            InstanceDef::Virtual(_, num) => {
                write!(f, " - shim(#{})", num)
            }
            InstanceDef::FnPtrShim(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
            InstanceDef::ClosureOnceShim { .. } => {
                write!(f, " - shim")
            }
            InstanceDef::DropGlue(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
            InstanceDef::CloneShim(_, ty) => {
                write!(f, " - shim({:?})", ty)
            }
        }
    }
}

impl<'a, 'b, 'tcx> Instance<'tcx> {
    pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
               -> Instance<'tcx> {
        assert!(substs.is_normalized_for_trans() && !substs.has_escaping_regions(),
                "substs of instance {:?} not normalized for trans: {:?}",
                def_id, substs);
        Instance { def: InstanceDef::Item(def_id), substs: substs }
    }

    pub fn mono(tcx: TyCtxt<'a, 'tcx, 'b>, def_id: DefId) -> Instance<'tcx> {
        Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id))
    }

    #[inline]
    pub fn def_id(&self) -> DefId {
        self.def.def_id()
    }

    /// The point where linking happens. Resolve a (def_id, substs)
    /// pair to an instance.
    pub fn resolve(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Instance<'tcx>> {
        let def_id = self.def_id();
        debug!("resolve(def_id={:?}, substs={:?})", def_id, self.substs);
        let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
            debug!(" => associated item, attempting to find impl");
            let item = tcx.associated_item(def_id);
            resolve_associated_item(tcx, &item, trait_def_id, self.substs)
        } else {
            let ty = tcx.type_of(def_id);
            let item_type = tcx.trans_apply_param_substs(self.substs, &ty);

            let def = match item_type.sty {
                ty::TyFnDef(..) if {
                    let f = item_type.fn_sig(tcx);
                    f.abi() == Abi::RustIntrinsic ||
                        f.abi() == Abi::PlatformIntrinsic
                } =>
                {
                    debug!(" => intrinsic");
                    ty::InstanceDef::Intrinsic(def_id)
                }
                _ => {
                    if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
                        let ty = self.substs.type_at(0);
                        if ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All)) {
                            debug!(" => nontrivial drop glue");
                            ty::InstanceDef::DropGlue(def_id, Some(ty))
                        } else {
                            debug!(" => trivial drop glue");
                            ty::InstanceDef::DropGlue(def_id, None)
                        }
                    } else {
                        debug!(" => free item");
                        ty::InstanceDef::Item(def_id)
                    }
                }
            };
            Some(Instance {
                def: def,
                substs: self.substs
            })
        };
        debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, self.substs, result);
        result
    }

}

fn resolve_closure<'a, 'tcx>(
                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
                   def_id: DefId,
                   substs: ty::ClosureSubsts<'tcx>,
                   requested_kind: ty::ClosureKind)
-> Instance<'tcx>
{
    let actual_kind = tcx.closure_kind(def_id);

    match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
        Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
        _ => Instance::new(def_id, substs.substs)
    }
}

fn resolve_associated_item<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    trait_item: &ty::AssociatedItem,
    trait_id: DefId,
    rcvr_substs: &'tcx Substs<'tcx>
    ) -> Option<Instance<'tcx>> {
    let def_id = trait_item.def_id;
    debug!("resolve_associated_item(trait_item={:?}, \
                                    trait_id={:?}, \
           rcvr_substs={:?})",
           def_id, trait_id, rcvr_substs);

    let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
    let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref));

    // Now that we know which impl is being used, we can dispatch to
    // the actual function:
    match vtbl {
        traits::VtableImpl(impl_data) => {
            let (def_id, substs) = traits::find_associated_item(
                tcx, trait_item, rcvr_substs, &impl_data);
            let substs = tcx.erase_regions(&substs);
            Some(ty::Instance::new(def_id, substs))
        }
        traits::VtableGenerator(closure_data) => {
            Some(Instance {
                def: ty::InstanceDef::Item(closure_data.closure_def_id),
                substs: closure_data.substs.substs
            })
        }
        traits::VtableClosure(closure_data) => {
            let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap();
            Some(resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs,
                                 trait_closure_kind))
        }
        traits::VtableFnPointer(ref data) => {
            Some(Instance {
                def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
                substs: rcvr_substs
            })
        }
        traits::VtableObject(ref data) => {
            let index = tcx.get_vtable_index_of_object_method(data, def_id);
            Some(Instance {
                def: ty::InstanceDef::Virtual(def_id, index),
                substs: rcvr_substs
            })
        }
        traits::VtableBuiltin(..) if Some(trait_id) == tcx.lang_items().clone_trait() => {
            Some(Instance {
                def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()),
                substs: rcvr_substs
            })
        }
        _ => {
            None
        }
    }
}

fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind,
                              trait_closure_kind: ty::ClosureKind)
    -> Result<bool, ()>
{
    match (actual_closure_kind, trait_closure_kind) {
        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
            (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
            (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
                // No adapter needed.
                Ok(false)
            }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
            // `fn(&mut self, ...)`. In fact, at trans time, these are
            // basically the same thing, so we can just return llfn.
            Ok(false)
        }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
            (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
                // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
                // self, ...)`.  We want a `fn(self, ...)`. We can produce
                // this by doing something like:
                //
                //     fn call_once(self, ...) { call_mut(&self, ...) }
                //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
                //
                // These are both the same at trans time.
                Ok(true)
            }
        _ => Err(()),
    }
}

fn fn_once_adapter_instance<'a, 'tcx>(
                            tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            closure_did: DefId,
                            substs: ty::ClosureSubsts<'tcx>,
                            ) -> Instance<'tcx> {
    debug!("fn_once_adapter_shim({:?}, {:?})",
    closure_did,
    substs);
    let fn_once = tcx.lang_items().fn_once_trait().unwrap();
    let call_once = tcx.associated_items(fn_once)
        .find(|it| it.kind == ty::AssociatedKind::Method)
        .unwrap().def_id;
    let def = ty::InstanceDef::ClosureOnceShim { call_once };

    let self_ty = tcx.mk_closure_from_closure_substs(
        closure_did, substs);

    let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs);
    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
    assert_eq!(sig.inputs().len(), 1);
    let substs = tcx.mk_substs([
                               Kind::from(self_ty),
                               Kind::from(sig.inputs()[0]),
    ].iter().cloned());

    debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
    Instance { def, substs }
}
<|endoftext|>


<commit_before>//! Support for "weak linkage" to symbols on Unix
//!
//! Some I/O operations we do in libstd require newer versions of OSes but we
//! need to maintain binary compatibility with older releases for now. In order
//! to use the new functionality when available we use this module for
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
//! really workable on Linux. Hence, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//! is currently always the case for things like libpthread/libc.
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).

use libc;

use ffi::CString;
use marker;
use mem;
use sync::atomic::{AtomicUsize, Ordering};

macro_rules! weak {
    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
        static $name: ::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
            ::sys::weak::Weak::new(stringify!($name));
    )
}

pub struct Weak<F> {
    name: &'static str,
    addr: AtomicUsize,
    _marker: marker::PhantomData<F>,
}

impl<F> Weak<F> {
    pub const fn new(name: &'static str) -> Weak<F> {
        Weak {
            name,
            addr: AtomicUsize::new(1),
            _marker: marker::PhantomData,
        }
    }

    pub fn get(&self) -> Option<&F> {
        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
        unsafe {
            if self.addr.load(Ordering::SeqCst) == 1 {
                self.addr.store(fetch(self.name), Ordering::SeqCst);
            }
            if self.addr.load(Ordering::SeqCst) == 0 {
                None
            } else {
                mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
            }
        }
    }
}

unsafe fn fetch(name: &str) -> usize {
    let name = match CString::new(name) {
        Ok(cstr) => cstr,
        Err(..) => return 0,
    };
    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
}

#[cfg(not(target_os = "linux"))]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name: $t),*) -> $ret {
            use libc;
            use super::os;

            weak! { fn $name($($t),*) -> $ret }

            if let Some(fun) = $name.get() {
                fun($($arg_name),*)
            } else {
                os::set_errno(libc::ENOSYS);
                -1
            }
        }
    )
}

#[cfg(target_os = "linux")]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name:$t),*) -> $ret {
            // This looks like a hack, but concat_idents only accepts idents
            // (not paths).
            use libc::*;

            syscall(
                concat_idents!(SYS_, $name),
                $($arg_name as c_long),*
            ) as $ret
        }
    )
}
<commit_msg>Avoid allocation in std::sys::unix::weak<commit_after>//! Support for "weak linkage" to symbols on Unix
//!
//! Some I/O operations we do in libstd require newer versions of OSes but we
//! need to maintain binary compatibility with older releases for now. In order
//! to use the new functionality when available we use this module for
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
//! really workable on Linux. Hence, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//! is currently always the case for things like libpthread/libc.
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).

use libc;

use ffi::CStr;
use marker;
use mem;
use sync::atomic::{AtomicUsize, Ordering};

macro_rules! weak {
    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
        static $name: ::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
            ::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
    )
}

pub struct Weak<F> {
    name: &'static str,
    addr: AtomicUsize,
    _marker: marker::PhantomData<F>,
}

impl<F> Weak<F> {
    pub const fn new(name: &'static str) -> Weak<F> {
        Weak {
            name,
            addr: AtomicUsize::new(1),
            _marker: marker::PhantomData,
        }
    }

    pub fn get(&self) -> Option<&F> {
        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
        unsafe {
            if self.addr.load(Ordering::SeqCst) == 1 {
                self.addr.store(fetch(self.name), Ordering::SeqCst);
            }
            if self.addr.load(Ordering::SeqCst) == 0 {
                None
            } else {
                mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
            }
        }
    }
}

unsafe fn fetch(name: &str) -> usize {
    let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
        Ok(cstr) => cstr,
        Err(..) => return 0,
    };
    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
}

#[cfg(not(target_os = "linux"))]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name: $t),*) -> $ret {
            use libc;
            use super::os;

            weak! { fn $name($($t),*) -> $ret }

            if let Some(fun) = $name.get() {
                fun($($arg_name),*)
            } else {
                os::set_errno(libc::ENOSYS);
                -1
            }
        }
    )
}

#[cfg(target_os = "linux")]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name:$t),*) -> $ret {
            // This looks like a hack, but concat_idents only accepts idents
            // (not paths).
            use libc::*;

            syscall(
                concat_idents!(SYS_, $name),
                $($arg_name as c_long),*
            ) as $ret
        }
    )
}
<|endoftext|>


<commit_before>use crate::ffi::CStr;
use crate::io;
use crate::sys::cvt_wasi;
use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::os::wasi::ffi::OsStringExt;
use crate::vec;

pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
}

pub unsafe fn cleanup() {
}

pub struct Args {
    iter: vec::IntoIter<OsString>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

/// Returns the command line arguments
pub fn args() -> Args {
    maybe_args().unwrap_or_else(|_| {
        Args {
            iter: Vec::new().into_iter(),
            _dont_send_or_sync_me: PhantomData
        }
    })
}

fn cvt_wasi(r: u16) -> crate::io::Result<()> {
    if r != 0 {
        Err(Error::from_raw_os_error(r as i32))
    } else {
        Ok(())
    }
}

fn maybe_args() -> io::Result<Args> {
    // FIXME: replace with safe functions
    use wasi::wasi_unstable::raw::{__wasi_args_sizes_get, __wasi_args_get};
    unsafe {
        let (mut argc, mut argv_buf_size) = (0, 0);
        cvt_wasi(__wasi_args_sizes_get(&mut argc, &mut argv_buf_size))?;

        let mut argc = vec![core::ptr::null_mut::<u8>(); argc];
        let mut argv_buf = vec![0; argv_buf_size];
        cvt_wasi(__wasi_args_get(argc.as_mut_ptr(), argv_buf.as_mut_ptr()))?;

        let args = argc.into_iter()
            .map(|ptr| CStr::from_ptr(ptr).to_bytes().to_vec())
            .map(|bytes| OsString::from_vec(bytes))
            .collect::<Vec<_>>();
        Ok(Args {
            iter: args.into_iter(),
            _dont_send_or_sync_me: PhantomData,
        })
    }
}

impl Args {
    pub fn inner_debug(&self) -> &[OsString] {
        self.iter.as_slice()
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        self.iter.next()
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize {
        self.iter.len()
    }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> {
        self.iter.next_back()
    }
}
<commit_msg>use wasi::get_args<commit_after>use crate::ffi::CStr;
use crate::io;
use crate::sys::cvt_wasi;
use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::os::wasi::ffi::OsStringExt;
use crate::vec;

pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
}

pub unsafe fn cleanup() {
}

pub struct Args {
    iter: vec::IntoIter<Vec<u8>>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

/// Returns the command line arguments
pub fn args() -> Args {
    Args {
        iter: wasi::get_args().unwrap_or(Vec::new()),
        _dont_send_or_sync_me: PhantomData
    }
}

impl Args {
    pub fn inner_debug(&self) -> &[OsString] {
        self.iter.as_slice()
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        self.iter.next().map(OsString::from_vec)
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize {
        self.iter.len()
    }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> {
        self.iter.next_back()
    }
}
<|endoftext|>


<commit_before>#![crate_id="app"]
#![crate_type="rlib"]
#![no_std]

extern crate zinc;
extern crate core;

use core::volatile_load;

#[cfg(mcu_lpc17xx)] use zinc::boards::mbed_lpc1768;
use zinc::hal::gpio::GPIOConf;
use zinc::hal::init::SysConf;
use zinc::hal::cortex_m3::systick;

struct Platform {
  configuration: SysConf,
  led1: GPIOConf,
}

#[cfg(mcu_lpc17xx)]
static platform: Platform = Platform {
  configuration: mbed_lpc1768::configuration,
  led1: mbed_lpc1768::led1,
};

static mut i: u32 = 0;
static mut on: u32 = 0;

/// TODO(farcaller): https://github.com/mozilla/rust/pull/13833
#[inline(always)]
#[no_split_stack]
#[link_section=".text.insignificant"]
unsafe fn systick_handler() {
  i += 1;
  if i > 100 {
    i = 0;
    on = !on;
  }
}

#[no_split_stack]
pub fn main() {
  platform.configuration.setup();
  systick::setup(systick::CALIBRATED, true);

  let led1 = platform.led1.setup();

  led1.set_high();

  let mut ison: bool = true;

  systick::enable();

  unsafe { loop {
    let on: bool = volatile_load(&on as *u32) == 0;
    if ison != on {
      ison = on;
      match ison {
        true  => led1.set_high(),
        false => led1.set_low(),
      }
    }
  } }
}
<commit_msg>Fixed dependency on rust-core.<commit_after>#![crate_id="app"]
#![crate_type="rlib"]
#![no_std]

extern crate zinc;
extern crate std;

use std::intrinsics::volatile_load;

#[cfg(mcu_lpc17xx)] use zinc::boards::mbed_lpc1768;
use zinc::hal::gpio::GPIOConf;
use zinc::hal::init::SysConf;
use zinc::hal::cortex_m3::systick;

struct Platform {
  configuration: SysConf,
  led1: GPIOConf,
}

#[cfg(mcu_lpc17xx)]
static platform: Platform = Platform {
  configuration: mbed_lpc1768::configuration,
  led1: mbed_lpc1768::led1,
};

static mut i: u32 = 0;
static mut on: u32 = 0;

/// TODO(farcaller): https://github.com/mozilla/rust/pull/13833
#[inline(always)]
#[no_split_stack]
#[link_section=".text.insignificant"]
unsafe fn systick_handler() {
  i += 1;
  if i > 100 {
    i = 0;
    on = !on;
  }
}

#[no_split_stack]
pub fn main() {
  platform.configuration.setup();
  systick::setup(systick::CALIBRATED, true);

  let led1 = platform.led1.setup();

  led1.set_high();

  let mut ison: bool = true;

  systick::enable();

  unsafe { loop {
    let on: bool = volatile_load(&on as *u32) == 0;
    if ison != on {
      ison = on;
      match ison {
        true  => led1.set_high(),
        false => led1.set_low(),
      }
    }
  } }
}
<|endoftext|>


<commit_before>#[allow(dead_code)]
const VERSION_ENVVAR: &str = "PLAN_VERSION";

#[allow(dead_code)]
mod builder {
    use std::env;
    use std::process::Command;

    use super::VERSION_ENVVAR;

    pub fn common() {
        super::version::write_file(version());
    }

    pub fn version() -> String {
        match env::var(VERSION_ENVVAR) {
            Ok(ver) => ver,
            _ => read_git_version(),
        }
    }

    fn read_git_version() -> String {
        let child = Command::new("git")
            .arg("rev-parse")
            .arg("HEAD")
            .output()
            .expect("Failed to spawn child");
        String::from_utf8_lossy(&child.stdout).into_owned()
    }
}

#[allow(dead_code)]
mod habitat {
    use std::env;
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use std::path::Path;

    use super::VERSION_ENVVAR;

    pub fn common() {
        super::version::write_file(version());
    }

    pub fn version() -> String {
        match env::var(VERSION_ENVVAR) {
            Ok(ver) => ver,
            _ => read_common_version(),
        }
    }

    fn read_common_version() -> String {
        let ver_file = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap())
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .join("VERSION");
        let f = File::open(ver_file).expect("Failed to open version file");
        let mut reader = BufReader::new(f);
        let mut ver = String::new();
        reader
            .read_line(&mut ver)
            .expect("Failed to read line from version file");
        ver
    }
}

#[allow(dead_code)]
mod util {
    use std::env;
    use std::fs::File;
    use std::io::Write;
    use std::path::Path;

    pub fn write_out_dir_file<P, S>(filename: P, content: S)
    where
        P: AsRef<Path>,
        S: AsRef<str>,
    {
        let mut f = File::create(
            Path::new(&env::var("OUT_DIR").expect("Failed to read OUT_DIR environment variable"))
                .join(filename),
        )
        .expect("Failed to create OUT_DIR file");
        f.write_all(content.as_ref().trim().as_bytes())
            .expect("Failed to write to OUT_DIR file");
    }
}

#[allow(dead_code)]
mod version {
    pub fn write_file<S: AsRef<str>>(version: S) {
        super::util::write_out_dir_file("VERSION", version);
    }
}
<commit_msg>[Chore] Clean up libbuild.rs<commit_after>mod habitat {
    use std::{env,
              fs::{self,
                   File},
              io::Write,
              path::Path};

    /// Writes version information to `$OUT_DIR/VERSION` during
    /// compilation, in order to be picked up by `include!` macros
    /// elsewhere in the compiling code.
    pub fn common() { write_out_dir_file("VERSION", version()); }

    /// Reads from $PLAN_VERSION in a `hab pkg build` run, but from
    /// the `VERSION` file in a plain `cargo build` run.
    fn version() -> String { env::var("PLAN_VERSION").unwrap_or_else(|_| read_common_version()) }

    /// Reads the contents of the `VERSION` file at the repository root.
    fn read_common_version() -> String {
        let version_file = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).parent()
                                                                              .unwrap()
                                                                              .parent()
                                                                              .unwrap()
                                                                              .join("VERSION");
        fs::read_to_string(version_file).expect("Couldn't read VERSION file!")
    }

    /// Write the given `content` to `$OUT_DIR/filename`.
    fn write_out_dir_file(filename: &str, content: String) {
        let mut f = File::create(
            Path::new(&env::var("OUT_DIR").unwrap())
                .join(filename),
        )
        .expect("Failed to create OUT_DIR file");
        f.write_all(content.trim().as_bytes())
         .expect("Failed to write to OUT_DIR file");
    }
}
<|endoftext|>