<commit_before>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 bincode::serde::DeserializeError;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::collections::hash_map::HashMap;
use std::cell::{RefCell};
use std::io::{Error, ErrorKind};
use std::slice;
use std::fmt::{self, Debug, Formatter};
use std::cmp::{PartialEq};
use std::ops::Deref;
use std::mem;
use std::usize;

use uuid::Uuid;

#[derive(Clone)]
struct ServerRecord {
    sender: OsIpcSender,
    conn_sender: mpsc::Sender<bool>,
    conn_receiver: Arc<Mutex<mpsc::Receiver<bool>>>,
}

impl ServerRecord {
    fn new(sender: OsIpcSender) -> ServerRecord {
        let (tx, rx) = mpsc::channel::<bool>();
        ServerRecord {
            sender: sender,
            conn_sender: tx,
            conn_receiver: Arc::new(Mutex::new(rx)),
        }
    }

    fn accept(&self) {
        self.conn_receiver.lock().unwrap().recv().unwrap();
    }

    fn connect(&self) {
        self.conn_sender.send(true).unwrap();
    }
}

lazy_static! {
    static ref ONE_SHOT_SERVERS: Mutex<HashMap<String,ServerRecord>> = Mutex::new(HashMap::new());
}

struct MpscChannelMessage(Vec<u8>, Vec<OsIpcChannel>, Vec<OsIpcSharedMemory>);

pub fn channel() -> Result<(OsIpcSender, OsIpcReceiver),MpscError> {
    let (base_sender, base_receiver) = mpsc::channel::<MpscChannelMessage>();
    Ok((OsIpcSender::new(base_sender), OsIpcReceiver::new(base_receiver)))
}

pub struct OsIpcReceiver {
    receiver: Arc<Mutex<Option<mpsc::Receiver<MpscChannelMessage>>>>,
}

impl PartialEq for OsIpcReceiver {
    fn eq(&self, other: &OsIpcReceiver) -> bool {
        self.receiver.lock().unwrap().as_ref().map(|rx| rx as *const _) ==
            other.receiver.lock().unwrap().as_ref().map(|rx| rx as *const _)
    }
}

// Can't derive, as mpsc::Receiver doesn't implement Debug.
impl fmt::Debug for OsIpcReceiver {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure there is anything useful we could print here.
        write!(f, "OsIpcReceiver {{ .. }}")
    }
}

impl OsIpcReceiver {
    fn new(receiver: mpsc::Receiver<MpscChannelMessage>) -> OsIpcReceiver {
        OsIpcReceiver {
            receiver: Arc::new(Mutex::new(Some(receiver))),
        }
    }

    pub fn consume(&self) -> OsIpcReceiver {
        let receiver = self.receiver.lock().unwrap().take();
        OsIpcReceiver::new(receiver.unwrap())
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>),MpscError> {
        let r = self.receiver.lock().unwrap();
        match r.as_ref().unwrap().recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OsOpaqueIpcChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }

    pub fn try_recv(&self) -> Result<(Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>),MpscError> {
        let r = self.receiver.lock().unwrap();
        match r.as_ref().unwrap().try_recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OsOpaqueIpcChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }
}

#[derive(Clone)]
pub struct OsIpcSender {
    sender: Arc<Mutex<mpsc::Sender<MpscChannelMessage>>>,
}

impl PartialEq for OsIpcSender {
    fn eq(&self, other: &OsIpcSender) -> bool {
        &*self.sender.lock().unwrap() as *const _ ==
            &*other.sender.lock().unwrap() as *const _
    }
}

// Can't derive, as mpsc::Sender doesn't implement Debug.
impl fmt::Debug for OsIpcSender {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure there is anything useful we could print here.
        write!(f, "OsIpcSender {{ .. }}")
    }
}

impl OsIpcSender {
    fn new(sender: mpsc::Sender<MpscChannelMessage>) -> OsIpcSender {
        OsIpcSender {
            sender: Arc::new(Mutex::new(sender)),
        }
    }

    pub fn connect(name: String) -> Result<OsIpcSender,MpscError> {
        let record = ONE_SHOT_SERVERS.lock().unwrap().get(&name).unwrap().clone();
        record.connect();
        Ok(record.sender)
    }

    pub fn get_max_fragment_size() -> usize {
        usize::MAX
    }

    pub fn send(&self,
                data: &[u8],
                ports: Vec<OsIpcChannel>,
                shared_memory_regions: Vec<OsIpcSharedMemory>)
                -> Result<(),MpscError>
    {
        match self.sender.lock().unwrap().send(MpscChannelMessage(data.to_vec(), ports, shared_memory_regions)) {
            Err(_) => Err(MpscError::ChannelClosedError),
            Ok(_) => Ok(()),
        }
    }
}

pub struct OsIpcReceiverSet {
    last_index: usize,
    receiver_ids: Vec<usize>,
    receivers: Vec<OsIpcReceiver>,
}

impl OsIpcReceiverSet {
    pub fn new() -> Result<OsIpcReceiverSet,MpscError> {
        Ok(OsIpcReceiverSet {
            last_index: 0,
            receiver_ids: vec![],
            receivers: vec![],
        })
    }

    pub fn add(&mut self, receiver: OsIpcReceiver) -> Result<i64,MpscError> {
        self.last_index += 1;
        self.receiver_ids.push(self.last_index);
        self.receivers.push(receiver.consume());
        Ok(self.last_index as i64)
    }

    pub fn select(&mut self) -> Result<Vec<OsIpcSelectionResult>,MpscError> {
        let mut receivers: Vec<Option<mpsc::Receiver<MpscChannelMessage>>> = Vec::with_capacity(self.receivers.len());
        let mut r_id: i64 = -1;
        let mut r_index: usize = 0;

        {
            let select = mpsc::Select::new();
            // we *must* allocate exact capacity for this, because the Handles *can't move*
            let mut handles: Vec<mpsc::Handle<MpscChannelMessage>> = Vec::with_capacity(self.receivers.len());

            for r in &self.receivers {
                let inner_r = mem::replace(&mut *r.receiver.lock().unwrap(), None);
                receivers.push(inner_r);
            }

            for r in &receivers {
                unsafe {
                    handles.push(select.handle(r.as_ref().unwrap()));
                    handles.last_mut().unwrap().add();
                }
            }

            let id = select.wait();

            for (index,h) in handles.iter().enumerate() {
                if h.id() == id {
                    r_index = index;
                    r_id = self.receiver_ids[index] as i64;
                    break;
                }
            }
        }

        // put the receivers back
        for (index,r) in self.receivers.iter().enumerate() {
            mem::replace(&mut *r.receiver.lock().unwrap(), mem::replace(&mut receivers[index], None));
        }

        if r_id == -1 {
            return Err(MpscError::UnknownError);
        }

        let receivers = &mut self.receivers;
        match receivers[r_index].recv() {
            Ok((data, channels, shmems)) =>
                Ok(vec![OsIpcSelectionResult::DataReceived(r_id, data, channels, shmems)]),
            Err(MpscError::ChannelClosedError) => {
                receivers.remove(r_index);
                self.receiver_ids.remove(r_index);
                Ok(vec![OsIpcSelectionResult::ChannelClosed(r_id)])
            },
            Err(err) => Err(err),
        }
    }
}

pub enum OsIpcSelectionResult {
    DataReceived(i64, Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>),
    ChannelClosed(i64),
}

impl OsIpcSelectionResult {
    pub fn unwrap(self) -> (i64, Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>) {
        match self {
            OsIpcSelectionResult::DataReceived(id, data, channels, shared_memory_regions) => {
                (id, data, channels, shared_memory_regions)
            }
            OsIpcSelectionResult::ChannelClosed(id) => {
                panic!("OsIpcSelectionResult::unwrap(): receiver ID {} was closed!", id)
            }
        }
    }
}

pub struct OsIpcOneShotServer {
    receiver: RefCell<Option<OsIpcReceiver>>,
    name: String,
}

impl OsIpcOneShotServer {
    pub fn new() -> Result<(OsIpcOneShotServer, String),MpscError> {
        let (sender, receiver) = match channel() {
            Ok((s,r)) => (s,r),
            Err(err) => return Err(err),
        };

        let name = Uuid::new_v4().to_string();
        let record = ServerRecord::new(sender);
        ONE_SHOT_SERVERS.lock().unwrap().insert(name.clone(), record);
        Ok((OsIpcOneShotServer {
            receiver: RefCell::new(Some(receiver)),
            name: name.clone(),
        },name.clone()))
    }

    pub fn accept(&self) -> Result<(OsIpcReceiver,
                                    Vec<u8>,
                                    Vec<OsOpaqueIpcChannel>,
                                    Vec<OsIpcSharedMemory>),MpscError>
    {
        let record = ONE_SHOT_SERVERS.lock().unwrap().get(&self.name).unwrap().clone();
        record.accept();
        ONE_SHOT_SERVERS.lock().unwrap().remove(&self.name).unwrap();
        let receiver = self.receiver.borrow_mut().take().unwrap();
        let (data, channels, shmems) = receiver.recv().unwrap();
        Ok((receiver, data, channels, shmems))
    }
}

#[derive(PartialEq, Debug)]
pub enum OsIpcChannel {
    Sender(OsIpcSender),
    Receiver(OsIpcReceiver),
}

#[derive(PartialEq, Debug)]
pub struct OsOpaqueIpcChannel {
    channel: RefCell<Option<OsIpcChannel>>,
}

impl OsOpaqueIpcChannel {
    fn new(channel: OsIpcChannel) -> OsOpaqueIpcChannel {
        OsOpaqueIpcChannel {
            channel: RefCell::new(Some(channel))
        }
    }

    pub fn to_receiver(&self) -> OsIpcReceiver {
        match self.channel.borrow_mut().take().unwrap() {
            OsIpcChannel::Sender(_) => panic!("Opaque channel is not a receiver!"),
            OsIpcChannel::Receiver(r) => r
        }
    }

    pub fn to_sender(&mut self) -> OsIpcSender {
        match self.channel.borrow_mut().take().unwrap() {
            OsIpcChannel::Sender(s) => s,
            OsIpcChannel::Receiver(_) => panic!("Opaque channel is not a sender!"),
        }
    }
}

pub struct OsIpcSharedMemory {
    ptr: *mut u8,
    length: usize,
    data: Arc<Vec<u8>>,
}

unsafe impl Send for OsIpcSharedMemory {}
unsafe impl Sync for OsIpcSharedMemory {}

impl Clone for OsIpcSharedMemory {
    fn clone(&self) -> OsIpcSharedMemory {
        OsIpcSharedMemory {
            ptr: self.ptr,
            length: self.length,
            data: self.data.clone(),
        }
    }
}

impl PartialEq for OsIpcSharedMemory {
    fn eq(&self, other: &OsIpcSharedMemory) -> bool {
        **self == **other
    }
}

impl Debug for OsIpcSharedMemory {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        (**self).fmt(formatter)
    }
}

impl Deref for OsIpcSharedMemory {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.ptr.is_null() {
            panic!("attempted to access a consumed `OsIpcSharedMemory`")
        }
        unsafe {
            slice::from_raw_parts(self.ptr, self.length)
        }
    }
}

