<commit_before>use libc;
use std::thread;
use std::rc::Rc;
use std::sync::{Arc};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::collections::BTreeSet;
use parking_lot::{Mutex, MutexGuard, RwLock, RwLockReadGuard};
use chashmap::{CHashMap, ReadGuard, WriteGuard};
use ram::schema::Schemas;
use ram::types::Id;
use ram::segs::{Segment, SEGMENT_SIZE};
use ram::cell::{Cell, ReadError, WriteError, Header};
use server::ServerMeta;

pub type CellReadGuard<'a> = ReadGuard<'a, u64, usize>;
pub type CellWriteGuard<'a> = WriteGuard<'a, u64, usize>;

pub struct Chunk {
    pub id: usize,
    pub addr: usize,
    pub index: CHashMap<u64, usize>,
    pub segs: Vec<Segment>,
    pub seg_round: AtomicUsize,
    pub meta: Arc<ServerMeta>,
    pub backup_storage: Option<String>,
}

pub struct Chunks {
    pub list: Vec<Chunk>,
}

impl Chunk {
    fn new (id: usize, size: usize, meta: Arc<ServerMeta>, back_storage: Option<String>) -> Chunk {
        let mem_ptr = unsafe {libc::malloc(size)} as usize;
        let seg_count = size / SEGMENT_SIZE;
        let mut segments = Vec::<Segment>::new();
        for seg_idx in 0..seg_count {
            let seg_addr = mem_ptr + seg_idx * SEGMENT_SIZE;
            segments.push(Segment {
                addr: seg_addr,
                id: seg_idx,
                bound: seg_addr + SEGMENT_SIZE,
                append_header: AtomicUsize::new(seg_addr),
                lock: RwLock::new(()),
                frags: Mutex::new(BTreeSet::new()),
            });
        }
        debug!("creating chunk at {}, segments {}", mem_ptr, seg_count + 1);
        Chunk {
            id: id,
            addr: mem_ptr,
            index: CHashMap::new(),
            meta: meta,
            segs: segments,
            seg_round: AtomicUsize::new(0),
            backup_storage: back_storage
        }
    }
    pub fn try_acquire(&self, size: usize) -> Option<(usize, RwLockReadGuard<()>)> {
        let mut retried = 0;
        loop {
            let n = self.seg_round.load(Ordering::Relaxed);
            let seg_id = n % self.segs.len();
            let seg_acquire = self.segs[seg_id].try_acquire(size);
            match seg_acquire {
                None => {
                    if retried > self.segs.len() * 2 {return None;}
                    self.seg_round.fetch_add(1, Ordering::Relaxed);
                    retried += 1;
                },
                _ => {return seg_acquire;}
            }
        }
    }
    fn locate_segment(&self, location: usize) -> &Segment {
        let offset = location - self.addr;
        let seg_id = offset / SEGMENT_SIZE;
        return &self.segs[seg_id];
    }
    pub fn location_for_read<'a>(&self, hash: u64)
        -> Option<CellReadGuard> {
        match self.index.get(&hash) {
            Some(index) => {
                if *index == 0 {
                    return None
                }
                return Some(index);
            },
            None => None
        }
    }
    pub fn location_for_write(&self, hash: u64)
        -> Option<CellWriteGuard> {
        match self.index.get_mut(&hash) {
            Some(index) => {
                if *index == 0 {
                    return None
                }
                return Some(index);
            },
            None => None
        }
    }
    fn put_tombstone(&self, location: usize) {
        let seg = self.locate_segment(location);
        seg.put_cell_tombstone(location);
        seg.put_frag(location);
    }
    fn read_cell(&self, hash: u64) -> Result<Cell, ReadError> {
        match self.location_for_read(hash) {
            Some(loc) => {
                Cell::from_chunk_raw(*loc, self)
            },
            None => Err(ReadError::CellDoesNotExisted)
        }
    }
    fn write_cell(&self, cell: &mut Cell) -> Result<Header, WriteError> {
        let hash = cell.header.hash;
        if self.location_for_read(hash).is_some() {
            return Err(WriteError::CellAlreadyExisted);
        } else {
            let written = cell.write_to_chunk(self);
            let mut need_rollback = false;
            if let Ok(loc) = written {
                self.index.upsert(
                    hash,
                    ||{loc},
                    |inserted_loc| {
                        if *inserted_loc == 0 {
                            *inserted_loc = loc
                        } else {
                            need_rollback = true;
                        }
                    }
                );
                if need_rollback {
                    self.put_tombstone(loc);
                    return Err(WriteError::CellAlreadyExisted)
                }
            }
            return Ok(cell.header)
        }
    }
    fn update_cell(&self, cell: &mut Cell) -> Result<Header, WriteError> {
        let hash = cell.header.hash;
        if let Some(mut cell_location) = self.location_for_write(hash) {
            let written = cell.write_to_chunk(self);
            if let Ok(new_location) = written {
                let old_location = *cell_location;
                *cell_location = new_location;
                self.put_tombstone(old_location);
            }
            return Ok(cell.header);
        } else {
            return Err(WriteError::CellDoesNotExisted)
        }
    }
    fn update_cell_by<U>(&self, hash: u64, update: U) -> Result<Cell, WriteError>
        where U: Fn(Cell) -> Option<Cell> {
        if let Some(mut cell_location) = self.location_for_write(hash) {
            let cell = Cell::from_chunk_raw(*cell_location, self);
            match cell {
                Ok(cell) => {
                    let mut new_cell = update(cell);
                    if let Some(mut new_cell) = new_cell {
                        let written = new_cell.write_to_chunk(self);
                        if let Ok(new_location) = written {
                            let old_location = *cell_location;
                            *cell_location = new_location;
                            self.put_tombstone(old_location);
                        }
                        return Ok(new_cell);
                    } else {
                        return Err(WriteError::UserCanceledUpdate);
                    }
                },
                Err(e) => Err(WriteError::ReadError(e))
            }
        } else {
            return Err(WriteError::CellDoesNotExisted)
        }
    }
    fn remove_cell(&self, hash: u64) -> Result<(), WriteError> {
        if let Some(cell_location) = self.index.remove(&hash) {
            self.put_tombstone(cell_location);
            Ok(())
        } else {
            Err(WriteError::CellDoesNotExisted)
        }
    }
    fn remove_cell_by<P>(&self, hash: u64, predict: P) -> Result<(), WriteError>
        where P: Fn(Cell) -> bool {
        if let Some(cell_location) = self.location_for_read(hash) {
            let cell = Cell::from_chunk_raw(*cell_location, self);
            match cell {
                Ok(cell) => {
                    if predict(cell) {
                        self.index.remove(&hash);
                        self.put_tombstone(*cell_location);
                        return Ok(());
                    } else {
                        return Err(WriteError::DeletionPredictionFailed);
                    }
                },
                Err(e) => Err(WriteError::ReadError(e))
            }
        } else {
            return Err(WriteError::CellDoesNotExisted);
        }
    }
    fn dispose (&mut self) {
        debug!("disposing chunk at {}", self.addr);
        unsafe {
            libc::free(self.addr as *mut libc::c_void)
        }
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        self.dispose();
    }
}

impl Chunks {
    pub fn new (count: usize, size: usize, meta: Arc<ServerMeta>, backup_storage: Option<String>) -> Arc<Chunks> {
        let chunk_size = size / count;
        let mut chunks = Vec::new();
        debug!("Creating {} chunks, total {} bytes", count, size);
        for i in 0..count {
            let backup_storage = match backup_storage {
                Some(ref dir) => Some(format!("{}/data-{}.bak", dir, i)),
                None => None
            };
            chunks.push(Chunk::new(i, chunk_size, meta.clone(), backup_storage));
        }
        Arc::new(Chunks {
            list: chunks
        })
    }
    pub fn new_dummy(count: usize, size: usize) -> Arc<Chunks> {
        Chunks::new(count, size, Arc::<ServerMeta>::new(ServerMeta {
            schemas: Schemas::new(None)
        }), None)
    }
    fn locate_chunk_by_partition(&self, partition: u64) -> &Chunk {
        let chunk_id = partition as usize % self.list.len();
        return &self.list[chunk_id];
    }
    fn locate_chunk_by_key(&self, key: &Id) -> (&Chunk, u64) {
        return (self.locate_chunk_by_partition(key.higher), key.lower);
    }
    pub fn read_cell(&self, key: &Id) -> Result<Cell, ReadError> {
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return chunk.read_cell(hash);
    }
    pub fn write_cell(&self, cell: &mut Cell) -> Result<Header, WriteError> {
        let chunk = self.locate_chunk_by_partition(cell.header.partition);
        return chunk.write_cell(cell);
    }
    pub fn update_cell(&self, cell: &mut Cell) -> Result<Header, WriteError> {
        let chunk = self.locate_chunk_by_partition(cell.header.partition);
        return chunk.update_cell(cell);
    }
    pub fn update_cell_by<U>(&self, key: &Id, update: U) -> Result<Cell, WriteError>
        where U: Fn(Cell) -> Option<Cell>{
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return chunk.update_cell_by(hash, update);
    }
    pub fn remove_cell(&self, key: &Id) -> Result<(), WriteError> {
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return chunk.remove_cell(hash);
    }
    pub fn remove_cell_by<P>(&self, key: &Id, predict: P) -> Result<(), WriteError>
        where P: Fn(Cell) -> bool {
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return chunk.remove_cell_by(hash, predict);
    }
    pub fn chunk_ptr(&self, key: &Id) -> usize {
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return *chunk.location_for_read(hash).unwrap()
    }
}<commit_msg>fix remove cell by deadlock<commit_after>use libc;
use std::thread;
use std::rc::Rc;
use std::sync::{Arc};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::collections::BTreeSet;
use parking_lot::{Mutex, MutexGuard, RwLock, RwLockReadGuard};
use chashmap::{CHashMap, ReadGuard, WriteGuard};
use ram::schema::Schemas;
use ram::types::Id;
use ram::segs::{Segment, SEGMENT_SIZE};
use ram::cell::{Cell, ReadError, WriteError, Header};
use server::ServerMeta;