impl OsIpcSharedMemory {
    pub fn from_byte(byte: u8, length: usize) -> OsIpcSharedMemory {
        let mut v = Arc::new(vec![byte; length]);
        OsIpcSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: length,
            data: v
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> OsIpcSharedMemory {
        let mut v = Arc::new(bytes.to_vec());
        OsIpcSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: v.len(),
            data: v
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum MpscError {
    ChannelClosedError,
    UnknownError,
}

impl MpscError {
    #[allow(dead_code)]
    pub fn channel_is_closed(&self) -> bool {
        *self == MpscError::ChannelClosedError
    }
}

impl From<MpscError> for DeserializeError {
    fn from(mpsc_error: MpscError) -> DeserializeError {
        DeserializeError::IoError(mpsc_error.into())
    }
}

impl From<MpscError> for Error {
    fn from(mpsc_error: MpscError) -> Error {
        match mpsc_error {
            MpscError::ChannelClosedError => {
                Error::new(ErrorKind::BrokenPipe, "MPSC channel closed")
            }
            MpscError::UnknownError => Error::new(ErrorKind::Other, "Other MPSC channel error"),
        }
    }
}

<commit_msg>inprocess: Don't wrap `OsIpcReceiver` to make it `Sync`<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 bincode::serde::DeserializeError;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::collections::hash_map::HashMap;
use std::cell::{RefCell};
use std::io::{Error, ErrorKind};
use std::slice;
use std::fmt::{self, Debug, Formatter};
use std::cmp::{PartialEq};
use std::ops::Deref;
use std::mem;
use std::usize;

use uuid::Uuid;

#[derive(Clone)]
struct ServerRecord {
    sender: OsIpcSender,
    conn_sender: mpsc::Sender<bool>,
    conn_receiver: Arc<Mutex<mpsc::Receiver<bool>>>,
}

impl ServerRecord {
    fn new(sender: OsIpcSender) -> ServerRecord {
        let (tx, rx) = mpsc::channel::<bool>();
        ServerRecord {
            sender: sender,
            conn_sender: tx,
            conn_receiver: Arc::new(Mutex::new(rx)),
        }
    }

    fn accept(&self) {
        self.conn_receiver.lock().unwrap().recv().unwrap();
    }

    fn connect(&self) {
        self.conn_sender.send(true).unwrap();
    }
}

lazy_static! {
    static ref ONE_SHOT_SERVERS: Mutex<HashMap<String,ServerRecord>> = Mutex::new(HashMap::new());
}

struct MpscChannelMessage(Vec<u8>, Vec<OsIpcChannel>, Vec<OsIpcSharedMemory>);

pub fn channel() -> Result<(OsIpcSender, OsIpcReceiver),MpscError> {
    let (base_sender, base_receiver) = mpsc::channel::<MpscChannelMessage>();
    Ok((OsIpcSender::new(base_sender), OsIpcReceiver::new(base_receiver)))
}

pub struct OsIpcReceiver {
    receiver: RefCell<Option<mpsc::Receiver<MpscChannelMessage>>>,
}

impl PartialEq for OsIpcReceiver {
    fn eq(&self, other: &OsIpcReceiver) -> bool {
        self.receiver.borrow().as_ref().map(|rx| rx as *const _) ==
            other.receiver.borrow().as_ref().map(|rx| rx as *const _)
    }
}

// Can't derive, as mpsc::Receiver doesn't implement Debug.
impl fmt::Debug for OsIpcReceiver {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure there is anything useful we could print here.
        write!(f, "OsIpcReceiver {{ .. }}")
    }
}

impl OsIpcReceiver {
    fn new(receiver: mpsc::Receiver<MpscChannelMessage>) -> OsIpcReceiver {
        OsIpcReceiver {
            receiver: RefCell::new(Some(receiver)),
        }
    }

    pub fn consume(&self) -> OsIpcReceiver {
        let receiver = self.receiver.borrow_mut().take();
        OsIpcReceiver::new(receiver.unwrap())
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OsOpaqueIpcChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }

    pub fn try_recv(&self) -> Result<(Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().try_recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OsOpaqueIpcChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }
}

#[derive(Clone)]
pub struct OsIpcSender {
    sender: Arc<Mutex<mpsc::Sender<MpscChannelMessage>>>,
}

impl PartialEq for OsIpcSender {
    fn eq(&self, other: &OsIpcSender) -> bool {
        &*self.sender.lock().unwrap() as *const _ ==
            &*other.sender.lock().unwrap() as *const _
    }
}

// Can't derive, as mpsc::Sender doesn't implement Debug.
impl fmt::Debug for OsIpcSender {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure there is anything useful we could print here.
        write!(f, "OsIpcSender {{ .. }}")
    }
}

impl OsIpcSender {
    fn new(sender: mpsc::Sender<MpscChannelMessage>) -> OsIpcSender {
        OsIpcSender {
            sender: Arc::new(Mutex::new(sender)),
        }
    }

    pub fn connect(name: String) -> Result<OsIpcSender,MpscError> {
        let record = ONE_SHOT_SERVERS.lock().unwrap().get(&name).unwrap().clone();
        record.connect();
        Ok(record.sender)
    }

    pub fn get_max_fragment_size() -> usize {
        usize::MAX
    }

    pub fn send(&self,
                data: &[u8],
                ports: Vec<OsIpcChannel>,
                shared_memory_regions: Vec<OsIpcSharedMemory>)
                -> Result<(),MpscError>
    {
        match self.sender.lock().unwrap().send(MpscChannelMessage(data.to_vec(), ports, shared_memory_regions)) {
            Err(_) => Err(MpscError::ChannelClosedError),
            Ok(_) => Ok(()),
        }
    }
}

pub struct OsIpcReceiverSet {
    last_index: usize,
    receiver_ids: Vec<usize>,
    receivers: Vec<OsIpcReceiver>,
}

impl OsIpcReceiverSet {
    pub fn new() -> Result<OsIpcReceiverSet,MpscError> {
        Ok(OsIpcReceiverSet {
            last_index: 0,
            receiver_ids: vec![],
            receivers: vec![],
        })
    }

    pub fn add(&mut self, receiver: OsIpcReceiver) -> Result<i64,MpscError> {
        self.last_index += 1;
        self.receiver_ids.push(self.last_index);
        self.receivers.push(receiver.consume());
        Ok(self.last_index as i64)
    }

    pub fn select(&mut self) -> Result<Vec<OsIpcSelectionResult>,MpscError> {
        let mut receivers: Vec<Option<mpsc::Receiver<MpscChannelMessage>>> = Vec::with_capacity(self.receivers.len());
        let mut r_id: i64 = -1;
        let mut r_index: usize = 0;

        {
            let select = mpsc::Select::new();
            // we *must* allocate exact capacity for this, because the Handles *can't move*
            let mut handles: Vec<mpsc::Handle<MpscChannelMessage>> = Vec::with_capacity(self.receivers.len());

            for r in &self.receivers {
                let inner_r = mem::replace(&mut *r.receiver.borrow_mut(), None);
                receivers.push(inner_r);
            }

            for r in &receivers {
                unsafe {
                    handles.push(select.handle(r.as_ref().unwrap()));
                    handles.last_mut().unwrap().add();
                }
            }

            let id = select.wait();

            for (index,h) in handles.iter().enumerate() {
                if h.id() == id {
                    r_index = index;
                    r_id = self.receiver_ids[index] as i64;
                    break;
                }
            }
        }

        // put the receivers back
        for (index,r) in self.receivers.iter().enumerate() {
            mem::replace(&mut *r.receiver.borrow_mut(), mem::replace(&mut receivers[index], None));
        }

        if r_id == -1 {
            return Err(MpscError::UnknownError);
        }

        let receivers = &mut self.receivers;
        match receivers[r_index].recv() {
            Ok((data, channels, shmems)) =>
                Ok(vec![OsIpcSelectionResult::DataReceived(r_id, data, channels, shmems)]),
            Err(MpscError::ChannelClosedError) => {
                receivers.remove(r_index);
                self.receiver_ids.remove(r_index);
                Ok(vec![OsIpcSelectionResult::ChannelClosed(r_id)])
            },
            Err(err) => Err(err),
        }
    }
}

pub enum OsIpcSelectionResult {
    DataReceived(i64, Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>),
    ChannelClosed(i64),
}

impl OsIpcSelectionResult {
    pub fn unwrap(self) -> (i64, Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>) {
        match self {
            OsIpcSelectionResult::DataReceived(id, data, channels, shared_memory_regions) => {
                (id, data, channels, shared_memory_regions)
            }
            OsIpcSelectionResult::ChannelClosed(id) => {
                panic!("OsIpcSelectionResult::unwrap(): receiver ID {} was closed!", id)
            }
        }
    }
}

pub struct OsIpcOneShotServer {
    receiver: RefCell<Option<OsIpcReceiver>>,
    name: String,
}

impl OsIpcOneShotServer {
    pub fn new() -> Result<(OsIpcOneShotServer, String),MpscError> {
        let (sender, receiver) = match channel() {
            Ok((s,r)) => (s,r),
            Err(err) => return Err(err),
        };

        let name = Uuid::new_v4().to_string();
        let record = ServerRecord::new(sender);
        ONE_SHOT_SERVERS.lock().unwrap().insert(name.clone(), record);
        Ok((OsIpcOneShotServer {
            receiver: RefCell::new(Some(receiver)),
            name: name.clone(),
        },name.clone()))
    }

    pub fn accept(&self) -> Result<(OsIpcReceiver,
                                    Vec<u8>,
                                    Vec<OsOpaqueIpcChannel>,
                                    Vec<OsIpcSharedMemory>),MpscError>
    {
        let record = ONE_SHOT_SERVERS.lock().unwrap().get(&self.name).unwrap().clone();
        record.accept();
        ONE_SHOT_SERVERS.lock().unwrap().remove(&self.name).unwrap();
        let receiver = self.receiver.borrow_mut().take().unwrap();
        let (data, channels, shmems) = receiver.recv().unwrap();
        Ok((receiver, data, channels, shmems))
    }
}

#[derive(PartialEq, Debug)]
pub enum OsIpcChannel {
    Sender(OsIpcSender),
    Receiver(OsIpcReceiver),
}

#[derive(PartialEq, Debug)]
pub struct OsOpaqueIpcChannel {
    channel: RefCell<Option<OsIpcChannel>>,
}

impl OsOpaqueIpcChannel {
    fn new(channel: OsIpcChannel) -> OsOpaqueIpcChannel {
        OsOpaqueIpcChannel {
            channel: RefCell::new(Some(channel))
        }
    }

    pub fn to_receiver(&self) -> OsIpcReceiver {
        match self.channel.borrow_mut().take().unwrap() {
            OsIpcChannel::Sender(_) => panic!("Opaque channel is not a receiver!"),
            OsIpcChannel::Receiver(r) => r
        }
    }