pub type CellReadGuard<'a> = ReadGuard<'a, u64, usize>;
pub type CellWriteGuard<'a> = WriteGuard<'a, u64, usize>;

pub struct Chunk {
    pub id: usize,
    pub addr: usize,
    pub index: CHashMap<u64, usize>,
    pub segs: Vec<Segment>,
    pub seg_round: AtomicUsize,
    pub meta: Arc<ServerMeta>,
    pub backup_storage: Option<String>,
}

pub struct Chunks {
    pub list: Vec<Chunk>,
}

impl Chunk {
    fn new (id: usize, size: usize, meta: Arc<ServerMeta>, back_storage: Option<String>) -> Chunk {
        let mem_ptr = unsafe {libc::malloc(size)} as usize;
        let seg_count = size / SEGMENT_SIZE;
        let mut segments = Vec::<Segment>::new();
        for seg_idx in 0..seg_count {
            let seg_addr = mem_ptr + seg_idx * SEGMENT_SIZE;
            segments.push(Segment {
                addr: seg_addr,
                id: seg_idx,
                bound: seg_addr + SEGMENT_SIZE,
                append_header: AtomicUsize::new(seg_addr),
                lock: RwLock::new(()),
                frags: Mutex::new(BTreeSet::new()),
            });
        }
        debug!("creating chunk at {}, segments {}", mem_ptr, seg_count + 1);
        Chunk {
            id: id,
            addr: mem_ptr,
            index: CHashMap::new(),
            meta: meta,
            segs: segments,
            seg_round: AtomicUsize::new(0),
            backup_storage: back_storage
        }
    }
    pub fn try_acquire(&self, size: usize) -> Option<(usize, RwLockReadGuard<()>)> {
        let mut retried = 0;
        loop {
            let n = self.seg_round.load(Ordering::Relaxed);
            let seg_id = n % self.segs.len();
            let seg_acquire = self.segs[seg_id].try_acquire(size);
            match seg_acquire {
                None => {
                    if retried > self.segs.len() * 2 {return None;}
                    self.seg_round.fetch_add(1, Ordering::Relaxed);
                    retried += 1;
                },
                _ => {return seg_acquire;}
            }
        }
    }
    fn locate_segment(&self, location: usize) -> &Segment {
        let offset = location - self.addr;
        let seg_id = offset / SEGMENT_SIZE;
        return &self.segs[seg_id];
    }
    pub fn location_for_read<'a>(&self, hash: u64)
        -> Option<CellReadGuard> {
        match self.index.get(&hash) {
            Some(index) => {
                if *index == 0 {
                    return None
                }
                return Some(index);
            },
            None => None
        }
    }
    pub fn location_for_write(&self, hash: u64)
        -> Option<CellWriteGuard> {
        match self.index.get_mut(&hash) {
            Some(index) => {
                if *index == 0 {
                    return None
                }
                return Some(index);
            },
            None => None
        }
    }
    fn put_tombstone(&self, location: usize) {
        let seg = self.locate_segment(location);
        seg.put_cell_tombstone(location);
        seg.put_frag(location);
    }
    fn read_cell(&self, hash: u64) -> Result<Cell, ReadError> {
        match self.location_for_read(hash) {
            Some(loc) => {
                Cell::from_chunk_raw(*loc, self)
            },
            None => Err(ReadError::CellDoesNotExisted)
        }
    }
    fn write_cell(&self, cell: &mut Cell) -> Result<Header, WriteError> {
        let hash = cell.header.hash;
        if self.location_for_read(hash).is_some() {
            return Err(WriteError::CellAlreadyExisted);
        } else {
            let written = cell.write_to_chunk(self);
            let mut need_rollback = false;
            if let Ok(loc) = written {
                self.index.upsert(
                    hash,
                    ||{loc},
                    |inserted_loc| {
                        if *inserted_loc == 0 {
                            *inserted_loc = loc
                        } else {
                            need_rollback = true;
                        }
                    }
                );
                if need_rollback {
                    self.put_tombstone(loc);
                    return Err(WriteError::CellAlreadyExisted)
                }
            }
            return Ok(cell.header)
        }
    }
    fn update_cell(&self, cell: &mut Cell) -> Result<Header, WriteError> {
        let hash = cell.header.hash;
        if let Some(mut cell_location) = self.location_for_write(hash) {
            let written = cell.write_to_chunk(self);
            if let Ok(new_location) = written {
                let old_location = *cell_location;
                *cell_location = new_location;
                self.put_tombstone(old_location);
            }
            return Ok(cell.header);
        } else {
            return Err(WriteError::CellDoesNotExisted)
        }
    }
    fn update_cell_by<U>(&self, hash: u64, update: U) -> Result<Cell, WriteError>
        where U: Fn(Cell) -> Option<Cell> {
        if let Some(mut cell_location) = self.location_for_write(hash) {
            let cell = Cell::from_chunk_raw(*cell_location, self);
            match cell {
                Ok(cell) => {
                    let mut new_cell = update(cell);
                    if let Some(mut new_cell) = new_cell {
                        let written = new_cell.write_to_chunk(self);
                        if let Ok(new_location) = written {
                            let old_location = *cell_location;
                            *cell_location = new_location;
                            self.put_tombstone(old_location);
                        }
                        return Ok(new_cell);
                    } else {
                        return Err(WriteError::UserCanceledUpdate);
                    }
                },
                Err(e) => Err(WriteError::ReadError(e))
            }
        } else {
            return Err(WriteError::CellDoesNotExisted)
        }
    }
    fn remove_cell(&self, hash: u64) -> Result<(), WriteError> {
        if let Some(cell_location) = self.index.remove(&hash) {
            self.put_tombstone(cell_location);
            Ok(())
        } else {
            Err(WriteError::CellDoesNotExisted)
        }
    }
    fn remove_cell_by<P>(&self, hash: u64, predict: P) -> Result<(), WriteError>
        where P: Fn(Cell) -> bool {
        if let Some(mut cell_location) = self.location_for_write(hash) {
            let cell = Cell::from_chunk_raw(*cell_location, self);
            match cell {
                Ok(cell) => {
                    if predict(cell) {
                        self.put_tombstone(*cell_location);
                        *cell_location = 0;
                        // can't remove from index at this time due to write deadlock
                        // TODO: FIX IT, remove cell by prediction, atomically
                        return Ok(());
                    } else {
                        return Err(WriteError::DeletionPredictionFailed);
                    }
                },
                Err(e) => Err(WriteError::ReadError(e))
            }
        } else {
            return Err(WriteError::CellDoesNotExisted);
        }
    }
    fn dispose (&mut self) {
        debug!("disposing chunk at {}", self.addr);
        unsafe {
            libc::free(self.addr as *mut libc::c_void)
        }
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        self.dispose();
    }
}

impl Chunks {
    pub fn new (count: usize, size: usize, meta: Arc<ServerMeta>, backup_storage: Option<String>) -> Arc<Chunks> {
        let chunk_size = size / count;
        let mut chunks = Vec::new();
        debug!("Creating {} chunks, total {} bytes", count, size);
        for i in 0..count {
            let backup_storage = match backup_storage {
                Some(ref dir) => Some(format!("{}/data-{}.bak", dir, i)),
                None => None
            };
            chunks.push(Chunk::new(i, chunk_size, meta.clone(), backup_storage));
        }
        Arc::new(Chunks {
            list: chunks
        })
    }
    pub fn new_dummy(count: usize, size: usize) -> Arc<Chunks> {
        Chunks::new(count, size, Arc::<ServerMeta>::new(ServerMeta {
            schemas: Schemas::new(None)
        }), None)
    }
    fn locate_chunk_by_partition(&self, partition: u64) -> &Chunk {
        let chunk_id = partition as usize % self.list.len();
        return &self.list[chunk_id];
    }
    fn locate_chunk_by_key(&self, key: &Id) -> (&Chunk, u64) {
        return (self.locate_chunk_by_partition(key.higher), key.lower);
    }
    pub fn read_cell(&self, key: &Id) -> Result<Cell, ReadError> {
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return chunk.read_cell(hash);
    }
    pub fn write_cell(&self, cell: &mut Cell) -> Result<Header, WriteError> {
        let chunk = self.locate_chunk_by_partition(cell.header.partition);
        return chunk.write_cell(cell);
    }
    pub fn update_cell(&self, cell: &mut Cell) -> Result<Header, WriteError> {
        let chunk = self.locate_chunk_by_partition(cell.header.partition);
        return chunk.update_cell(cell);
    }
    pub fn update_cell_by<U>(&self, key: &Id, update: U) -> Result<Cell, WriteError>
        where U: Fn(Cell) -> Option<Cell>{
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return chunk.update_cell_by(hash, update);
    }
    pub fn remove_cell(&self, key: &Id) -> Result<(), WriteError> {
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return chunk.remove_cell(hash);
    }
    pub fn remove_cell_by<P>(&self, key: &Id, predict: P) -> Result<(), WriteError>
        where P: Fn(Cell) -> bool {
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return chunk.remove_cell_by(hash, predict);
    }
    pub fn chunk_ptr(&self, key: &Id) -> usize {
        let (chunk, hash) = self.locate_chunk_by_key(key);
        return *chunk.location_for_read(hash).unwrap()
    }
}<|endoftext|>


<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicU8, Ordering};
#[cfg(feature = "nightly")]
type U8 = u8;
#[cfg(not(feature = "nightly"))]
use stable::{AtomicU8, Ordering};
#[cfg(not(feature = "nightly"))]
type U8 = usize;
use parking_lot_core::{self, UnparkResult, SpinWait, UnparkToken};

// UnparkToken used to indicate that that the target thread should attempt to
// lock the mutex again as soon as it is unparked.
pub const TOKEN_NORMAL: UnparkToken = UnparkToken(0);

// UnparkToken used to indicate that the mutex is being handed off to the target
// thread directly without unlocking it.
pub const TOKEN_HANDOFF: UnparkToken = UnparkToken(1);

const LOCKED_BIT: U8 = 1;
const PARKED_BIT: U8 = 2;

pub struct RawMutex {
    state: AtomicU8,
}

impl RawMutex {
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new() -> RawMutex {
        RawMutex { state: AtomicU8::new(0) }
    }
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new() -> RawMutex {
        RawMutex { state: AtomicU8::new(0) }
    }

    #[inline]
    pub fn lock(&self) {
        if self.state
            .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.lock_slow();
    }

    #[inline]
    pub fn try_lock(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & LOCKED_BIT != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state | LOCKED_BIT,
                                                   Ordering::Acquire,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    pub fn unlock(&self) {
        if self.state
            .compare_exchange_weak(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_slow(false);
    }

    #[inline]
    pub fn unlock_fair(&self) {
        if self.state
            .compare_exchange_weak(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_slow(true);
    }

    // Used by Condvar when requeuing threads to us, must be called while
    // holding the queue lock.
    #[inline]
    pub fn mark_parked_if_locked(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & LOCKED_BIT == 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state | PARKED_BIT,
                                                   Ordering::Relaxed,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    // Used by Condvar when requeuing threads to us, must be called while
    // holding the queue lock.
    #[inline]
    pub fn mark_parked(&self) {
        self.state.fetch_or(PARKED_BIT, Ordering::Relaxed);
    }

    #[cold]
    #[inline(never)]
    fn lock_slow(&self) {
        let mut spinwait = SpinWait::new();
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if it isn't locked, even if there is a queue on it
            if state & LOCKED_BIT == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state | LOCKED_BIT,
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there is no queue, try spinning a few times
            if state & PARKED_BIT == 0 && spinwait.spin() {
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = || self.state.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
                let before_sleep = || {};
                let timed_out = |_, _| unreachable!();
                if parking_lot_core::park(addr, validate, before_sleep, timed_out, None) ==
                   Some(TOKEN_HANDOFF) {
                    // The thread that unparked us passed the lock on to us
                    // directly without unlocking it.
                    return;
                }
            }

            // Loop back and try locking again
            spinwait.reset();
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_slow(&self, force_fair: bool) {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Unlock directly if there are no parked threads
            if state & PARKED_BIT == 0 {
                match self.state
                    .compare_exchange_weak(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // Unpark one thread and leave the parked bit set if there might
            // still be parked threads on this address.
            unsafe {
                let addr = self as *const _ as usize;
                let callback = |result: UnparkResult| {
                    // If we are using a fair unlock then we should keep the
                    // mutex locked and hand it off to the unparked thread.
                    if result.unparked_thread && (force_fair || result.be_fair) {
                        // Clear the parked bit if there are no more parked
                        // threads.
                        if !result.have_more_threads {
                            self.state.store(LOCKED_BIT, Ordering::Relaxed);
                        }
                        return TOKEN_HANDOFF;
                    }

                    // Clear the locked bit, and the parked bit as well if there
                    // are no more parked threads.
                    if result.have_more_threads {
                        self.state.store(PARKED_BIT, Ordering::Release);
                    } else {
                        self.state.store(0, Ordering::Release);
                    }
                    TOKEN_NORMAL
                };
                parking_lot_core::unpark_one(addr, callback);
            }
            break;
        }
    }
}
<commit_msg>Simplify the mutex unlocking logic<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicU8, Ordering};
#[cfg(feature = "nightly")]
type U8 = u8;
#[cfg(not(feature = "nightly"))]
use stable::{AtomicU8, Ordering};
#[cfg(not(feature = "nightly"))]
type U8 = usize;
use parking_lot_core::{self, UnparkResult, SpinWait, UnparkToken};

// UnparkToken used to indicate that that the target thread should attempt to
// lock the mutex again as soon as it is unparked.
pub const TOKEN_NORMAL: UnparkToken = UnparkToken(0);

// UnparkToken used to indicate that the mutex is being handed off to the target
// thread directly without unlocking it.
pub const TOKEN_HANDOFF: UnparkToken = UnparkToken(1);

const LOCKED_BIT: U8 = 1;
const PARKED_BIT: U8 = 2;

pub struct RawMutex {
    state: AtomicU8,
}

impl RawMutex {
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new() -> RawMutex {
        RawMutex { state: AtomicU8::new(0) }
    }
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new() -> RawMutex {
        RawMutex { state: AtomicU8::new(0) }
    }

    #[inline]
    pub fn lock(&self) {
        if self.state
            .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.lock_slow();
    }

    #[inline]
    pub fn try_lock(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & LOCKED_BIT != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state | LOCKED_BIT,
                                                   Ordering::Acquire,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    pub fn unlock(&self) {
        if self.state
            .compare_exchange_weak(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_slow(false);
    }

    #[inline]
    pub fn unlock_fair(&self) {
        if self.state
            .compare_exchange_weak(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_slow(true);
    }

    // Used by Condvar when requeuing threads to us, must be called while
    // holding the queue lock.
    #[inline]
    pub fn mark_parked_if_locked(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & LOCKED_BIT == 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state | PARKED_BIT,
                                                   Ordering::Relaxed,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    // Used by Condvar when requeuing threads to us, must be called while
    // holding the queue lock.
    #[inline]
    pub fn mark_parked(&self) {
        self.state.fetch_or(PARKED_BIT, Ordering::Relaxed);
    }

    #[cold]
    #[inline(never)]
    fn lock_slow(&self) {
        let mut spinwait = SpinWait::new();
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if it isn't locked, even if there is a queue on it
            if state & LOCKED_BIT == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state | LOCKED_BIT,
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there is no queue, try spinning a few times
            if state & PARKED_BIT == 0 && spinwait.spin() {
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = || self.state.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
                let before_sleep = || {};
                let timed_out = |_, _| unreachable!();
                if parking_lot_core::park(addr, validate, before_sleep, timed_out, None) ==
                   Some(TOKEN_HANDOFF) {
                    // The thread that unparked us passed the lock on to us
                    // directly without unlocking it.
                    return;
                }
            }

            // Loop back and try locking again
            spinwait.reset();
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_slow(&self, force_fair: bool) {
        // Unlock directly if there are no parked threads
        if self.state.compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed).is_ok() {
            return;
        }

        // Unpark one thread and leave the parked bit set if there might
        // still be parked threads on this address.
        unsafe {
            let addr = self as *const _ as usize;
            let callback = |result: UnparkResult| {
                // If we are using a fair unlock then we should keep the
                // mutex locked and hand it off to the unparked thread.
                if result.unparked_thread && (force_fair || result.be_fair) {
                    // Clear the parked bit if there are no more parked
                    // threads.
                    if !result.have_more_threads {
                        self.state.store(LOCKED_BIT, Ordering::Relaxed);
                    }
                    return TOKEN_HANDOFF;
                }

                // Clear the locked bit, and the parked bit as well if there
                // are no more parked threads.
                if result.have_more_threads {
                    self.state.store(PARKED_BIT, Ordering::Release);
                } else {
                    self.state.store(0, Ordering::Release);
                }
                TOKEN_NORMAL
            };
            parking_lot_core::unpark_one(addr, callback);
        }
    }
}
<|endoftext|>


<commit_before>use actix_web::{http::StatusCode, server};
use env_logger;
use failure::{Error, Fail};
use potboiler;
use potboiler_common::{pg, server_id, ServerThread};
use reqwest::{Client, header};
use serde_json::json;
use serial_test_derive::serial;
use std::{str, env};
use regex::Regex;

#[derive(Debug, Fail)]
enum IntegrationError {
    #[fail(display = "IoError")]
    IoError {
        #[cause]
        cause: std::io::Error,
    },
}

fn boot_potboiler() -> Result<ServerThread, Error> {
    let _ = env_logger::try_init();
    let pool = potboiler::db_setup()?;
    let app_state = potboiler::AppState::new(pool, server_id::test()).unwrap();
    return ServerThread::new({
        move || server::new(move || potboiler::app_router(app_state.clone()).unwrap()).bind("0.0.0.0:8000")
    })
    .map_err(|e| IntegrationError::IoError { cause: e }.into());
}

fn test_setup() -> Result<(ServerThread, ServerThread), Error> {
    let _ = env_logger::try_init();
    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = pg::get_pool(db_url).unwrap();
    pool.wipe_db()?;
    let pb_server = boot_potboiler()?;
    env::set_var("SERVER_URL", "http://localhost:8000/log");
    env::set_var("PORT", "8001");
    let app_state = pigtail::AppState::new(pool)?;
    let pigtail_server = ServerThread::new({
        move || server::new(move || pigtail::app_router(app_state.clone()).unwrap()).bind("0.0.0.0:8001")
    })?;
    pigtail::register();
    return Ok((pb_server, pigtail_server));
}

#[test]
#[serial]
fn test_create_queue() {
    let (_pb_server, _pigtail_server) = test_setup().unwrap();
    let client = Client::new();
    let response = client
        .post("http://localhost:8001/create")
        .json(&json!({"name":"foo", "timeout_ms": 1000}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
}

#[test]
#[serial]
fn test_add_entry() {
    let (_pb_server, _pigtail_server) = test_setup().unwrap();
    let client = Client::new();
    let mut response = client
        .post("http://localhost:8001/create")
        .json(&json!({"name":"foo", "timeout_ms": 1000}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
    response = client
        .post("http://localhost:8001/queue/foo")
        .json(&json!({"task_name":"hello_world", "info":{"foo":"bar"}}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
    let re = Regex::new(r"/queue/foo/([a-z0-9-]+)").unwrap();
    let location = format!("{:?}", response.headers()[header::LOCATION]);
    assert!(re.is_match(&location), location);
}<commit_msg>Fix pigtail formatting<commit_after>use actix_web::{http::StatusCode, server};
use env_logger;
use failure::{Error, Fail};
use potboiler;
use potboiler_common::{pg, server_id, ServerThread};
use regex::Regex;
use reqwest::{header, Client};
use serde_json::json;
use serial_test_derive::serial;
use std::{env, str};

#[derive(Debug, Fail)]
enum IntegrationError {
    #[fail(display = "IoError")]
    IoError {
        #[cause]
        cause: std::io::Error,
    },
}

fn boot_potboiler() -> Result<ServerThread, Error> {
    let _ = env_logger::try_init();
    let pool = potboiler::db_setup()?;
    let app_state = potboiler::AppState::new(pool, server_id::test()).unwrap();
    return ServerThread::new({
        move || server::new(move || potboiler::app_router(app_state.clone()).unwrap()).bind("0.0.0.0:8000")
    })
    .map_err(|e| IntegrationError::IoError { cause: e }.into());
}

fn test_setup() -> Result<(ServerThread, ServerThread), Error> {
    let _ = env_logger::try_init();
    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = pg::get_pool(db_url).unwrap();
    pool.wipe_db()?;
    let pb_server = boot_potboiler()?;
    env::set_var("SERVER_URL", "http://localhost:8000/log");
    env::set_var("PORT", "8001");
    let app_state = pigtail::AppState::new(pool)?;
    let pigtail_server = ServerThread::new({
        move || server::new(move || pigtail::app_router(app_state.clone()).unwrap()).bind("0.0.0.0:8001")
    })?;
    pigtail::register();
    return Ok((pb_server, pigtail_server));
}

#[test]
#[serial]
fn test_create_queue() {
    let (_pb_server, _pigtail_server) = test_setup().unwrap();
    let client = Client::new();
    let response = client
        .post("http://localhost:8001/create")
        .json(&json!({"name":"foo", "timeout_ms": 1000}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
}

#[test]
#[serial]
fn test_add_entry() {
    let (_pb_server, _pigtail_server) = test_setup().unwrap();
    let client = Client::new();
    let mut response = client
        .post("http://localhost:8001/create")
        .json(&json!({"name":"foo", "timeout_ms": 1000}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
    response = client
        .post("http://localhost:8001/queue/foo")
        .json(&json!({"task_name":"hello_world", "info":{"foo":"bar"}}))
        .send()
        .unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);
    let re = Regex::new(r"/queue/foo/([a-z0-9-]+)").unwrap();
    let location = format!("{:?}", response.headers()[header::LOCATION]);
    assert!(re.is_match(&location), location);
}
<|endoftext|>


<commit_before>
use std::io;
use std::io::prelude::*;
use job::jobs;
use agent::client;
use repl::readline;

pub fn start() {
    //let mut stdout = io::stdout();
    loop {

        //write!(&mut stdout, "builr> ");
        //stdout.flush();

        //let input = &mut String::new();
        //match io::stdin().read_line(input) {
        match readline::readline(">") {
            Ok(input) => {
                let input = input.replace("\n", "");
                if input.len() > 0 {
                    println!("{:?}", input);

                    if "jobs" == input {
                        jobs::list();
                    }
                    else if "ping" == input {
                        client::ping(4);
                    }
                }
            },
            Err(e) => {
                panic!("{}", e);
            }
        }

    }
}

<commit_msg>make use of external readline dependency<commit_after>extern crate readline;

use std::io;
use std::io::prelude::*;
use job::jobs;
use agent::client;

pub fn start() {
    //let mut stdout = io::stdout();
    loop {

        //write!(&mut stdout, "builr> ");
        //stdout.flush();

        //let input = &mut String::new();
        //match io::stdin().read_line(input) {
        match readline::readline("> ") {
            Ok(input) => {
                let input = input.replace("\n", "");
                if input.len() > 0 {
                    readline::add_history(input.as_ref());
                    println!("{:?}", input);

                    if "jobs" == input {
                        jobs::list();
                    }
                    else if "ping" == input {
                        client::ping(4);
                    }
                }
            },
            Err(e) => {
                panic!("{}", e);
            }
        }

    }
}

<|endoftext|>


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

use std::io;
use std::io::{Read, Write};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

/// The header of a message sent to FSUIPC module via IPC
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq)]
pub enum MsgHeader {
    /// Read state data message header
    /// Read `len` bytes from given offset and prepar to store `data` in `target`.
    ReadStateData {
        offset: u16,
        len: usize,
        target: *mut u8,
    },
    /// Write state data message header
    /// Write `len` bytes from given `source` to given offset.
    WriteStateData {
        offset: u16,
        len: usize,
    },
    TerminationMark
}

pub trait MsgRead : Read {
    /// Read a IPC message header from the given `Read` object.
    /// It returns the read message header and the number of bytes processed.
    fn read_header(&mut self) -> io::Result<(MsgHeader, usize)> {
        match try!(self.read_u32::<LittleEndian>()) {
            FS6IPC_READSTATEDATA_ID => {
                let offset = try!(self.read_u32::<LittleEndian>()) as u16;
                let len = try!(self.read_u32::<LittleEndian>()) as usize;
                let target = try!(self.read_u32::<LittleEndian>()) as *mut u8;
                Ok((MsgHeader::ReadStateData {
                    offset: offset,
                    len: len,
                    target: target,
                }, 16))
            },
            FS6IPC_WRITESTATEDATA_ID => {
                let offset = try!(self.read_u32::<LittleEndian>()) as u16;
                let len = try!(self.read_u32::<LittleEndian>()) as usize;
                Ok((MsgHeader::WriteStateData {
                    offset: offset,
                    len: len,
                }, 12))
            },
            FS6IPC_TERMINATIONMARK_ID => return Ok((MsgHeader::TerminationMark, 4)),
            unexpected => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("unexpected double word 0x{} while reading IPC message header",
                    unexpected))),
        }
    }

    fn read_body<W: Write>(&mut self, header: &MsgHeader, output: &mut W) -> io::Result<usize> {
        match header {
            &MsgHeader::ReadStateData { offset: _, len, target: _ } => {
                for _ in 0..len { try!(output.write_u8(try!(self.read_u8()))); }
                Ok(len)
            },
            &MsgHeader::WriteStateData { offset: _, len } => {
                for _ in 0..len { try!(output.write_u8(try!(self.read_u8()))); }
                Ok(len)
            },
            &MsgHeader::TerminationMark => Ok(0),
        }
    }
}

impl<R: Read + ?Sized> MsgRead for R {}

pub trait MsgWrite : Write {
    /// Write a IPC message header into the given `Write` object.
    fn write_header(&mut self, msg: &MsgHeader) -> io::Result<usize> {
        match msg {
            &MsgHeader::ReadStateData { offset, len, target } => {
                try!(self.write_u32::<LittleEndian>(FS6IPC_READSTATEDATA_ID));
                try!(self.write_u32::<LittleEndian>(offset as u32));
                try!(self.write_u32::<LittleEndian>(len as u32));
                try!(self.write_u32::<LittleEndian>(target as u32));
                Ok(16)
            },
            &MsgHeader::WriteStateData { offset, len } => {
                try!(self.write_u32::<LittleEndian>(FS6IPC_WRITESTATEDATA_ID));
                try!(self.write_u32::<LittleEndian>(offset as u32));
                try!(self.write_u32::<LittleEndian>(len as u32));
                Ok(12)
            },
            &MsgHeader::TerminationMark => {
                try!(self.write_u32::<LittleEndian>(FS6IPC_TERMINATIONMARK_ID));
                Ok(4)
            },
        }
    }

    fn write_body<R: Read>(&mut self, header: &MsgHeader, input: &mut R) -> io::Result<usize> {
        match header {
            &MsgHeader::ReadStateData { offset: _, len, target: _ } => {
                for _ in 0..len { try!(self.write_u8(try!(input.read_u8()))); }
                Ok(len)
            },
            &MsgHeader::WriteStateData { offset: _, len } => {
                for _ in 0..len { try!(self.write_u8(try!(input.read_u8()))); }
                Ok(len)
            },
            &MsgHeader::TerminationMark => Ok(0),
        }
    }
}

impl<W: Write + ?Sized> MsgWrite for W {}

const FS6IPC_TERMINATIONMARK_ID: u32 = 0;
const FS6IPC_READSTATEDATA_ID: u32 = 1;
const FS6IPC_WRITESTATEDATA_ID: u32 = 2;

#[cfg(test)]
mod test {

    use std::io::{Cursor, ErrorKind};

    use byteorder::{LittleEndian, ReadBytesExt};

    use super::*;

    #[test]
    fn should_read_rsd_header() {
        let mut buff: &[u8] = &[
            0x01, 0x00, 0x00, 0x00,
            0x00, 0x10, 0x00, 0x00,
            0x04, 0x00, 0x00, 0x00,
            0x00, 0x20, 0x00, 0x00,
        ];
        let expected = MsgHeader::ReadStateData {
            offset: 0x1000,
            len: 4,
            target: 0x2000 as *mut u8,
        };
        assert_eq!(buff.read_header().unwrap(), (expected, 16));
    }

    #[test]
    fn should_read_rsd_body() {
        let mut buff: &[u8] = &[ 0x01, 0x02, 0x03, 0x04 ];
        let header = MsgHeader::ReadStateData {
            offset: 0x1000,
            len: 4,
            target: 0x2000 as *mut u8,
        };
        let mut data = Vec::new();
        assert_eq!(buff.read_body(&header, &mut data).unwrap(), 4);
        assert_eq!(data[0], 1);
        assert_eq!(data[1], 2);
        assert_eq!(data[2], 3);
        assert_eq!(data[3], 4);
    }

    #[test]
    fn should_read_wsd() {
        let mut buff: &[u8] = &[
            0x02, 0x00, 0x00, 0x00,
            0x00, 0x10, 0x00, 0x00,
            0x04, 0x00, 0x00, 0x00,
        ];
        let expected = MsgHeader::WriteStateData {
            offset: 0x1000,
            len: 4,
        };
        assert_eq!(buff.read_header().unwrap(), (expected, 12));
    }

    #[test]
    fn should_read_wsd_body() {
        let mut buff: &[u8] = &[ 0x01, 0x02, 0x03, 0x04 ];
        let header = MsgHeader::WriteStateData {
            offset: 0x1000,
            len: 4,
        };
        let mut data = Vec::new();
        assert_eq!(buff.read_body(&header, &mut data).unwrap(), 4);
        assert_eq!(data[0], 1);
        assert_eq!(data[1], 2);
        assert_eq!(data[2], 3);
        assert_eq!(data[3], 4);
    }

    #[test]
    fn should_read_tm() {
        let mut buff: &[u8] = &[0x00, 0x00, 0x00, 0x00];
        assert_eq!(buff.read_header().unwrap(), ( MsgHeader::TerminationMark, 4));
    }

    #[test]
    fn should_read_tm_body() {
        let mut buff: &[u8] = &[ 0x01, 0x02, 0x03, 0x04 ];
        let mut data = Vec::new();
        assert_eq!(buff.read_body(&MsgHeader::TerminationMark, &mut data).unwrap(), 0);
        assert_eq!(data.len(), 0);
    }

    #[test]
    fn should_fail_to_read_from_invalid_stream() {
        let mut buff: &[u8] = &[0x01, 0x02, 0x03, 0x04];
        let expected_error = ErrorKind::InvalidInput;
        let actual_error = buff.read_header().err().unwrap().kind();
        assert_eq!(actual_error, expected_error);
    }

    #[test]
    fn should_write_rsd() {
        let mut buff = Cursor::new(Vec::new());
        let msg = MsgHeader::ReadStateData {
            offset: 0x1000,
            len: 4,
            target: 0x2000 as *mut u8,
        };
        assert_eq!(buff.write_header(&msg).unwrap(), 16);
        buff.set_position(0);
        assert_eq!(buff.get_ref().len(), 16);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 1);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x1000);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 4);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x2000);
    }

    #[test]
    fn should_write_rsd_body() {
        let mut buff = Vec::new();
        let mut input = Cursor::new(vec![ 0x01u8, 0x02, 0x03, 0x04 ]);
        let msg = MsgHeader::ReadStateData {
            offset: 0x1000,
            len: 4,
            target: 0x2000 as *mut u8,
        };

        assert_eq!(buff.write_body(&msg, &mut input).unwrap(), 4);
        assert_eq!(buff[0], 1);
        assert_eq!(buff[1], 2);
        assert_eq!(buff[2], 3);
        assert_eq!(buff[3], 4);
    }

    #[test]
    fn should_write_wsd() {
        let mut buff = Cursor::new(Vec::new());
        let msg = MsgHeader::WriteStateData {
            offset: 0x1000,
            len: 4,
        };
        assert_eq!(buff.write_header(&msg).unwrap(), 12);
        buff.set_position(0);
        assert_eq!(buff.get_ref().len(), 12);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 2);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x1000);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 4);
    }

    #[test]
    fn should_write_wsd_body() {
        let mut buff = Vec::new();
        let mut input = Cursor::new(vec![ 0x01u8, 0x02, 0x03, 0x04 ]);
        let msg = MsgHeader::WriteStateData {
            offset: 0x1000,
            len: 4,
        };

        assert_eq!(buff.write_body(&msg, &mut input).unwrap(), 4);
        assert_eq!(buff[0], 1);
        assert_eq!(buff[1], 2);
        assert_eq!(buff[2], 3);
        assert_eq!(buff[3], 4);
    }

    #[test]
    fn should_write_tm() {
        let mut buff = Cursor::new(Vec::new());
        assert_eq!(buff.write_header(&MsgHeader::TerminationMark).unwrap(),4);
        buff.set_position(0);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0);
    }

    #[test]
    fn should_write_tm_body() {
        let mut buff = Vec::new();
        let mut input = Cursor::new(vec![ 0x01u8, 0x02, 0x03, 0x04 ]);
        assert_eq!(buff.write_body(&MsgHeader::TerminationMark, &mut input).unwrap(), 0);
        assert_eq!(buff.len(), 0);
    }
}
<commit_msg>Add methods to `MsgWrite` to write full messages<commit_after>
//
// FSUIPC library
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io;
use std::io::{Read, Write};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use super::raw::RawBytes;

/// The header of a message sent to FSUIPC module via IPC
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq)]
pub enum MsgHeader {
    /// Read state data message header
    /// Read `len` bytes from given offset and prepar to store `data` in `target`.
    ReadStateData {
        offset: u16,
        len: usize,
        target: *mut u8,
    },
    /// Write state data message header
    /// Write `len` bytes from given `source` to given offset.
    WriteStateData {
        offset: u16,
        len: usize,
    },
    TerminationMark
}

pub trait MsgRead : Read {
    /// Read a IPC message header from the given `Read` object.
    /// It returns the read message header and the number of bytes processed.
    fn read_header(&mut self) -> io::Result<(MsgHeader, usize)> {
        match try!(self.read_u32::<LittleEndian>()) {
            FS6IPC_READSTATEDATA_ID => {
                let offset = try!(self.read_u32::<LittleEndian>()) as u16;
                let len = try!(self.read_u32::<LittleEndian>()) as usize;
                let target = try!(self.read_u32::<LittleEndian>()) as *mut u8;
                Ok((MsgHeader::ReadStateData {
                    offset: offset,
                    len: len,
                    target: target,
                }, 16))
            },
            FS6IPC_WRITESTATEDATA_ID => {
                let offset = try!(self.read_u32::<LittleEndian>()) as u16;
                let len = try!(self.read_u32::<LittleEndian>()) as usize;
                Ok((MsgHeader::WriteStateData {
                    offset: offset,
                    len: len,
                }, 12))
            },
            FS6IPC_TERMINATIONMARK_ID => return Ok((MsgHeader::TerminationMark, 4)),
            unexpected => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("unexpected double word 0x{} while reading IPC message header",
                    unexpected))),
        }
    }

    fn read_body<W: Write>(&mut self, header: &MsgHeader, output: &mut W) -> io::Result<usize> {
        match header {
            &MsgHeader::ReadStateData { offset: _, len, target: _ } => {
                for _ in 0..len { try!(output.write_u8(try!(self.read_u8()))); }
                Ok(len)
            },
            &MsgHeader::WriteStateData { offset: _, len } => {
                for _ in 0..len { try!(output.write_u8(try!(self.read_u8()))); }
                Ok(len)
            },
            &MsgHeader::TerminationMark => Ok(0),
        }
    }
}

impl<R: Read + ?Sized> MsgRead for R {}

pub trait MsgWrite : Write {
    /// Write a IPC message header into the given `Write` object.
    fn write_header(&mut self, msg: &MsgHeader) -> io::Result<usize> {
        match msg {
            &MsgHeader::ReadStateData { offset, len, target } => {
                try!(self.write_u32::<LittleEndian>(FS6IPC_READSTATEDATA_ID));
                try!(self.write_u32::<LittleEndian>(offset as u32));
                try!(self.write_u32::<LittleEndian>(len as u32));
                try!(self.write_u32::<LittleEndian>(target as u32));
                Ok(16)
            },
            &MsgHeader::WriteStateData { offset, len } => {
                try!(self.write_u32::<LittleEndian>(FS6IPC_WRITESTATEDATA_ID));
                try!(self.write_u32::<LittleEndian>(offset as u32));
                try!(self.write_u32::<LittleEndian>(len as u32));
                Ok(12)
            },
            &MsgHeader::TerminationMark => {
                try!(self.write_u32::<LittleEndian>(FS6IPC_TERMINATIONMARK_ID));
                Ok(4)
            },
        }
    }

    fn write_body<R: Read>(&mut self, header: &MsgHeader, input: &mut R) -> io::Result<usize> {
        match header {
            &MsgHeader::ReadStateData { offset: _, len, target: _ } => {
                for _ in 0..len { try!(self.write_u8(try!(input.read_u8()))); }
                Ok(len)
            },
            &MsgHeader::WriteStateData { offset: _, len } => {
                for _ in 0..len { try!(self.write_u8(try!(input.read_u8()))); }
                Ok(len)
            },
            &MsgHeader::TerminationMark => Ok(0),
        }
    }

    fn write_rsd(&mut self, offset: u16, dest: *mut u8, len: usize) -> io::Result<usize> {
        let header = MsgHeader::ReadStateData {
            offset: offset, len: len, target: dest,
        };
        let hdr_bytes = try!(self.write_header(&header));
        let body_bytes = try!(self.write_body(&header, &mut io::repeat(0)));
        Ok(hdr_bytes + body_bytes)
    }

    fn write_wsd(&mut self, offset: u16, src: *const u8, len: usize) -> io::Result<usize> {
        let header = MsgHeader::WriteStateData {
            offset: offset, len: len,
        };
        let hdr_bytes = try!(self.write_header(&header));
        let body_bytes = try!(self.write_body(&header, &mut RawBytes::new(src, len)));
        Ok(hdr_bytes + body_bytes)
    }
}

impl<W: Write + ?Sized> MsgWrite for W {}

const FS6IPC_TERMINATIONMARK_ID: u32 = 0;
const FS6IPC_READSTATEDATA_ID: u32 = 1;
const FS6IPC_WRITESTATEDATA_ID: u32 = 2;

#[cfg(test)]
mod test {

    use std::io::{Cursor, ErrorKind};

    use byteorder::{LittleEndian, ReadBytesExt};

    use super::*;

    #[test]
    fn should_read_rsd_header() {
        let mut buff: &[u8] = &[
            0x01, 0x00, 0x00, 0x00,
            0x00, 0x10, 0x00, 0x00,
            0x04, 0x00, 0x00, 0x00,
            0x00, 0x20, 0x00, 0x00,
        ];
        let expected = MsgHeader::ReadStateData {
            offset: 0x1000,
            len: 4,
            target: 0x2000 as *mut u8,
        };
        assert_eq!(buff.read_header().unwrap(), (expected, 16));
    }

    #[test]
    fn should_read_rsd_body() {
        let mut buff: &[u8] = &[ 0x01, 0x02, 0x03, 0x04 ];
        let header = MsgHeader::ReadStateData {
            offset: 0x1000,
            len: 4,
            target: 0x2000 as *mut u8,
        };
        let mut data = Vec::new();
        assert_eq!(buff.read_body(&header, &mut data).unwrap(), 4);
        assert_eq!(data[0], 1);
        assert_eq!(data[1], 2);
        assert_eq!(data[2], 3);
        assert_eq!(data[3], 4);
    }

    #[test]
    fn should_read_wsd_header() {
        let mut buff: &[u8] = &[
            0x02, 0x00, 0x00, 0x00,
            0x00, 0x10, 0x00, 0x00,
            0x04, 0x00, 0x00, 0x00,
        ];
        let expected = MsgHeader::WriteStateData {
            offset: 0x1000,
            len: 4,
        };
        assert_eq!(buff.read_header().unwrap(), (expected, 12));
    }

    #[test]
    fn should_read_wsd_body() {
        let mut buff: &[u8] = &[ 0x01, 0x02, 0x03, 0x04 ];
        let header = MsgHeader::WriteStateData {
            offset: 0x1000,
            len: 4,
        };
        let mut data = Vec::new();
        assert_eq!(buff.read_body(&header, &mut data).unwrap(), 4);
        assert_eq!(data[0], 1);
        assert_eq!(data[1], 2);
        assert_eq!(data[2], 3);
        assert_eq!(data[3], 4);
    }

    #[test]
    fn should_read_tm_header() {
        let mut buff: &[u8] = &[0x00, 0x00, 0x00, 0x00];
        assert_eq!(buff.read_header().unwrap(), ( MsgHeader::TerminationMark, 4));
    }

    #[test]
    fn should_read_tm_body() {
        let mut buff: &[u8] = &[ 0x01, 0x02, 0x03, 0x04 ];
        let mut data = Vec::new();
        assert_eq!(buff.read_body(&MsgHeader::TerminationMark, &mut data).unwrap(), 0);
        assert_eq!(data.len(), 0);
    }

    #[test]
    fn should_fail_to_read_from_invalid_stream() {
        let mut buff: &[u8] = &[0x01, 0x02, 0x03, 0x04];
        let expected_error = ErrorKind::InvalidInput;
        let actual_error = buff.read_header().err().unwrap().kind();
        assert_eq!(actual_error, expected_error);
    }

    #[test]
    fn should_write_rsd_header() {
        let mut buff = Cursor::new(Vec::new());
        let msg = MsgHeader::ReadStateData {
            offset: 0x1000,
            len: 4,
            target: 0x2000 as *mut u8,
        };
        assert_eq!(buff.write_header(&msg).unwrap(), 16);
        buff.set_position(0);
        assert_eq!(buff.get_ref().len(), 16);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 1);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x1000);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 4);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x2000);
    }

    #[test]
    fn should_write_rsd_body() {
        let mut buff = Vec::new();
        let mut input = Cursor::new(vec![ 0x01u8, 0x02, 0x03, 0x04 ]);
        let msg = MsgHeader::ReadStateData {
            offset: 0x1000,
            len: 4,
            target: 0x2000 as *mut u8,
        };

        assert_eq!(buff.write_body(&msg, &mut input).unwrap(), 4);
        assert_eq!(buff[0], 1);
        assert_eq!(buff[1], 2);
        assert_eq!(buff[2], 3);
        assert_eq!(buff[3], 4);
    }

    #[test]
    fn should_write_rsd() {
        let mut buff = Cursor::new(Vec::new());
        assert_eq!(buff.write_rsd(0x1000, 0x2000 as *mut u8, 4).unwrap(), 20);
        buff.set_position(0);
        assert_eq!(buff.get_ref().len(), 20);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 1);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x1000);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 4);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x2000);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0);
    }

    #[test]
    fn should_write_wsd_header() {
        let mut buff = Cursor::new(Vec::new());
        let msg = MsgHeader::WriteStateData {
            offset: 0x1000,
            len: 4,
        };
        assert_eq!(buff.write_header(&msg).unwrap(), 12);
        buff.set_position(0);
        assert_eq!(buff.get_ref().len(), 12);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 2);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x1000);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 4);
    }

    #[test]
    fn should_write_wsd_body() {
        let mut buff = Vec::new();
        let mut input = Cursor::new(vec![ 0x01u8, 0x02, 0x03, 0x04 ]);
        let msg = MsgHeader::WriteStateData {
            offset: 0x1000,
            len: 4,
        };

        assert_eq!(buff.write_body(&msg, &mut input).unwrap(), 4);
        assert_eq!(buff[0], 1);
        assert_eq!(buff[1], 2);
        assert_eq!(buff[2], 3);
        assert_eq!(buff[3], 4);
    }

    #[test]
    fn should_write_wsd() {
        let mut buff = Cursor::new(Vec::new());
        let data = &0x01020304u32 as *const u32 as *const u8;
        assert_eq!(buff.write_wsd(0x1000, data, 4).unwrap(), 16);
        buff.set_position(0);
        assert_eq!(buff.get_ref().len(), 16);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 2);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x1000);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 4);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0x01020304);
    }

    #[test]
    fn should_write_tm_header() {
        let mut buff = Cursor::new(Vec::new());
        assert_eq!(buff.write_header(&MsgHeader::TerminationMark).unwrap(),4);
        buff.set_position(0);
        assert_eq!(buff.read_u32::<LittleEndian>().unwrap(), 0);
    }

    #[test]
    fn should_write_tm_body() {
        let mut buff = Vec::new();
        let mut input = Cursor::new(vec![ 0x01u8, 0x02, 0x03, 0x04 ]);
        assert_eq!(buff.write_body(&MsgHeader::TerminationMark, &mut input).unwrap(), 0);
        assert_eq!(buff.len(), 0);
    }
}
<|endoftext|>