    pub fn to_sender(&mut self) -> OsIpcSender {
        match self.channel.borrow_mut().take().unwrap() {
            OsIpcChannel::Sender(s) => s,
            OsIpcChannel::Receiver(_) => panic!("Opaque channel is not a sender!"),
        }
    }
}

pub struct OsIpcSharedMemory {
    ptr: *mut u8,
    length: usize,
    data: Arc<Vec<u8>>,
}

unsafe impl Send for OsIpcSharedMemory {}
unsafe impl Sync for OsIpcSharedMemory {}

impl Clone for OsIpcSharedMemory {
    fn clone(&self) -> OsIpcSharedMemory {
        OsIpcSharedMemory {
            ptr: self.ptr,
            length: self.length,
            data: self.data.clone(),
        }
    }
}

impl PartialEq for OsIpcSharedMemory {
    fn eq(&self, other: &OsIpcSharedMemory) -> bool {
        **self == **other
    }
}

impl Debug for OsIpcSharedMemory {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        (**self).fmt(formatter)
    }
}

impl Deref for OsIpcSharedMemory {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.ptr.is_null() {
            panic!("attempted to access a consumed `OsIpcSharedMemory`")
        }
        unsafe {
            slice::from_raw_parts(self.ptr, self.length)
        }
    }
}

impl OsIpcSharedMemory {
    pub fn from_byte(byte: u8, length: usize) -> OsIpcSharedMemory {
        let mut v = Arc::new(vec![byte; length]);
        OsIpcSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: length,
            data: v
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> OsIpcSharedMemory {
        let mut v = Arc::new(bytes.to_vec());
        OsIpcSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: v.len(),
            data: v
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum MpscError {
    ChannelClosedError,
    UnknownError,
}

impl MpscError {
    #[allow(dead_code)]
    pub fn channel_is_closed(&self) -> bool {
        *self == MpscError::ChannelClosedError
    }
}

impl From<MpscError> for DeserializeError {
    fn from(mpsc_error: MpscError) -> DeserializeError {
        DeserializeError::IoError(mpsc_error.into())
    }
}

impl From<MpscError> for Error {
    fn from(mpsc_error: MpscError) -> Error {
        match mpsc_error {
            MpscError::ChannelClosedError => {
                Error::new(ErrorKind::BrokenPipe, "MPSC channel closed")
            }
            MpscError::UnknownError => Error::new(ErrorKind::Other, "Other MPSC channel error"),
        }
    }
}

<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for reading & extracting data from Multiboot 2 boot information.
//!
//! Consult the [Multiboot Specification](http://nongnu.askapache.com/grub/phcoder/multiboot.pdf)
//! for more information.
//  TODO: this is x86-only and should move to `arch`
use memory::PAddr;
use elf::section::{Sections, HeaderRepr};

const END_TAG_LEN: u32 = 8;

#[repr(C)]
pub struct Info { pub length: u32
                , _pad: u32
                , tag_start: Tag
                }

impl Info {

    #[inline]
    pub fn start_addr(&self) -> PAddr {
        PAddr::from(self as *const _ as u64)
    }

    pub fn end_addr(&self) -> PAddr {
        PAddr::from(self.start_addr() + self.length as u64)
    }

    pub unsafe fn from(addr: PAddr) -> Result<&'static Self, &'static str> {
        let info: &Info = &*(addr.into(): u64 as *const Info);
        if info.has_end() { Ok(info) }
        else { Err("Multiboot info structure had no end tag!") }
    }

    /// Finds the tag with the given tag type.
    ///
    /// This is actually safe since the tag types are constrained by The
    /// `TagType` enum
    ///
    /// # Returns
    ///  - `Some(tag)` if a tag of the given type could be found.
    ///  - `None` if no tag of the given type could be found.
    pub fn get_tag(&self, tag_type: TagType) -> Option<&'static Tag> {
        self.tags()
            .find(|t| t.ty == tag_type)
    }

    /// Finds the memory map tag.
    ///
    ///  # Returns
    ///  - `Some(MemMapTag)` if a memory map tag could be found
    ///  - `None` if no tag of the given type could be found.
    #[inline]
    pub fn mem_map(&self) -> Option<&'static MemMapTag> {
        self.get_tag(TagType::MemoryMap)
            .map(|tag| unsafe { &*((tag as *const Tag) as *const MemMapTag) })
    }

    /// Finds the ELF sections tag.
    ///
    ///  # Returns
    ///  - `Some(ElfSectionsTag)` if a memory map tag could be found
    ///  - `None` if no tag of the given type could be found.
    #[inline]
    pub fn elf_sections(&self) -> Option<&'static ElfSectionsTag> {
        self.get_tag(TagType::ELFSections)
            .map(|tag| unsafe {
                &*((tag as *const Tag) as *const ElfSectionsTag)
            })
    }

    /// Returns an iterator over all Multiboot tags.
    #[inline]
    fn tags(&self) -> Tags { Tags(&self.tag_start as *const Tag) }

    /// Returns true if the multiboot structure has a valid end tag.
    fn has_end(&self) -> bool {
        let end_tag_addr
            = (self as *const _) as usize +
              (self.length - END_TAG_LEN) as usize;
        let end_tag = unsafe {&*(end_tag_addr as *const Tag)};
        end_tag.ty == TagType::End && end_tag.length == 8
    }
}

/// A Multiboot tag.
///
/// From the specification:
///
/// Boot information consists of a fixed part and a series of tags.
/// Its start is 8-bytes aligned. Fixed part is as following:
///
///<rawtext>
///
///             +-------------------+
///     u32     | total_size        |
///     u32     | reserved          |
///             +-------------------+
///</rawtext>
///
/// `total_size` contains the total size of boot information including this
/// field and terminating tag in bytes.
/// `reserved` is always set to zero and must be ignored by OS image.
///
///  Every tag begins with following fields:
///<rawtext>
///
///             +-------------------+
///     u32     | type              |
///     u32     | size              |
///             +-------------------+
///</rawtext>
/// `type` contains an identifier of contents of the rest of the tag. `size`
/// contains the size of tag including header fields but not including padding.
/// Tags follow one another padded when necessary in order for each tag to
/// start at 8-bytes aligned address. Tags are terminated by a tag of type `0`
/// and size `8`.
#[repr(C)]
#[derive(Debug)]
pub struct Tag { /// the type of this tag.
                 pub ty: TagType
               , length: u32
               }

/// Types of Multiboot tags
///
/// Refer to Chapter 3 of the Multiboot 2 spec
#[repr(u32)]
#[derive(Debug, Eq, PartialEq)]
pub enum TagType { /// Tag that indicates the end of multiboot tags
                   End              = 0
                 , /// Command line passed to the bootloader
                   CommandLine      = 1
                 , BootloaderName   = 2
                 , Modules          = 3
                 , BasicMemInfo     = 4
                 , BIOSBootDev      = 5
                 , MemoryMap        = 6
                 , VBEInfo          = 7
                 , FramebufferInfo  = 8
                 , ELFSections      = 9
                 , APMTable         = 10
                 }

/// An iterator over Multiboot 2 tags.
struct Tags(*const Tag);

impl Tags {
    #[inline] fn advance(&mut self, size: u32) {
        let next_addr = self.0 as usize + size as usize;
        self.0 = (((next_addr-1) & !0x7) + 0x8) as *const _;
    }
}

impl Iterator for Tags {
    type Item = &'static Tag;

    fn next(&mut self) -> Option<Self::Item> {
        match unsafe { &*self.0 } {
            &Tag{ ty: TagType::End, length: END_TAG_LEN } => None
          , tag => { self.advance(tag.length); Some(tag) }
        }
    }
}

/// A Memory Map tag
#[repr(C)]
pub struct MemMapTag { tag: Tag
                     , pub entry_size: u32
                     , pub entry_version: u32
                     , first_entry: MemArea
                     }

impl MemMapTag {

    /// Returns an iterator over all the memory areas in this tag.
    pub fn areas(&self) -> MemAreas {
        MemAreas { curr: (&self.first_entry) as *const MemArea
                 , last: ((self as *const MemMapTag as u32) +
                         self.tag.length - self.entry_size)
                         as *const MemArea
                 , size: self.entry_size
                 }
    }
}

/// A tag that stores the boot command line.
#[repr(C)]
pub struct CommandLineTag { tag: Tag
                          , /// The boot command line.
                            ///
                            /// The command line is a normal C-style zero-
                            /// terminated UTF-8 string.
                            pub command_line: [u8]
                          }

#[repr(C)]
pub struct ModulesTag { tag: Tag
                      , /// The address at which the module begins.
                        pub mod_begin: PAddr
                      , /// The address at which the module ends.
                        pub mod_end: PAddr
                      , /// A string (typically a command line)
                        pub string: [u8]
                      }

#[repr(u32)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum MemAreaType { Available = 1
                     , Acpi      = 3
                     , Preserve  = 4
                     }

/// A multiboot 2 memory area
#[repr(C)]
pub struct MemArea { /// the starting address of the memory area
                     pub base: PAddr
                   , /// the length of the memory area
                     pub length: PAddr
                   , /// the type of the memory area
                     pub ty: MemAreaType
                   , _pad: u32
                   }

impl MemArea {
    #[inline] pub fn address(&self) -> PAddr {
        self.base + self.length - 1
    }
}

/// An iterator over memory areas
#[derive(Clone)]
pub struct MemAreas { curr: *const MemArea
                    , last: *const MemArea
                    , size: u32
                    }

impl Iterator for MemAreas {
    type Item = &'static MemArea;

    fn next(&mut self) -> Option<&'static MemArea> {
        if self.curr > self.last {
            None
        } else {
            let current = unsafe { &*self.curr };
            self.curr = (self.curr as u32 + self.size) as *const MemArea;
            if current.ty == MemAreaType::Available {
                Some(current)
            } else {
                self.next()
            }
        }
    }
}

#[cfg(target_pointer_width = "32")]
pub type Word = u32;
#[cfg(target_pointer_width = "64")]
pub type Word = u64;

/// A Multiboot 2 ELF sections tag
#[derive(Debug)]
#[repr(packed)]
pub struct ElfSectionsTag { tag: Tag
                          , /// the number of sections pointed to by this tag
                            pub n_sections: u32
                          , /// the size of each ELF section
                            pub section_size: u32
                          , stringtable_idx: u32
                          , first_section: HeaderRepr<Word>
                          }

impl ElfSectionsTag {
    /// Returns an iterator over the ELF sections pointed to by this tag.
    pub fn sections(&'static self) -> Sections<'static, Word> {
        Sections::new( &self.first_section
                     , self.n_sections - 1
                     , self.section_size
                     )
    }
}
<commit_msg>[multiboot2] fix u32 overflow in Info::has_end()<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for reading & extracting data from Multiboot 2 boot information.
//!
//! Consult the [Multiboot Specification](http://nongnu.askapache.com/grub/phcoder/multiboot.pdf)
//! for more information.
//  TODO: this is x86-only and should move to `arch`
use memory::PAddr;
use elf::section::{Sections, HeaderRepr};

const END_TAG_LEN: u32 = 8;

#[repr(C)]
pub struct Info { pub length: u32
                , _pad: u32
                , tag_start: Tag
                }

impl Info {