<commit_before>use utils::{outb, inb};
use stdio;

static mut pos: u8 = 0;
#[no_mangle]
pub unsafe fn _interrupt_handler_kbd() {
    pos += 1;
    outb(0x20, 0x20);
    let key = inb(0x60);
    stdio::putchar(5 + (pos as u16), 6, key);
}
<commit_msg>What is even going on<commit_after>use utils::{outb, inb};
use core::slice;
use core::container::Container;
use stdio;

static NUMS: &'static [u8] = bytes!("01234567890");

static mut pos: u8 = 0;
#[no_mangle]
pub unsafe fn _interrupt_handler_kbd() {
    let keycode = inb(0x60);
    if (keycode == 2 || keycode == 3) {
        stdio::putc(NUMS[2]); // should be '2'. It is
        stdio::putc(65 + keycode); // should be 'C' (keycode = 2). It is.
        stdio::putc(NUMS[keycode]); // should be '2', BUT IT ISN'T
        stdio::putc(124);
    }
    outb(0x20, 0x20);
}
<|endoftext|>


<commit_before>//! User LEDs

use stm32f103xx::{GPIOC, Gpioc, Rcc};

/// All the user LEDs
pub static LEDS: [Led; 1] = [
    Led { i: 13 },
];

/// An LED
pub struct Led {
    i: u8,
}

impl Led {
    /// Turns off the LED
    pub fn off(&self) {
        // NOTE(safe) atomic write
        unsafe { (*GPIOC.get()).bsrr.write(|w| w.bits(1 << (self.i + 16))) }
    }

    /// Turns on the LED
    pub fn on(&self) {
        // NOTE(safe) atomic write
        unsafe { (*GPIOC.get()).bsrr.write(|w| w.bits(1 << self.i)) }
    }
}

/// Initializes all the user LEDs
pub fn init(gpioc: &Gpioc, rcc: &Rcc) {
    // Power up peripherals
    rcc.apb2enr.modify(|_, w| w.iopcen().enabled());

    // Configure pin 13 as output
    gpioc
        .crh
        .modify(
            |_, w| {
                w.mode13()
                    .output()
            },
        );
}
<commit_msg>pin c13 is only supposed to go to 2Mhz, was set to 10<commit_after>//! User LEDs

use stm32f103xx::{GPIOC, Gpioc, Rcc};

/// All the user LEDs
pub static LEDS: [Led; 1] = [
    Led { i: 13 },
];

/// An LED
pub struct Led {
    i: u8,
}

impl Led {
    /// Turns off the LED
    pub fn off(&self) {
        // NOTE(safe) atomic write
        unsafe { (*GPIOC.get()).bsrr.write(|w| w.bits(1 << (self.i + 16))) }
    }