    #[inline]
    pub fn start_addr(&self) -> PAddr {
        PAddr::from(self as *const _ as u64)
    }

    pub fn end_addr(&self) -> PAddr {
        PAddr::from(self.start_addr() + self.length as u64)
    }

    pub unsafe fn from(addr: PAddr) -> Result<&'static Self, &'static str> {
        let info: &Info = &*(addr.into(): u64 as *const Info);
        if info.has_end() { Ok(info) }
        else { Err("Multiboot info structure had no end tag!") }
    }

    /// Finds the tag with the given tag type.
    ///
    /// This is actually safe since the tag types are constrained by The
    /// `TagType` enum
    ///
    /// # Returns
    ///  - `Some(tag)` if a tag of the given type could be found.
    ///  - `None` if no tag of the given type could be found.
    pub fn get_tag(&self, tag_type: TagType) -> Option<&'static Tag> {
        self.tags()
            .find(|t| t.ty == tag_type)
    }

    /// Finds the memory map tag.
    ///
    ///  # Returns
    ///  - `Some(MemMapTag)` if a memory map tag could be found
    ///  - `None` if no tag of the given type could be found.
    #[inline]
    pub fn mem_map(&self) -> Option<&'static MemMapTag> {
        self.get_tag(TagType::MemoryMap)
            .map(|tag| unsafe { &*((tag as *const Tag) as *const MemMapTag) })
    }

    /// Finds the ELF sections tag.
    ///
    ///  # Returns
    ///  - `Some(ElfSectionsTag)` if a memory map tag could be found
    ///  - `None` if no tag of the given type could be found.
    #[inline]
    pub fn elf_sections(&self) -> Option<&'static ElfSectionsTag> {
        self.get_tag(TagType::ELFSections)
            .map(|tag| unsafe {
                &*((tag as *const Tag) as *const ElfSectionsTag)
            })
    }

    /// Returns an iterator over all Multiboot tags.
    #[inline]
    fn tags(&self) -> Tags { Tags(&self.tag_start as *const Tag) }

    /// Returns true if the multiboot structure has a valid end tag.
    fn has_end(&self) -> bool {
        let end_tag_addr
            = self as *const _ as usize +
              (self.length as usize - END_TAG_LEN as usize);
        let end_tag = unsafe {&*(end_tag_addr as *const Tag)};
        end_tag.ty == TagType::End && end_tag.length == 8
    }
}

/// A Multiboot tag.
///
/// From the specification:
///
/// Boot information consists of a fixed part and a series of tags.
/// Its start is 8-bytes aligned. Fixed part is as following:
///
///<rawtext>
///
///             +-------------------+
///     u32     | total_size        |
///     u32     | reserved          |
///             +-------------------+
///</rawtext>
///
/// `total_size` contains the total size of boot information including this
/// field and terminating tag in bytes.
/// `reserved` is always set to zero and must be ignored by OS image.
///
///  Every tag begins with following fields:
///<rawtext>
///
///             +-------------------+
///     u32     | type              |
///     u32     | size              |
///             +-------------------+
///</rawtext>
/// `type` contains an identifier of contents of the rest of the tag. `size`
/// contains the size of tag including header fields but not including padding.
/// Tags follow one another padded when necessary in order for each tag to
/// start at 8-bytes aligned address. Tags are terminated by a tag of type `0`
/// and size `8`.
#[repr(C)]
#[derive(Debug)]
pub struct Tag { /// the type of this tag.
                 pub ty: TagType
               , length: u32
               }

/// Types of Multiboot tags
///
/// Refer to Chapter 3 of the Multiboot 2 spec
#[repr(u32)]
#[derive(Debug, Eq, PartialEq)]
pub enum TagType { /// Tag that indicates the end of multiboot tags
                   End              = 0
                 , /// Command line passed to the bootloader
                   CommandLine      = 1
                 , BootloaderName   = 2
                 , Modules          = 3
                 , BasicMemInfo     = 4
                 , BIOSBootDev      = 5
                 , MemoryMap        = 6
                 , VBEInfo          = 7
                 , FramebufferInfo  = 8
                 , ELFSections      = 9
                 , APMTable         = 10
                 }

/// An iterator over Multiboot 2 tags.
struct Tags(*const Tag);

impl Tags {
    #[inline] fn advance(&mut self, size: u32) {
        let next_addr = self.0 as usize + size as usize;
        self.0 = (((next_addr-1) & !0x7) + 0x8) as *const _;
    }
}

impl Iterator for Tags {
    type Item = &'static Tag;

    fn next(&mut self) -> Option<Self::Item> {
        match unsafe { &*self.0 } {
            &Tag{ ty: TagType::End, length: END_TAG_LEN } => None
          , tag => { self.advance(tag.length); Some(tag) }
        }
    }
}

/// A Memory Map tag
#[repr(C)]
pub struct MemMapTag { tag: Tag
                     , pub entry_size: u32
                     , pub entry_version: u32
                     , first_entry: MemArea
                     }

impl MemMapTag {

    /// Returns an iterator over all the memory areas in this tag.
    pub fn areas(&self) -> MemAreas {
        MemAreas { curr: (&self.first_entry) as *const MemArea
                 , last: ((self as *const MemMapTag as u32) +
                         self.tag.length - self.entry_size)
                         as *const MemArea
                 , size: self.entry_size
                 }
    }
}

/// A tag that stores the boot command line.
#[repr(C)]
pub struct CommandLineTag { tag: Tag
                          , /// The boot command line.
                            ///
                            /// The command line is a normal C-style zero-
                            /// terminated UTF-8 string.
                            pub command_line: [u8]
                          }

#[repr(C)]
pub struct ModulesTag { tag: Tag
                      , /// The address at which the module begins.
                        pub mod_begin: PAddr
                      , /// The address at which the module ends.
                        pub mod_end: PAddr
                      , /// A string (typically a command line)
                        pub string: [u8]
                      }

#[repr(u32)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum MemAreaType { Available = 1
                     , Acpi      = 3
                     , Preserve  = 4
                     }

/// A multiboot 2 memory area
#[repr(C)]
pub struct MemArea { /// the starting address of the memory area
                     pub base: PAddr
                   , /// the length of the memory area
                     pub length: PAddr
                   , /// the type of the memory area
                     pub ty: MemAreaType
                   , _pad: u32
                   }

impl MemArea {
    #[inline] pub fn address(&self) -> PAddr {
        self.base + self.length - 1
    }
}

/// An iterator over memory areas
#[derive(Clone)]
pub struct MemAreas { curr: *const MemArea
                    , last: *const MemArea
                    , size: u32
                    }

impl Iterator for MemAreas {
    type Item = &'static MemArea;

    fn next(&mut self) -> Option<&'static MemArea> {
        if self.curr > self.last {
            None
        } else {
            let current = unsafe { &*self.curr };
            self.curr = (self.curr as u32 + self.size) as *const MemArea;
            if current.ty == MemAreaType::Available {
                Some(current)
            } else {
                self.next()
            }
        }
    }
}

#[cfg(target_pointer_width = "32")]
pub type Word = u32;
#[cfg(target_pointer_width = "64")]
pub type Word = u64;

/// A Multiboot 2 ELF sections tag
#[derive(Debug)]
#[repr(packed)]
pub struct ElfSectionsTag { tag: Tag
                          , /// the number of sections pointed to by this tag
                            pub n_sections: u32
                          , /// the size of each ELF section
                            pub section_size: u32
                          , stringtable_idx: u32
                          , first_section: HeaderRepr<Word>
                          }

impl ElfSectionsTag {
    /// Returns an iterator over the ELF sections pointed to by this tag.
    pub fn sections(&'static self) -> Sections<'static, Word> {
        Sections::new( &self.first_section
                     , self.n_sections - 1
                     , self.section_size
                     )
    }
}
<|endoftext|>


<commit_before>//! An exfiltrator providing the process that caused the signal.
//!
//! The [`WithOrigin`] is an [`Exfiltrator`][crate::iterator::exfiltrator::Exfiltrator] that
//! provides the information about sending process in addition to the signal number, through the
//! [`Origin`] type.
//!
//! See the [`WithOrigin`] example.

// Note on unsafety in this module:
// * Implementing an unsafe trait, that one needs to ensure at least store is async-signal-safe.
//   That's done by delegating to the Channel (and reading an atomic pointer, but that one is
//   primitive op).
// * A bit of juggling with atomic and raw pointers. In effect, that is just late lazy
//   initialization, the Slot is in line with Option would be, except that it is set atomically
//   during the init. Lifetime is ensured by not dropping until the Drop of the whole slot and that
//   is checked by taking `&mut self`.

use std::ptr;
use std::sync::atomic::{AtomicPtr, Ordering};

use libc::{c_int, pid_t, siginfo_t, uid_t};
use signal_hook_sys::internal::{Cause as ICause, SigInfo};

use super::sealed::Exfiltrator;
use crate::channel::Channel;

/// Information about process, as presented in the signal metadata.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub struct Process {
    /// The process ID.
    pub pid: pid_t,

    /// The user owning the process.
    pub uid: uid_t,
}

/// The means by which a signal was sent by other process.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Sent {
    /// The `kill` call.
    User,

    /// The `tkill` call.
    ///
    /// This is likely linux specific.
    TKill,

    /// `sigqueue`.
    Queue,

    /// `mq_notify`.
    MesgQ,
}

/// A child changed its state.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Chld {
    /// The child exited normally.
    Exited,

    /// It got killed by a signal.
    Killed,

    /// It got killed by a signal and dumped core.
    Dumped,

    /// The child was trapped by a `SIGTRAP` signal.
    Trapped,

    /// The child got stopped.
    Stopped,

    /// The child continued (after being stopped).
    Continued,
}

/// What caused a signal.
///
/// This is a best-effort (and possibly incomplete) representation of the C `siginfo_t::si_code`.
/// It may differ between OSes and may be extended in future versions.
///
/// Note that this doesn't contain all the „fault“ signals (`SIGILL`, `SIGSEGV` and similar).
/// There's no reasonable way to use the exfiltrators with them, since the handler either needs to
/// terminate the process or somehow recover from the situation. Things based on exfiltrators do
/// neither, which would cause an UB and therefore these values just don't make sense.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Cause {
    /// The cause is unknown.
    ///
    /// Some systems don't fill this in. Some systems have values we don't understand. Some signals
    /// don't have specific reasons to come to being.
    Unknown,

    /// Sent by the kernel.
    ///
    /// This probably exists only on Linux.
    Kernel,

    /// The signal was sent by other process.
    Sent(Sent),

    /// A `SIGCHLD`, caused by a child process changing state.
    Chld(Chld),
}

impl From<ICause> for Cause {
    fn from(c: ICause) -> Cause {
        match c {
            ICause::Kernel => Cause::Kernel,
            ICause::User => Cause::Sent(Sent::User),
            ICause::TKill => Cause::Sent(Sent::TKill),
            ICause::Queue => Cause::Sent(Sent::Queue),
            ICause::MesgQ => Cause::Sent(Sent::MesgQ),
            ICause::Exited => Cause::Chld(Chld::Exited),
            ICause::Killed => Cause::Chld(Chld::Killed),
            ICause::Dumped => Cause::Chld(Chld::Dumped),
            ICause::Trapped => Cause::Chld(Chld::Trapped),
            ICause::Stopped => Cause::Chld(Chld::Stopped),
            ICause::Continued => Cause::Chld(Chld::Continued),
            // Unknown and possibly others if the underlying lib is updated
            _ => Cause::Unknown,
        }
    }
}

/// Information about a signal and its origin.
///
/// This is produced by the [`WithOrigin`] exfiltrator. See the example there.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Origin {
    /// The signal that happened.
    pub signal: c_int,

    /// Information about the process that caused the signal.
    ///
    /// Note that not all signals are caused by a specific process or have the information
    /// available („fault“ signals like `SIGBUS` don't have, any signal may be sent by the kernel
    /// instead of a specific process).
    ///
    /// This is filled in whenever available. For most signals, this is the process that sent the
    /// signal (by `kill` or similar), for `SIGCHLD` it is the child that caused the signal.
    pub process: Option<Process>,

    /// How the signal happened.
    ///
    /// This is a best-effort value. In particular, some systems may have causes not known to this
    /// library. Some other systems (MacOS) does not fill the value in so there's no way to know.
    /// In all these cases, this will contain [`Cause::Unknown`].
    ///
    /// Some values are platform specific and not available on other systems.
    ///
    /// Future versions may enrich the enum by further values.
    pub cause: Cause,
}

#[derive(Default, Debug)]
struct Slot(AtomicPtr<Channel<Origin>>);

impl Drop for Slot {
    fn drop(&mut self) {
        let ptr = self.0.swap(ptr::null_mut(), Ordering::Acquire);
        if !ptr.is_null() {
            unsafe { drop(Box::from_raw(ptr)) }
        }
    }
}

/// The [`Exfiltrator`][crate::iterator::exfiltrator::Exfiltrator] that produces [`Origin`] of
/// signals.
///
/// # Examples
///
/// ```rust
/// # use signal_hook::SIGUSR1;
/// # use signal_hook::iterator::SignalsInfo;
/// # use signal_hook::iterator::exfiltrator::origin::WithOrigin;
/// #
/// # fn main() -> Result<(), std::io::Error> {
/// // Subscribe to SIGUSR1, with information about the process.
/// let signals = SignalsInfo::<WithOrigin>::new(&[SIGUSR1])?;
///
/// // Send a signal to ourselves.
/// let my_pid = unsafe { libc::getpid() };
/// unsafe { libc::kill(my_pid, SIGUSR1) };
///
/// // Grab the signal and look into the details.
/// let received = signals.forever().next().unwrap();
///
/// assert_eq!(SIGUSR1, received.signal);
/// assert_eq!(my_pid, received.process.unwrap().pid);
/// # Ok(()) }
/// ```
#[derive(Copy, Clone, Debug, Default)]
pub struct WithOrigin;

unsafe impl Exfiltrator for WithOrigin {
    type Storage = AtomicPtr<Channel<Origin>>;
    type Output = Origin;
    fn supports_signal(&self, _: c_int) -> bool {
        true
    }

    fn store(&self, slot: &Self::Storage, signal: c_int, info: &siginfo_t) {
        let extracted = SigInfo::extract(info);
        let process = extracted.process.map(|p| Process {
            pid: p.pid,
            uid: p.uid,
        });
        let origin = Origin {
            cause: extracted.cause.into(),
            signal,
            process,
        };
        // Condition just not to crash if someone forgot to call init.
        //
        // Lifetime is from init to our own drop, and drop needs &mut self.
        if let Some(slot) = unsafe { slot.load(Ordering::Acquire).as_ref() } {
            slot.send(origin);
        }
    }

    fn load(&self, slot: &Self::Storage, _: c_int) -> Option<Origin> {
        let slot = unsafe { slot.load(Ordering::Acquire).as_ref() };
        // Condition just not to crash if someone forgot to call init.
        slot.and_then(|s| s.recv())
    }

    fn init(&self, slot: &Self::Storage, _: c_int) {
        let new = Box::new(Channel::default());
        let old = slot.swap(Box::into_raw(new), Ordering::Release);
        // We leak the pointer on purpose here. This is invalid state anyway and must not happen,
        // but if it still does, we can't drop that while some other thread might still be having
        // the raw pointer.
        assert!(old.is_null(), "Init called multiple times");
    }
}
<commit_msg>Don't leak on Origin exfiltrator drop<commit_after>//! An exfiltrator providing the process that caused the signal.
//!
//! The [`WithOrigin`] is an [`Exfiltrator`][crate::iterator::exfiltrator::Exfiltrator] that
//! provides the information about sending process in addition to the signal number, through the
//! [`Origin`] type.
//!
//! See the [`WithOrigin`] example.

// Note on unsafety in this module:
// * Implementing an unsafe trait, that one needs to ensure at least store is async-signal-safe.
//   That's done by delegating to the Channel (and reading an atomic pointer, but that one is
//   primitive op).
// * A bit of juggling with atomic and raw pointers. In effect, that is just late lazy
//   initialization, the Slot is in line with Option would be, except that it is set atomically
//   during the init. Lifetime is ensured by not dropping until the Drop of the whole slot and that
//   is checked by taking `&mut self`.

use std::ptr;
use std::sync::atomic::{AtomicPtr, Ordering};

use libc::{c_int, pid_t, siginfo_t, uid_t};
use signal_hook_sys::internal::{Cause as ICause, SigInfo};

use super::sealed::Exfiltrator;
use crate::channel::Channel;

/// Information about process, as presented in the signal metadata.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub struct Process {
    /// The process ID.
    pub pid: pid_t,

    /// The user owning the process.
    pub uid: uid_t,
}

/// The means by which a signal was sent by other process.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Sent {
    /// The `kill` call.
    User,

    /// The `tkill` call.
    ///
    /// This is likely linux specific.
    TKill,

    /// `sigqueue`.
    Queue,

    /// `mq_notify`.
    MesgQ,
}

/// A child changed its state.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Chld {
    /// The child exited normally.
    Exited,

    /// It got killed by a signal.
    Killed,

    /// It got killed by a signal and dumped core.
    Dumped,

    /// The child was trapped by a `SIGTRAP` signal.
    Trapped,

    /// The child got stopped.
    Stopped,

    /// The child continued (after being stopped).
    Continued,
}

/// What caused a signal.
///
/// This is a best-effort (and possibly incomplete) representation of the C `siginfo_t::si_code`.
/// It may differ between OSes and may be extended in future versions.
///
/// Note that this doesn't contain all the „fault“ signals (`SIGILL`, `SIGSEGV` and similar).
/// There's no reasonable way to use the exfiltrators with them, since the handler either needs to
/// terminate the process or somehow recover from the situation. Things based on exfiltrators do
/// neither, which would cause an UB and therefore these values just don't make sense.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Cause {
    /// The cause is unknown.
    ///
    /// Some systems don't fill this in. Some systems have values we don't understand. Some signals
    /// don't have specific reasons to come to being.
    Unknown,

    /// Sent by the kernel.
    ///
    /// This probably exists only on Linux.
    Kernel,

    /// The signal was sent by other process.
    Sent(Sent),

    /// A `SIGCHLD`, caused by a child process changing state.
    Chld(Chld),
}

impl From<ICause> for Cause {
    fn from(c: ICause) -> Cause {
        match c {
            ICause::Kernel => Cause::Kernel,
            ICause::User => Cause::Sent(Sent::User),
            ICause::TKill => Cause::Sent(Sent::TKill),
            ICause::Queue => Cause::Sent(Sent::Queue),
            ICause::MesgQ => Cause::Sent(Sent::MesgQ),
            ICause::Exited => Cause::Chld(Chld::Exited),
            ICause::Killed => Cause::Chld(Chld::Killed),
            ICause::Dumped => Cause::Chld(Chld::Dumped),
            ICause::Trapped => Cause::Chld(Chld::Trapped),
            ICause::Stopped => Cause::Chld(Chld::Stopped),
            ICause::Continued => Cause::Chld(Chld::Continued),
            // Unknown and possibly others if the underlying lib is updated
            _ => Cause::Unknown,
        }
    }
}

/// Information about a signal and its origin.
///
/// This is produced by the [`WithOrigin`] exfiltrator. See the example there.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Origin {
    /// The signal that happened.
    pub signal: c_int,

    /// Information about the process that caused the signal.
    ///
    /// Note that not all signals are caused by a specific process or have the information
    /// available („fault“ signals like `SIGBUS` don't have, any signal may be sent by the kernel
    /// instead of a specific process).
    ///
    /// This is filled in whenever available. For most signals, this is the process that sent the
    /// signal (by `kill` or similar), for `SIGCHLD` it is the child that caused the signal.
    pub process: Option<Process>,

    /// How the signal happened.
    ///
    /// This is a best-effort value. In particular, some systems may have causes not known to this
    /// library. Some other systems (MacOS) does not fill the value in so there's no way to know.
    /// In all these cases, this will contain [`Cause::Unknown`].
    ///
    /// Some values are platform specific and not available on other systems.
    ///
    /// Future versions may enrich the enum by further values.
    pub cause: Cause,
}

#[doc(hidden)]
#[derive(Default, Debug)]
pub struct Slot(AtomicPtr<Channel<Origin>>);

impl Drop for Slot {
    fn drop(&mut self) {
        let ptr = self.0.swap(ptr::null_mut(), Ordering::Acquire);
        if !ptr.is_null() {
            unsafe { drop(Box::from_raw(ptr)) }
        }
    }
}

/// The [`Exfiltrator`][crate::iterator::exfiltrator::Exfiltrator] that produces [`Origin`] of
/// signals.
///
/// # Examples
///
/// ```rust
/// # use signal_hook::SIGUSR1;
/// # use signal_hook::iterator::SignalsInfo;
/// # use signal_hook::iterator::exfiltrator::origin::WithOrigin;
/// #
/// # fn main() -> Result<(), std::io::Error> {
/// // Subscribe to SIGUSR1, with information about the process.
/// let signals = SignalsInfo::<WithOrigin>::new(&[SIGUSR1])?;
///
/// // Send a signal to ourselves.
/// let my_pid = unsafe { libc::getpid() };
/// unsafe { libc::kill(my_pid, SIGUSR1) };
///
/// // Grab the signal and look into the details.
/// let received = signals.forever().next().unwrap();
///
/// assert_eq!(SIGUSR1, received.signal);
/// assert_eq!(my_pid, received.process.unwrap().pid);
/// # Ok(()) }
/// ```
#[derive(Copy, Clone, Debug, Default)]
pub struct WithOrigin;

unsafe impl Exfiltrator for WithOrigin {
    type Storage = Slot;
    type Output = Origin;
    fn supports_signal(&self, _: c_int) -> bool {
        true
    }