    /// Turns on the LED
    pub fn on(&self) {
        // NOTE(safe) atomic write
        unsafe { (*GPIOC.get()).bsrr.write(|w| w.bits(1 << self.i)) }
    }
}

/// Initializes all the user LEDs
pub fn init(gpioc: &Gpioc, rcc: &Rcc) {
    // Power up peripherals
    rcc.apb2enr.modify(|_, w| w.iopcen().enabled());

    // Configure pin 13 as output
    gpioc
        .crh
        .modify(
            |_, w| {
                w.mode13()
                    .output2()
            },
        );
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::io::{Io, Pio, ReadOnly, WriteOnly};

use graphics::display::VBEMODEINFO;

use fs::KScheme;

use drivers::kb_layouts::layouts;

pub struct Ps2Keyboard<'a> {
    bus: &'a mut Ps2
}

impl<'a> Ps2Keyboard<'a> {
    //TODO: Use result
    fn cmd(&mut self, command: u8) -> u8 {
        self.bus.wait_write();
        self.bus.data.write(command);
        self.bus.wait_read();
        self.bus.data.read()
    }
}

pub struct Ps2Mouse<'a> {
    bus: &'a mut Ps2
}

impl<'a> Ps2Mouse<'a> {
    //TODO: Use result
    fn cmd(&mut self, command: u8) -> u8 {
        self.bus.write(0xD4, command);
        self.bus.wait_read();
        self.bus.data.read()
    }
}