    fn store(&self, slot: &Self::Storage, signal: c_int, info: &siginfo_t) {
        let extracted = SigInfo::extract(info);
        let process = extracted.process.map(|p| Process {
            pid: p.pid,
            uid: p.uid,
        });
        let origin = Origin {
            cause: extracted.cause.into(),
            signal,
            process,
        };
        // Condition just not to crash if someone forgot to call init.
        //
        // Lifetime is from init to our own drop, and drop needs &mut self.
        if let Some(slot) = unsafe { slot.0.load(Ordering::Acquire).as_ref() } {
            slot.send(origin);
        }
    }

    fn load(&self, slot: &Self::Storage, _: c_int) -> Option<Origin> {
        let slot = unsafe { slot.0.load(Ordering::Acquire).as_ref() };
        // Condition just not to crash if someone forgot to call init.
        slot.and_then(|s| s.recv())
    }

    fn init(&self, slot: &Self::Storage, _: c_int) {
        let new = Box::new(Channel::default());
        let old = slot.0.swap(Box::into_raw(new), Ordering::Release);
        // We leak the pointer on purpose here. This is invalid state anyway and must not happen,
        // but if it still does, we can't drop that while some other thread might still be having
        // the raw pointer.
        assert!(old.is_null(), "Init called multiple times");
    }
}
<|endoftext|>


<commit_before>use tui::{
    backend::TestBackend,
    buffer::Buffer,
    style::{Color, Style},
    widgets::{List, ListState, Text},
    Terminal,
};

#[test]
fn it_should_highlight_the_selected_item() {
    let backend = TestBackend::new(10, 3);
    let mut terminal = Terminal::new(backend).unwrap();
    let mut state = ListState::default();
    state.select(Some(1));
    terminal
        .draw(|mut f| {
            let size = f.size();
            let items = vec![
                Text::raw("Item 1"),
                Text::raw("Item 2"),
                Text::raw("Item 3"),
            ];
            let list = List::new(items.into_iter())
                .highlight_style(Style::default().bg(Color::Yellow))
                .highlight_symbol(">> ");
            f.render_stateful_widget(list, size, &mut state);
        })
        .unwrap();
    let mut expected = Buffer::with_lines(vec!["   Item 1 ", ">> Item 2 ", "   Item 3 "]);
    for x in 0..9 {
        expected.get_mut(x, 1).set_bg(Color::Yellow);
    }
    assert_eq!(*terminal.backend().buffer(), expected);
}
<commit_msg>test: assert items are correctly truncated in the `List` widget<commit_after>use tui::{
    backend::TestBackend,
    buffer::Buffer,
    layout::Rect,
    style::{Color, Style},
    symbols,
    widgets::{Block, Borders, List, ListState, Text},
    Terminal,
};

#[test]
fn it_should_highlight_the_selected_item() {
    let backend = TestBackend::new(10, 3);
    let mut terminal = Terminal::new(backend).unwrap();
    let mut state = ListState::default();
    state.select(Some(1));
    terminal
        .draw(|mut f| {
            let size = f.size();
            let items = vec![
                Text::raw("Item 1"),
                Text::raw("Item 2"),
                Text::raw("Item 3"),
            ];
            let list = List::new(items.into_iter())
                .highlight_style(Style::default().bg(Color::Yellow))
                .highlight_symbol(">> ");
            f.render_stateful_widget(list, size, &mut state);
        })
        .unwrap();
    let mut expected = Buffer::with_lines(vec!["   Item 1 ", ">> Item 2 ", "   Item 3 "]);
    for x in 0..9 {
        expected.get_mut(x, 1).set_bg(Color::Yellow);
    }
    assert_eq!(*terminal.backend().buffer(), expected);
}

#[test]
fn it_should_truncate_items() {
    let backend = TestBackend::new(10, 2);
    let mut terminal = Terminal::new(backend).unwrap();

    struct TruncateTestCase<'a> {
        name: &'a str,
        selected: Option<usize>,
        items: Vec<Text<'a>>,
        expected: Buffer,
    }

    let cases = vec![
        TruncateTestCase {
            name: "an item is selected",
            selected: Some(0),
            items: vec![Text::raw("A very long line"), Text::raw("A very long line")],
            expected: Buffer::with_lines(vec![
                format!(">> A ve{}  ", symbols::line::VERTICAL),
                format!("   A ve{}  ", symbols::line::VERTICAL),
            ]),
        },
        TruncateTestCase {
            name: "no item is selected",
            selected: None,
            items: vec![Text::raw("A very long line"), Text::raw("A very long line")],
            expected: Buffer::with_lines(vec![
                format!("A very {}  ", symbols::line::VERTICAL),
                format!("A very {}  ", symbols::line::VERTICAL),
            ]),
        },
    ];
    for mut case in cases {
        let mut state = ListState::default();
        state.select(case.selected);
        let items = case.items.drain(..);
        terminal
            .draw(|mut f| {
                let list = List::new(items.into_iter())
                    .block(Block::default().borders(Borders::RIGHT))
                    .highlight_symbol(">> ");
                f.render_stateful_widget(list, Rect::new(0, 0, 8, 2), &mut state);
            })
            .unwrap();
        assert_eq!(
            *terminal.backend().buffer(),
            case.expected,
            "Failed to assert the buffer matches the expected one when {}",
            case.name
        );
    }
}
<|endoftext|>


<commit_before>use super::unsupported;
use crate::ffi::CStr;
use crate::io;
use crate::num::NonZeroUsize;
use crate::sys::unsupported;
use crate::time::Duration;

pub struct Thread(!);

pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;

impl Thread {
    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
    pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
        unsupported()
    }

    pub fn yield_now() {}

    pub fn set_name(_name: &CStr) {}

    pub fn sleep(dur: Duration) {
        use crate::arch::wasm32;
        use crate::cmp;

        // Use an atomic wait to block the current thread artificially with a
        // timeout listed. Note that we should never be notified (return value
        // of 0) or our comparison should never fail (return value of 1) so we
        // should always only resume execution through a timeout (return value
        // 2).
        let mut nanos = dur.as_nanos();
        while nanos > 0 {
            let amt = cmp::min(i64::MAX as u128, nanos);
            let mut x = 0;
            let val = unsafe { wasm32::memory_atomic_wait32(&mut x, 0, amt as i64) };
            debug_assert_eq!(val, 2);
            nanos -= amt;
        }
    }

    pub fn join(self) {}
}

pub fn available_concurrency() -> io::Result<NonZeroUsize> {
    unsupported()
}

pub mod guard {
    pub type Guard = !;
    pub unsafe fn current() -> Option<Guard> {
        None
    }
    pub unsafe fn init() -> Option<Guard> {
        None
    }
}

// We currently just use our own thread-local to store our
// current thread's ID, and then we lazily initialize it to something allocated
// from a global counter.
pub fn my_id() -> u32 {
    use crate::sync::atomic::{AtomicU32, Ordering::SeqCst};

    static NEXT_ID: AtomicU32 = AtomicU32::new(0);

    #[thread_local]
    static mut MY_ID: u32 = 0;

    unsafe {
        // If our thread ID isn't set yet then we need to allocate one. Do so
        // with with a simple "atomically add to a global counter" strategy.
        // This strategy doesn't handled what happens when the counter
        // overflows, however, so just abort everything once the counter
        // overflows and eventually we could have some sort of recycling scheme
        // (or maybe this is all totally irrelevant by that point!). In any case
        // though we're using a CAS loop instead of a `fetch_add` to ensure that
        // the global counter never overflows.
        if MY_ID == 0 {
            let mut cur = NEXT_ID.load(SeqCst);
            MY_ID = loop {
                let next = cur.checked_add(1).unwrap_or_else(|| crate::process::abort());
                match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) {
                    Ok(_) => break next,
                    Err(i) => cur = i,
                }
            };
        }
        MY_ID
    }
}
<commit_msg>Fix double import in wasm thread<commit_after>use crate::ffi::CStr;
use crate::io;
use crate::num::NonZeroUsize;
use crate::sys::unsupported;
use crate::time::Duration;

pub struct Thread(!);

pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;

impl Thread {
    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
    pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
        unsupported()
    }

    pub fn yield_now() {}

    pub fn set_name(_name: &CStr) {}

    pub fn sleep(dur: Duration) {
        use crate::arch::wasm32;
        use crate::cmp;

        // Use an atomic wait to block the current thread artificially with a
        // timeout listed. Note that we should never be notified (return value
        // of 0) or our comparison should never fail (return value of 1) so we
        // should always only resume execution through a timeout (return value
        // 2).
        let mut nanos = dur.as_nanos();
        while nanos > 0 {
            let amt = cmp::min(i64::MAX as u128, nanos);
            let mut x = 0;
            let val = unsafe { wasm32::memory_atomic_wait32(&mut x, 0, amt as i64) };
            debug_assert_eq!(val, 2);
            nanos -= amt;
        }
    }

    pub fn join(self) {}
}

pub fn available_concurrency() -> io::Result<NonZeroUsize> {
    unsupported()
}

pub mod guard {
    pub type Guard = !;
    pub unsafe fn current() -> Option<Guard> {
        None
    }
    pub unsafe fn init() -> Option<Guard> {
        None
    }
}

// We currently just use our own thread-local to store our
// current thread's ID, and then we lazily initialize it to something allocated
// from a global counter.
pub fn my_id() -> u32 {
    use crate::sync::atomic::{AtomicU32, Ordering::SeqCst};

    static NEXT_ID: AtomicU32 = AtomicU32::new(0);

    #[thread_local]
    static mut MY_ID: u32 = 0;

    unsafe {
        // If our thread ID isn't set yet then we need to allocate one. Do so
        // with with a simple "atomically add to a global counter" strategy.
        // This strategy doesn't handled what happens when the counter
        // overflows, however, so just abort everything once the counter
        // overflows and eventually we could have some sort of recycling scheme
        // (or maybe this is all totally irrelevant by that point!). In any case
        // though we're using a CAS loop instead of a `fetch_add` to ensure that
        // the global counter never overflows.
        if MY_ID == 0 {
            let mut cur = NEXT_ID.load(SeqCst);
            MY_ID = loop {
                let next = cur.checked_add(1).unwrap_or_else(|| crate::process::abort());
                match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) {
                    Ok(_) => break next,
                    Err(i) => cur = i,
                }
            };
        }
        MY_ID
    }
}
<|endoftext|>


<commit_before>#[macro_use]
mod common;

use common::util::*;

static UTIL_NAME: &'static str = "sort";

#[test]
fn numeric1() {
    numeric_helper(1);
}

#[test]
fn numeric2() {
    numeric_helper(2);
}

#[test]
fn numeric3() {
    numeric_helper(3);
}

#[test]
fn numeric4() {
    numeric_helper(4);
}

#[test]
fn numeric5() {
    numeric_helper(5);
}

#[test]
fn numeric6() {
    numeric_helper(6);
}

#[test]
fn human1() {
    test_helper(&String::from("human1"), &String::from("-H"));
}

#[test]
fn month1() {
    test_helper(&String::from("month1"), &String::from("-M"));
}

fn numeric_helper(test_num: isize) {
    test_helper(&format!("numeric{}", test_num), &String::from("-n"))
}