/// PS2
pub struct Ps2 {
    /// The data register
    data: Pio<u8>,
    /// The status register
    sts: ReadOnly<u8, Pio<u8>>,
    /// The command register
    cmd: WriteOnly<u8, Pio<u8>>,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// AltGr?
    altgr: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: i32,
    /// Mouse point y
    mouse_y: i32,
    /// Layout for keyboard
    /// Default: English
    layout: layouts::Layout,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio::new(0x60),
            sts: ReadOnly::new(Pio::new(0x64)),
            cmd: WriteOnly::new(Pio::new(0x64)),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            altgr: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: layouts::Layout::English,
        };

        module.init();

        module
    }

    fn wait_read(&self) {
        while self.sts.read() & 1 == 0 {}
    }

    fn wait_write(&self) {
        while self.sts.read() & 2 == 2 {}
    }

    fn cmd(&mut self, command: u8) {
        self.wait_write();
        self.cmd.write(command);
    }

    fn read(&mut self, command: u8) -> u8 {
        self.cmd(command);
        self.wait_read();
        self.data.read()
    }

    fn write(&mut self, command: u8, data: u8) {
        self.cmd(command);
        self.wait_write();
        self.data.write(data);
    }

    fn keyboard<'a>(&'a mut self) -> Ps2Keyboard<'a> {
        Ps2Keyboard {
            bus: self
        }
    }

    fn mouse<'a>(&'a mut self) -> Ps2Mouse<'a> {
        Ps2Mouse {
            bus: self
        }
    }

    fn init(&mut self) {
        while (self.sts.read() & 0x1) == 1 {
            self.data.read();
        }

        // No interrupts, system flag set, clocks enabled, translation disabled
        self.write(0x60, 0b00000100);

        // Enable First Port
        self.cmd(0xAE);
        {
            let mut keyboard = self.keyboard();

            // Reset
            keyboard.cmd(0xFF);

            // Set defaults
            keyboard.cmd(0xF6);

            // Set LEDS
            keyboard.cmd(0xED);
            keyboard.cmd(0);

            // Set Scancode Map:
            keyboard.cmd(0xF0);
            keyboard.cmd(1);

            // Enable Streaming
            keyboard.cmd(0xF4);
        }

        // Enable Second Port
        self.cmd(0xA8);
        {
            let mut mouse = self.mouse();

            // Reset
            mouse.cmd(0xFF);

            // Set defaults
            mouse.cmd(0xF6);

            // Enable Streaming
            mouse.cmd(0xF4);
        }

        // Both interrupts, system flag set, clocks enabled, translation disabled
        self.write(0x60, 0b00000111);
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let mut scancode = self.data.read();

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        } else if scancode == 0xE0 {
            let scancode_byte_2 = self.data.read();
            if scancode_byte_2 == 0x38 {
                self.altgr = true;
            } else if scancode_byte_2 == 0xB8 {
                self.altgr = false;
            } else {
                scancode = scancode_byte_2;
            }
        }

        let shift = self.caps_lock != (self.lshift || self.rshift);

        return Some(KeyEvent {
            character: layouts::char_for_scancode(scancode & 0x7F, shift, self.altgr, &self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = self.data.read();
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = (self.mouse_packet[1] as isize -
                     (((self.mouse_packet[0] as isize) << 4) & 0x100)) as i32;
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = ((((self.mouse_packet[0] as isize) << 3) & 0x100) -
                     self.mouse_packet[2] as isize) as i32;
            } else {
                y = 0;
            }

            if let Some(mode_info) = unsafe { VBEMODEINFO } {
                self.mouse_x = cmp::max(0, cmp::min(mode_info.xresolution as i32, self.mouse_x + x));
                self.mouse_y = cmp::max(0, cmp::min(mode_info.yresolution as i32, self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = match layout {
            0 => layouts::Layout::English,
            1 => layouts::Layout::French,
            2 => layouts::Layout::German,
            _ => layouts::Layout::English,
        }
    }
}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            loop {
                let status = self.sts.read();
                if status & 0x21 == 0x21 {
                    if let Some(mouse_event) = self.mouse_interrupt() {
                        if ::env().console.lock().draw {
                            //Ignore mouse event
                        } else {
                            ::env().events.send(mouse_event.to_event());
                        }
                    }
                } else if status & 0x21 == 1 {
                    if let Some(key_event) = self.keyboard_interrupt() {
                        if ::env().console.lock().draw {
                            ::env().console.lock().event(key_event.to_event());
                        } else {
                            ::env().events.send(key_event.to_event());
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }
}
<commit_msg>Cleanup interrupt handling in ps/2, clear buffer before returning from init<commit_after>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::io::{Io, Pio, ReadOnly, WriteOnly};

use graphics::display::VBEMODEINFO;

use fs::KScheme;

use drivers::kb_layouts::layouts;

pub struct Ps2Keyboard<'a> {
    bus: &'a mut Ps2
}

impl<'a> Ps2Keyboard<'a> {
    //TODO: Use result
    fn cmd(&mut self, command: u8) -> u8 {
        self.bus.wait_write();
        self.bus.data.write(command);
        self.bus.wait_read();
        self.bus.data.read()
    }
}

pub struct Ps2Mouse<'a> {
    bus: &'a mut Ps2
}

impl<'a> Ps2Mouse<'a> {
    //TODO: Use result
    fn cmd(&mut self, command: u8) -> u8 {
        self.bus.write(0xD4, command);
        self.bus.wait_read();
        self.bus.data.read()
    }
}

/// PS2
pub struct Ps2 {
    /// The data register
    data: Pio<u8>,
    /// The status register
    sts: ReadOnly<u8, Pio<u8>>,
    /// The command register
    cmd: WriteOnly<u8, Pio<u8>>,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// AltGr?
    altgr: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: i32,
    /// Mouse point y
    mouse_y: i32,
    /// Layout for keyboard
    /// Default: English
    layout: layouts::Layout,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio::new(0x60),
            sts: ReadOnly::new(Pio::new(0x64)),
            cmd: WriteOnly::new(Pio::new(0x64)),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            altgr: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: layouts::Layout::English,
        };

        module.init();

        module
    }

    fn wait_read(&self) {
        while self.sts.read() & 1 == 0 {}
    }

    fn wait_write(&self) {
        while self.sts.read() & 2 == 2 {}
    }

    fn cmd(&mut self, command: u8) {
        self.wait_write();
        self.cmd.write(command);
    }

    fn read(&mut self, command: u8) -> u8 {
        self.cmd(command);
        self.wait_read();
        self.data.read()
    }

    fn write(&mut self, command: u8, data: u8) {
        self.cmd(command);
        self.wait_write();
        self.data.write(data);
    }

    fn keyboard<'a>(&'a mut self) -> Ps2Keyboard<'a> {
        Ps2Keyboard {
            bus: self
        }
    }

    fn mouse<'a>(&'a mut self) -> Ps2Mouse<'a> {
        Ps2Mouse {
            bus: self
        }
    }

    fn init(&mut self) {
        while (self.sts.read() & 0x1) == 1 {
            self.data.read();
        }

        // No interrupts, system flag set, clocks enabled, translation disabled
        self.write(0x60, 0b00000100);

        // Enable First Port
        self.cmd(0xAE);
        {
            let mut keyboard = self.keyboard();

            // Reset
            keyboard.cmd(0xFF);

            // Set defaults
            keyboard.cmd(0xF6);

            // Set LEDS
            keyboard.cmd(0xED);
            keyboard.cmd(0);

            // Set Scancode Map:
            keyboard.cmd(0xF0);
            keyboard.cmd(1);

            // Enable Streaming
            keyboard.cmd(0xF4);
        }

        // Enable Second Port
        self.cmd(0xA8);
        {
            let mut mouse = self.mouse();

            // Reset
            mouse.cmd(0xFF);

            // Set defaults
            mouse.cmd(0xF6);

            // Enable Streaming
            mouse.cmd(0xF4);
        }

        // Both interrupts, system flag set, clocks enabled, translation disabled
        self.write(0x60, 0b00000111);

        while (self.sts.read() & 0x1) == 1 {
            debugln!("Extra: {:X}", self.data.read());
        }
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self, mut scancode: u8) -> Option<KeyEvent> {
        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        } else if scancode == 0xE0 {
            let scancode_byte_2 = self.data.read();
            if scancode_byte_2 == 0x38 {
                self.altgr = true;
            } else if scancode_byte_2 == 0xB8 {
                self.altgr = false;
            } else {
                scancode = scancode_byte_2;
            }
        }

        let shift = self.caps_lock != (self.lshift || self.rshift);

        return Some(KeyEvent {
            character: layouts::char_for_scancode(scancode & 0x7F, shift, self.altgr, &self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self, byte: u8) -> Option<MouseEvent> {
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = (self.mouse_packet[1] as isize -
                     (((self.mouse_packet[0] as isize) << 4) & 0x100)) as i32;
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = ((((self.mouse_packet[0] as isize) << 3) & 0x100) -
                     self.mouse_packet[2] as isize) as i32;
            } else {
                y = 0;
            }

            if let Some(mode_info) = unsafe { VBEMODEINFO } {
                self.mouse_x = cmp::max(0, cmp::min(mode_info.xresolution as i32, self.mouse_x + x));
                self.mouse_y = cmp::max(0, cmp::min(mode_info.yresolution as i32, self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = match layout {
            0 => layouts::Layout::English,
            1 => layouts::Layout::French,
            2 => layouts::Layout::German,
            _ => layouts::Layout::English,
        }
    }
}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0xC {
            let data = self.data.read();
            if let Some(mouse_event) = self.mouse_interrupt(data) {
                if ::env().console.lock().draw {
                    //Ignore mouse event
                } else {
                    ::env().events.send(mouse_event.to_event());
                }
            }
        } else if irq == 0x1 {
            let data = self.data.read();
            if let Some(key_event) = self.keyboard_interrupt(data) {
                if ::env().console.lock().draw {
                    ::env().console.lock().event(key_event.to_event());
                } else {
                    ::env().events.send(key_event.to_event());
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! GPIO wired to the LEDs of the Beaglebone

use just;

/// Root folder (modulo number) that contains the files that control the GPIO
static ROOT: &'static str = "/sys/class/leds/beaglebone:green:usr";

/// LED identifier
pub enum Number {
    /// First LED, by default is in heartbeat mode
    Zero = 0,
    /// Second LED, unused and powered off by default
    One = 1,
    /// Third LED, tracks CPU usage by default
    Three = 3,
    /// Fourth LED, tracks disk I/O by default
    Two = 2,
}

/// LED trigger modes
pub enum Trigger {
    Heartbeat,
    NoTrigger,
    Timer,
}

impl Trigger {
    fn from_str(s: &str) -> Option<Trigger> {
        match s {
            "heartbeat" => Some(Heartbeat),
            "none" => Some(NoTrigger),
            "timer" => Some(Timer),
            _ => None,
        }
    }

    fn to_str(&self) -> &'static str {
        match *self {
            Heartbeat => "heartbeat",
            NoTrigger => "none",
            Timer => "timer",
        }
    }
}

/// An LED controller
pub struct Led {
    root: Path,
}

impl Led {
    /// Create access to an LED
    pub fn new(number: Number) -> Led {
        Led {
            root: Path::new(format!("{}{}", ROOT, number as u8)),
        }
    }

    /// Makes the LED blink
    // XXX Not sure about how big can `on_ms` and `off_ms` be
    pub fn blink(&self, on_ms: u16, off_ms: u16) {
        self.set_trigger(Timer);
        just::write(&self.root.join("delay_on"), format!("{}", on_ms)[]);
        just::write(&self.root.join("delay_off"), format!("{}", off_ms)[]);
    }

    /// Changes the brightness of the LED
    // XXX Is `u8` enough?
    pub fn set_brightness(&self, brightness: u8) {
        just::write(&self.root.join("brightness"), format!("{}", brightness)[])
    }

    /// Turns on the LED
    pub fn set_high(&self) {
        self.set_trigger(NoTrigger);
        self.set_brightness(1);
    }

    /// Turns off the LED
    pub fn set_low(&self) {
        self.set_trigger(NoTrigger);
        self.set_brightness(0);
    }

    /// Changes the trigger mode of the LED
    pub fn set_trigger(&self, trigger: Trigger) {
        just::write(&self.root.join("trigger"), trigger.to_str());
    }

    /// Returns the current trigger mode the LED is using
    pub fn trigger(&self) -> Trigger {
        let s = just::read(&self.root.join("trigger"));
        match s[].split('[').skip(1).next().and_then(|s| s.split(']').next()) {
            Some(s) => match Trigger::from_str(s) {
                Some(trigger) => trigger,
                None => fail!("Unknown trigger mode: {}", s),
            },
            None => fail!("Failed to parse: {}", s),
        }
    }
}
<commit_msg>docs(led): add some examples<commit_after>//! GPIO wired to the LEDs of the Beaglebone

use just;

/// Root folder (modulo number) that contains the files that control the GPIO
static ROOT: &'static str = "/sys/class/leds/beaglebone:green:usr";

/// LED identifier
pub enum Number {
    /// First LED, by default is in heartbeat mode
    Zero = 0,
    /// Second LED, unused and powered off by default
    One = 1,
    /// Third LED, tracks CPU usage by default
    Three = 3,
    /// Fourth LED, tracks disk I/O by default
    Two = 2,
}

/// LED trigger modes
pub enum Trigger {
    Heartbeat,
    NoTrigger,
    Timer,
}

impl Trigger {
    fn from_str(s: &str) -> Option<Trigger> {
        match s {
            "heartbeat" => Some(Heartbeat),
            "none" => Some(NoTrigger),
            "timer" => Some(Timer),
            _ => None,
        }
    }

    fn to_str(&self) -> &'static str {
        match *self {
            Heartbeat => "heartbeat",
            NoTrigger => "none",
            Timer => "timer",
        }
    }
}

/// An LED controller
pub struct Led {
    root: Path,
}

impl Led {
    /// Create access to an LED
    pub fn new(number: Number) -> Led {
        Led {
            root: Path::new(format!("{}{}", ROOT, number as u8)),
        }
    }

    /// Makes the LED blink
    ///
    /// # Example
    ///
    /// ``` ignore
    /// use bb::led::{Led, Zero};
    ///
    /// // On for one second, off for half a second
    /// Led::new(Zero).blink(1000, 500);
    /// ```
    // XXX Not sure about how big can `on_ms` and `off_ms` be
    pub fn blink(&self, on_ms: u16, off_ms: u16) {
        self.set_trigger(Timer);
        just::write(&self.root.join("delay_on"), format!("{}", on_ms)[]);
        just::write(&self.root.join("delay_off"), format!("{}", off_ms)[]);
    }

    /// Changes the brightness of the LED
    // XXX Is `u8` enough?
    pub fn set_brightness(&self, brightness: u8) {
        just::write(&self.root.join("brightness"), format!("{}", brightness)[])
    }

    /// Turns on the LED
    pub fn set_high(&self) {
        self.set_trigger(NoTrigger);
        self.set_brightness(1);
    }

    /// Turns off the LED
    pub fn set_low(&self) {
        self.set_trigger(NoTrigger);
        self.set_brightness(0);
    }

    /// Changes the trigger mode of the LED
    ///
    /// # Example
    ///
    /// ``` ignore
    /// use bb::led::{Led, Heartbeat, Zero};
    ///
    /// Led::new(Zero).set_trigger(Heartbeat);
    /// println!("I'm alive!");
    /// ```
    pub fn set_trigger(&self, trigger: Trigger) {
        just::write(&self.root.join("trigger"), trigger.to_str());
    }

    /// Returns the current trigger mode the LED is using
    pub fn trigger(&self) -> Trigger {
        let s = just::read(&self.root.join("trigger"));
        match s[].split('[').skip(1).next().and_then(|s| s.split(']').next()) {
            Some(s) => match Trigger::from_str(s) {
                Some(trigger) => trigger,
                None => fail!("Unknown trigger mode: {}", s),
            },
            None => fail!("Failed to parse: {}", s),
        }
    }
}
<|endoftext|>