fn test_helper(file_name: &String, args: &String) {
    let (at, mut ucmd) = testing(UTIL_NAME);
    ucmd.arg(args);
    let out = ucmd.arg(format!("{}{}", file_name, ".txt")).run().stdout;

    let filename = format!("{}{}", file_name, ".ans");
    assert_eq!(out, at.read(&filename));
}
<commit_msg>tests/sort: fix flag for human numeric test<commit_after>#[macro_use]
mod common;

use common::util::*;

static UTIL_NAME: &'static str = "sort";

#[test]
fn numeric1() {
    numeric_helper(1);
}

#[test]
fn numeric2() {
    numeric_helper(2);
}

#[test]
fn numeric3() {
    numeric_helper(3);
}

#[test]
fn numeric4() {
    numeric_helper(4);
}

#[test]
fn numeric5() {
    numeric_helper(5);
}

#[test]
fn numeric6() {
    numeric_helper(6);
}

#[test]
fn human1() {
    test_helper(&String::from("human1"), &String::from("-h"));
}

#[test]
fn month1() {
    test_helper(&String::from("month1"), &String::from("-M"));
}

fn numeric_helper(test_num: isize) {
    test_helper(&format!("numeric{}", test_num), &String::from("-n"))
}

fn test_helper(file_name: &String, args: &String) {
    let (at, mut ucmd) = testing(UTIL_NAME);
    ucmd.arg(args);
    let out = ucmd.arg(format!("{}{}", file_name, ".txt")).run().stdout;

    let filename = format!("{}{}", file_name, ".ans");
    assert_eq!(out, at.read(&filename));
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::fs::{self, File, ReadDir, DirEntry};
use std::path::Path;
use std::vec;
use std::io::BufReader;
use std::cmp::Ordering;
use std::str::FromStr;

/// Get process stats (/proc/[pid]/stat)
mod stat;
/// Get process status (/proc/[pid]/status)
mod status;

use self::stat::PidStat;
use self::status::PidStatus;
use error::{ProcError, ProcFile, ProcOper};
use TaskId;

/// A struct containing information about a process.
///
/// This struct contains information from various files inside the
/// /proc/[pid] directory (for the respective pid).
#[derive(Debug)]
pub struct Pid {
    /// The tid of this process
    pub pid: TaskId,
    /// The /proc/[pid]/stat file
    pub stat: Box<PidStat>,
    /// The /proc/[pid]/status file
    pub status: Box<PidStatus>,
    /// The /proc/[pid]/cmdline file
    pub cmdline: Vec<String>,
    /// If this is a thread, this is set to true.
    /// Threads will never have tasks attached.
    is_thread: bool,
    /// Vec of threads under /proc/[pid]/tasks/[tid]
    threads: Option<Vec<Pid>>,
}

impl Pid {
    /// Create a new Pid struct for a process, given a pid.
    pub fn new(pid: TaskId) -> Result<Self, ProcError> {
        let pid_dir = Path::new("/proc");
        Self::new_dir(pid_dir, pid)
    }

    fn new_dir(proc_dir: &Path, pid: TaskId) -> Result<Self, ProcError> {
        let proc_dir = proc_dir.join(pid.to_string());
        let pid_stat = try!(PidStat::new(&proc_dir));
        let pid_status = try!(PidStatus::new(&proc_dir));
        let cmdline = try!(Self::read_cmdline(&proc_dir));

        Ok(Pid {
            pid: pid,
            stat: Box::new(pid_stat),
            status: Box::new(pid_status),
            cmdline: cmdline,
            is_thread: false,
            threads: None,
        })
    }

    /// Given a /proc/[pid] directory, read the respective /proc/[pid]/cmdline
    /// file and return them in a Vec.
    fn read_cmdline(proc_dir: &Path) -> Result<Vec<String>, ProcError> {
        File::open(proc_dir.join("cmdline"))
            .map_err(|e| ProcError::new_err(ProcOper::Opening, ProcFile::PidCmdline, e))
            .and_then(|file| {
                let mut contents = Vec::new();
                try!(
                    BufReader::with_capacity(4096, file)
                        .read_to_end(&mut contents)
                        .map_err(|e| ProcError::new_err(ProcOper::Reading, ProcFile::PidCmdline, e))
                );
                if contents.ends_with(&['\0' as u8]) {
                    let _ = contents.pop();
                }
                Ok(contents)
            }).and_then(|contents| {
                String::from_utf8(contents)
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::PidCmdline,
                                    Some("parsing utf8"))))
            }).map(|contents|
                contents
                    .split('\0')
                    .map(|a| a.to_string())
                    .collect()
            )
    }

    /// Determine whether this process matches this query
    fn query(&self, query: &PidQuery) -> bool {
        match *query {
            PidQuery::PidQuery(q) => PidQuery::taskid_query(self.stat.pid, q),
            PidQuery::PpidQuery(q) => PidQuery::taskid_query(self.stat.ppid, q),
            PidQuery::NameQuery(ref q) => PidQuery::string_query(&self.stat.comm, &q),
            PidQuery::CmdlineQuery(ref q) => PidQuery::string_query(&self.cmdline.join(" "), &q),
            PidQuery::NoneQuery => true
        }
    }

    pub fn tasks(&mut self) -> Option<Vec<Pid>> {
        self.tasks_query(PidQuery::NoneQuery)
    }

    // TODO: Work out if this really should return Option<_>
    // or Option<Result<Vec<Pid>>>. Otherwise the error is uncaught.
    pub fn tasks_query(&self, query: PidQuery) -> Option<Vec<Pid>> {
        if self.is_thread {
            return None;
        }

        PidIter::new_tid_query(self.pid, query.clone()).unwrap()
            .filter(|p| {
                let query = query.clone();
                match *p {
                    Ok(ref pid) => pid.query(&query),
                    Err(_) => true
                }
            }).collect::<Result<Vec<_>, _>>().ok()
    }
}

impl PartialEq for Pid {
    fn eq(&self, other: &Self) -> bool {
        self.stat.pid.eq(&other.stat.pid)
    }
}

impl Eq for Pid {}
impl PartialOrd for Pid {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for Pid {
    fn cmp(&self, other: &Self) -> Ordering {
        self.stat.pid.cmp(&other.stat.pid)
    }
}

/// An Iterator over processes in the system.
///
/// If a process disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct PidIter {
    dir_iter: ReadDir,
    query: PidQuery,
}

impl PidIter {
    /// Create a new iterator over all processes in /proc.
    pub fn new() -> Result<Self, ProcError> {
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all processes in /proc, but only yield
    /// processes that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        let proc_dir = Path::new("/proc");
        let dir_iter = try!(
            fs::read_dir(proc_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::ProcDir, Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir_iter: dir_iter,
            query: query,
        })
    }

    fn new_tid_query(pid: TaskId, query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = format!("/proc/{}/task", pid);
        let task_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(task_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::PidTaskDir,
                        Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir_iter: dir_iter,
            query: query
        })
    }

    /// Given a DirEntry, try to create a Pid struct, and only return if
    /// it matches the query, and is complete.
    fn proc_dir_filter(entry_opt: Result<DirEntry, io::Error>, query: &PidQuery)
        -> Option<Result<Pid, ProcError>> {
        let file = entry_opt
            .map_err(|e|
                ProcError::new(ProcOper::Reading, ProcFile::ProcDir, Some(e), Some("PidIter"))
            )
            .and_then(|entry|
                entry.file_name().into_string()
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::ProcDir, Some("PidIter"))))
            );

        if let Err(e) = file{
            return Some(Err(e));
        }

        // Ensure filename is an integer (skip if not)
        match file.unwrap().parse() {
            Ok(pid) => {
                // If an error is not hard (error opening or reading file),
                // do not error as it may be a now-dead process.
                // If a parsing error occurs, then do return an error.
                let prc = match Pid::new(pid) {
                    Ok(prc) => prc,
                    Err(e) => {
                        if e.is_hard() {
                            return Some(Err(e));
                        } else {
                            return None;
                        }
                    }
                };
                match prc.query(query) {
                    true => Some(Ok(prc)),
                    false => None
                }
            },
            Err(_) => None
        }
    }
}

impl Iterator for PidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        for entry in self.dir_iter.by_ref() {
            match Self::proc_dir_filter(entry, &self.query) {
                some @ Some(_) => return some,
                None => continue
            }
        }
        None
    }

    /// Size may be anywhere from 0 to number of dirs.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, self.dir_iter.size_hint().1)
    }
}

/// An Iterator over threads of processes in the system.
///
/// If a task disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct TidIter {
    pid_iter: PidIter,
    task_iter: Option<vec::IntoIter<Pid>>,
    query: PidQuery,
}

impl TidIter {
    /// Create a new iterator over all tasks in /proc.
    pub fn new() -> Result<Self, ProcError> {
            println!("{:?}", 3);
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all tasks in /proc, but only yield
    /// those that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        Ok(TidIter{
            pid_iter: try!(PidIter::new_query(query.clone())),
            task_iter: None,
            query: query,
        })
    }
}

impl Iterator for TidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.task_iter.is_none() {
                let pid = match self.pid_iter.next() {
                    Some(Ok(pid)) => pid,
                    Some(Err(e)) => { return Some(Err(e)) },
                    None => { return None; }
                };
                let tasks_vec = pid.tasks_query(self.query.clone());
                if let Some(vec) = tasks_vec {
                    self.task_iter = Some(vec.into_iter());
                }
                continue;
            } else {
                let next = self.task_iter.as_mut().unwrap().next();
                match next {
                    Some(pid) => { return Some(Ok(pid)); },
                    None => { self.task_iter = None; },
                };
            }
        }
    }
}

#[derive(Clone, Debug)]
/// A list of query types for process querying.
pub enum PidQuery {
    /// Query by pid
    PidQuery(TaskId),
    /// Query by ppid
    PpidQuery(TaskId),
    /// Query by program name
    NameQuery(String),
    /// Query by cmdline contents (joined with space)
    CmdlineQuery(String),
    /// An empty query that always matches
    NoneQuery
}

impl PidQuery {
    /// Given a user-specified query string, decode it into
    /// an appropriate query.
    ///
    /// Bare number -> PidQuery
    /// Bare string -> NameQuery
    ///
    /// type=query is supported for the following types;
    /// pid -> PidQuery
    /// ppid -> PpidQuery
    /// name -> NameQuery
    /// cmdline -> CmdlineQuery
    fn create_query(query: &str) -> Result<PidQuery, String> {
        let splits: Vec<_> = query.splitn(2, '=').collect();

        match splits.len() {
            0 => Ok(PidQuery::NoneQuery),
            1 => Ok(match query.parse().ok() {
                Some(tid) => PidQuery::PidQuery(tid),
                None => PidQuery::NameQuery(query.to_owned())
            }),
            _ => {
                let q_text = splits[1].to_owned();
                let q_tid = q_text.parse();
                match &*splits[0].to_lowercase() {
                    "pid" => q_tid.map(|q| PidQuery::PidQuery(q))
                        .or(Err("Query value for type 'pid' not valid".to_owned())),
                    "ppid" => q_tid.map(|q| PidQuery::PpidQuery(q))
                        .or(Err("Query value for type 'ppid' not valid".to_owned())),
                    "name" => Ok(PidQuery::NameQuery(q_text)),
                    "cmdline" => Ok(PidQuery::CmdlineQuery(q_text)),
                    _ => Err("Invalid query type".to_owned())
                }
            }
        }
    }

    /// Match a pid by simple equality.
    pub fn taskid_query(tid: TaskId, query: TaskId) -> bool {
        tid == query
    }

    /// For strings, use a substring search.
    pub fn string_query(text: &str, query: &str) -> bool {
        text.contains(query)
    }
}

impl FromStr for PidQuery {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::create_query(s)
    }
}
<commit_msg>Fix thread parsing, previously was failing to use right dir<commit_after>use std::io;
use std::io::prelude::*;
use std::fs::{self, File, ReadDir, DirEntry};
use std::path::Path;
use std::vec;
use std::io::BufReader;
use std::cmp::Ordering;
use std::str::FromStr;

/// Get process stats (/proc/[pid]/stat)
mod stat;
/// Get process status (/proc/[pid]/status)
mod status;

use self::stat::PidStat;
use self::status::PidStatus;
use error::{ProcError, ProcFile, ProcOper};
use TaskId;

/// A struct containing information about a process.
///
/// This struct contains information from various files inside the
/// /proc/[pid] directory (for the respective pid).
#[derive(Debug)]
pub struct Pid {
    /// The tid of this process
    pub pid: TaskId,
    /// The /proc/[pid]/stat file
    pub stat: Box<PidStat>,
    /// The /proc/[pid]/status file
    pub status: Box<PidStatus>,
    /// The /proc/[pid]/cmdline file
    pub cmdline: Vec<String>,
    /// If this is a thread, this is set to true.
    /// Threads will never have tasks attached.
    is_thread: bool,
    /// Vec of threads under /proc/[pid]/tasks/[tid]
    threads: Option<Vec<Pid>>,
}

impl Pid {
    /// Create a new Pid struct for a process, given a pid.
    pub fn new(pid: TaskId) -> Result<Self, ProcError> {
        let pid_dir = Path::new("/proc");
        Self::new_dir(pid_dir, pid)
    }

    fn new_dir(proc_dir: &Path, pid: TaskId) -> Result<Self, ProcError> {
        let proc_dir = proc_dir.join(pid.to_string());
        let pid_stat = try!(PidStat::new(&proc_dir));
        let pid_status = try!(PidStatus::new(&proc_dir));
        let cmdline = try!(Self::read_cmdline(&proc_dir));

        Ok(Pid {
            pid: pid,
            stat: Box::new(pid_stat),
            status: Box::new(pid_status),
            cmdline: cmdline,
            is_thread: false,
            threads: None,
        })
    }

    /// Given a /proc/[pid] directory, read the respective /proc/[pid]/cmdline
    /// file and return them in a Vec.
    fn read_cmdline(proc_dir: &Path) -> Result<Vec<String>, ProcError> {
        File::open(proc_dir.join("cmdline"))
            .map_err(|e| ProcError::new_err(ProcOper::Opening, ProcFile::PidCmdline, e))
            .and_then(|file| {
                let mut contents = Vec::new();
                try!(
                    BufReader::with_capacity(4096, file)
                        .read_to_end(&mut contents)
                        .map_err(|e| ProcError::new_err(ProcOper::Reading, ProcFile::PidCmdline, e))
                );
                if contents.ends_with(&['\0' as u8]) {
                    let _ = contents.pop();
                }
                Ok(contents)
            }).and_then(|contents| {
                String::from_utf8(contents)
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::PidCmdline,
                                    Some("parsing utf8"))))
            }).map(|contents|
                contents
                    .split('\0')
                    .map(|a| a.to_string())
                    .collect()
            )
    }

    /// Determine whether this process matches this query
    fn query(&self, query: &PidQuery) -> bool {
        match *query {
            PidQuery::PidQuery(q) => PidQuery::taskid_query(self.stat.pid, q),
            PidQuery::PpidQuery(q) => PidQuery::taskid_query(self.stat.ppid, q),
            PidQuery::NameQuery(ref q) => PidQuery::string_query(&self.stat.comm, &q),
            PidQuery::CmdlineQuery(ref q) => PidQuery::string_query(&self.cmdline.join(" "), &q),
            PidQuery::NoneQuery => true
        }
    }

    pub fn tasks(&mut self) -> Option<Vec<Pid>> {
        self.tasks_query(PidQuery::NoneQuery)
    }

    // TODO: Work out if this really should return Option<_>
    // or Option<Result<Vec<Pid>>>. Otherwise the error is uncaught.
    pub fn tasks_query(&self, query: PidQuery) -> Option<Vec<Pid>> {
        if self.is_thread {
            return None;
        }

        PidIter::new_tid_query(self.pid, query.clone()).unwrap()
            .filter(|p| {
                let query = query.clone();
                match *p {
                    Ok(ref pid) => pid.query(&query),
                    Err(_) => true
                }
            }).collect::<Result<Vec<_>, _>>().ok()
    }
}

impl PartialEq for Pid {
    fn eq(&self, other: &Self) -> bool {
        self.stat.pid.eq(&other.stat.pid)
    }
}

impl Eq for Pid {}
impl PartialOrd for Pid {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for Pid {
    fn cmp(&self, other: &Self) -> Ordering {
        self.stat.pid.cmp(&other.stat.pid)
    }
}

/// An Iterator over processes in the system.
///
/// If a process disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct PidIter {
    dir: String,
    dir_iter: ReadDir,
    query: PidQuery,
}

impl PidIter {
    /// Create a new iterator over all processes in /proc.
    pub fn new() -> Result<Self, ProcError> {
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all processes in /proc, but only yield
    /// processes that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = "/proc".to_owned();
        let proc_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(proc_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::ProcDir, Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query,
        })
    }

    fn new_tid_query(pid: TaskId, query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = format!("/proc/{}/task", pid);
        let task_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(task_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::PidTaskDir,
                        Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query
        })
    }

    /// Given a DirEntry, try to create a Pid struct, and only return if
    /// it matches the query, and is complete.
    fn proc_dir_filter(entry_opt: Result<DirEntry, io::Error>, query: &PidQuery, dir_name: &str)
        -> Option<Result<Pid, ProcError>> {
        let file = entry_opt
            .map_err(|e|
                ProcError::new(ProcOper::Reading, ProcFile::ProcDir, Some(e), Some("PidIter"))
            )
            .and_then(|entry|
                entry.file_name().into_string()
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::ProcDir, Some("PidIter"))))
            );

        if let Err(e) = file{
            return Some(Err(e));
        }

        // Ensure filename is an integer (skip if not)
        match file.unwrap().parse() {
            Ok(pid) => {
                // If an error is not hard (error opening or reading file),
                // do not error as it may be a now-dead process.
                // If a parsing error occurs, then do return an error.
                let prc = match Pid::new_dir(Path::new(&dir_name), pid) {
                    Ok(prc) => prc,
                    Err(e) => {
                        if e.is_hard() {
                            return Some(Err(e));
                        } else {
                            return None;
                        }
                    }
                };
                match prc.query(&query) {
                    true => Some(Ok(prc)),
                    false => None
                }
            },
            Err(_) => None
        }
    }
}

impl Iterator for PidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        for entry in self.dir_iter.by_ref() {
            match Self::proc_dir_filter(entry, &self.query, &self.dir) {
                some @ Some(_) => return some,
                None => continue
            }
        }
        None
    }

    /// Size may be anywhere from 0 to number of dirs.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, self.dir_iter.size_hint().1)
    }
}

/// An Iterator over threads of processes in the system.
///
/// If a task disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct TidIter {
    pid_iter: PidIter,
    task_iter: Option<vec::IntoIter<Pid>>,
    query: PidQuery,
}

impl TidIter {
    /// Create a new iterator over all tasks in /proc.
    pub fn new() -> Result<Self, ProcError> {
            println!("{:?}", 3);
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all tasks in /proc, but only yield
    /// those that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        Ok(TidIter{
            pid_iter: try!(PidIter::new_query(query.clone())),
            task_iter: None,
            query: query,
        })
    }
}

impl Iterator for TidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.task_iter.is_none() {
                let pid = match self.pid_iter.next() {
                    Some(Ok(pid)) => pid,
                    Some(Err(e)) => { return Some(Err(e)) },
                    None => { return None; }
                };
                let tasks_vec = pid.tasks_query(self.query.clone());
                if let Some(vec) = tasks_vec {
                    self.task_iter = Some(vec.into_iter());
                }
                continue;
            } else {
                let next = self.task_iter.as_mut().unwrap().next();
                match next {
                    Some(pid) => { return Some(Ok(pid)); },
                    None => { self.task_iter = None; },
                };
            }
        }
    }
}

#[derive(Clone, Debug)]
/// A list of query types for process querying.
pub enum PidQuery {
    /// Query by pid
    PidQuery(TaskId),
    /// Query by ppid
    PpidQuery(TaskId),
    /// Query by program name
    NameQuery(String),
    /// Query by cmdline contents (joined with space)
    CmdlineQuery(String),
    /// An empty query that always matches
    NoneQuery
}

impl PidQuery {
    /// Given a user-specified query string, decode it into
    /// an appropriate query.
    ///
    /// Bare number -> PidQuery
    /// Bare string -> NameQuery
    ///
    /// type=query is supported for the following types;
    /// pid -> PidQuery
    /// ppid -> PpidQuery
    /// name -> NameQuery
    /// cmdline -> CmdlineQuery
    fn create_query(query: &str) -> Result<PidQuery, String> {
        let splits: Vec<_> = query.splitn(2, '=').collect();

        match splits.len() {
            0 => Ok(PidQuery::NoneQuery),
            1 => Ok(match query.parse().ok() {
                Some(tid) => PidQuery::PidQuery(tid),
                None => PidQuery::NameQuery(query.to_owned())
            }),
            _ => {
                let q_text = splits[1].to_owned();
                let q_tid = q_text.parse();
                match &*splits[0].to_lowercase() {
                    "pid" => q_tid.map(|q| PidQuery::PidQuery(q))
                        .or(Err("Query value for type 'pid' not valid".to_owned())),
                    "ppid" => q_tid.map(|q| PidQuery::PpidQuery(q))
                        .or(Err("Query value for type 'ppid' not valid".to_owned())),
                    "name" => Ok(PidQuery::NameQuery(q_text)),
                    "cmdline" => Ok(PidQuery::CmdlineQuery(q_text)),
                    _ => Err("Invalid query type".to_owned())
                }
            }
        }
    }

    /// Match a pid by simple equality.
    pub fn taskid_query(tid: TaskId, query: TaskId) -> bool {
        tid == query
    }

    /// For strings, use a substring search.
    pub fn string_query(text: &str, query: &str) -> bool {
        text.contains(query)
    }
}

impl FromStr for PidQuery {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::create_query(s)
    }
}
<|endoftext|>