<commit_before>//! Implements a pass that goes over the ssa and checks if the ssa is still valid.
//!
//! This is only for verification and to catch potential mistakes.
#![allow(unused_imports, unused_variables)]
use petgraph::EdgeDirection;
use petgraph::graph::{Graph, NodeIndex, EdgeIndex};

use std::collections::HashSet;

use super::cfg_traits::{CFG, CFGMod};
use super::ssa_traits::SSA;
use super::ssastorage::{NodeData,EdgeData};
use super::ssastorage::SSAStorage;

pub trait Verify: SSA {
	fn verify_block(&self, i: &Self::ActionRef);
	fn verify_expr(&self, i: &Self::ValueRef);
}

impl Verify for SSAStorage {
	fn verify_block(&self, block: &NodeIndex) {
		let edge_count = self.edge_count();
		let node_count = self.node_count();
		// Make sure that we have a valid node first.
		assert!(block.index() < node_count);
		let edges = self.edges_of(block);
		// Every BB can have a maximum of 2 Outgoing CFG Edges.
		assert!(edges.len() < 3);

		let mut edgecases = [false; 256];

		for edge in edges.iter() {
			match self.g[*edge] {
				EdgeData::Control(i) => {
					let target = self.target_of(edge);
					assert!(self.g.is_action(target));
					assert!(!self.edgecases[i]);
					self.edgecases[i] = true;
				},
				_ => ()
			}
		}

		for edge in edges.iter() {
			assert!(edge.index() < edge_count);
			match self.g[*edge] {
				EdgeData::Control(i) if i < 2 => {
					// Things to lookout for:
					//  * There must be a minimum of two edges.
					//  * There _must_ be a selector.
					//  * The jump targets must not be the same block.
					assert!(edges.len() == 2);
					let other_edge = match i {
						0 => self.true_edge_of(block),
						1 => self.false_edge_of(block),
						_ => unreachable!(),
					};
					let target_1 = self.target_of(edge);
					let target_2 = self.target_of(&other_edge);
					assert!(target_1 != target_2);
					// No need to test the next edge.
					break;
				},
				EdgeData::Control(2) => {
					// Things to lookout for:
					//  * There can be only one Unconditional Edge.
					//  * There can be no selector.
					//  * Make sure we have not introduced an unconditional jump
					//    which self-loops.
					let target_block = self.target_of(edge);
					assert!(edges.len() == 1);
					assert!(*block != target_block);
				},
				_ => panic!("Found something other than a control edge!"),
			}
		}

		if edges.len() >= 2 {
			assert!(self.selector_of(block).is_none());
		} else {
			assert!(self.selector_of(block).is_some());
		}

		// Make sure that this block is reachable.
		let incoming = self.incoming_edges(block);
		assert!((incoming.len() > 0) || *block == self.start_node());
	}

	fn verify_expr(&self, i: &NodeIndex) {
		let node_count = self.node_count();
		// Make sure we have a valid node first.
		assert!(i.index() < node_count);
		let node_data = &self.g[*i];
		match *node_data {
			NodeData::Op(opcode, v) => {
			},
			_ => panic!("Found something other than an expression!"),
		}
	}
}

pub fn verify<T>(ssa: &T) where T: Verify {
	let blocks = ssa.blocks();
	for block in blocks.iter() {
		// assert the qualities of the block first.
		ssa.verify_block(block);
		// Iterate through each node in the block and assert their properties.
		let exprs = ssa.exprs_in(block);
		for expr in exprs.iter() {
			ssa.verify_expr(expr);
		}
	}
}
<commit_msg>last commit was broken<commit_after>//! Implements a pass that goes over the ssa and checks if the ssa is still valid.
//!
//! This is only for verification and to catch potential mistakes.
#![allow(unused_imports, unused_variables)]
use petgraph::EdgeDirection;
use petgraph::graph::{Graph, NodeIndex, EdgeIndex};

use std::collections::HashSet;

use super::cfg_traits::{CFG, CFGMod};
use super::ssa_traits::SSA;
use super::ssastorage::{NodeData,EdgeData};
use super::ssastorage::SSAStorage;

pub trait Verify: SSA {
	fn verify_block(&self, i: &Self::ActionRef);
	fn verify_expr(&self, i: &Self::ValueRef);
}

impl Verify for SSAStorage {
	fn verify_block(&self, block: &NodeIndex) {
		let edge_count = self.edge_count();
		let node_count = self.node_count();
		// Make sure that we have a valid node first.
		assert!(block.index() < node_count);
		let edges = self.edges_of(block);
		// Every BB can have a maximum of 2 Outgoing CFG Edges.
		assert!(edges.len() < 3);

		let mut edgecases = [false; 256];

		for edge in edges.iter() {
			match self.g[*edge] {
				EdgeData::Control(i) => {
					let target = self.target_of(edge);
					assert!(self.is_action(target));
					assert!(!edgecases[i as usize]);
					edgecases[i as usize] = true;
				},
				_ => ()
			}
		}

		for edge in edges.iter() {
			assert!(edge.index() < edge_count);
			match self.g[*edge] {
				EdgeData::Control(i) if i < 2 => {
					// Things to lookout for:
					//  * There must be a minimum of two edges.
					//  * There _must_ be a selector.
					//  * The jump targets must not be the same block.
					assert!(edges.len() == 2);
					let other_edge = match i {
						0 => self.true_edge_of(block),
						1 => self.false_edge_of(block),
						_ => unreachable!(),
					};
					let target_1 = self.target_of(edge);
					let target_2 = self.target_of(&other_edge);
					assert!(target_1 != target_2);
					// No need to test the next edge.
					break;
				},
				EdgeData::Control(2) => {
					// Things to lookout for:
					//  * There can be only one Unconditional Edge.
					//  * There can be no selector.
					//  * Make sure we have not introduced an unconditional jump
					//    which self-loops.
					let target_block = self.target_of(edge);
					assert!(edges.len() == 1);
					assert!(*block != target_block);
				},
				_ => panic!("Found something other than a control edge!"),
			}
		}

		if edges.len() >= 2 {
			assert!(self.selector_of(block).is_none());
		} else {
			assert!(self.selector_of(block).is_some());
		}

		// Make sure that this block is reachable.
		let incoming = self.incoming_edges(block);
		assert!((incoming.len() > 0) || *block == self.start_node());
	}

	fn verify_expr(&self, i: &NodeIndex) {
		let node_count = self.node_count();
		// Make sure we have a valid node first.
		assert!(i.index() < node_count);
		let node_data = &self.g[*i];
		match *node_data {
			NodeData::Op(opcode, v) => {
			},
			_ => panic!("Found something other than an expression!"),
		}
	}
}

pub fn verify<T>(ssa: &T) where T: Verify {
	let blocks = ssa.blocks();
	for block in blocks.iter() {
		// assert the qualities of the block first.
		ssa.verify_block(block);
		// Iterate through each node in the block and assert their properties.
		let exprs = ssa.exprs_in(block);
		for expr in exprs.iter() {
			ssa.verify_expr(expr);
		}
	}
}
<|endoftext|>


<commit_before>//! Quicksort algorithm.
//!
//! The `efficient` module contains the efficient sorting algorithm "Quicksort".
//!
//! Source: https://en.wikipedia.org/wiki/Quicksort

use std::fmt::Debug;

/// Quicksort
///
/// # Details
///
///
///
/// # Scaling
///
///
///
/// # Optimizations
///
/// None
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::efficientsorts::quick::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
// pub fn sort<T: PartialOrd>(array: &mut Vec<T>) {
pub fn sort<T: PartialOrd + Debug>(array: &mut [T]) {
    println!("");
    println!("##########################################################################");
    let n = array.len();

    println!("  array: {:?}", array);

    if n <= 1 {
        // Don't do anything
    } else if n == 2 {
        if array.first() > array.last() {
            array.swap(0, 1);
        }
    } else {
        // Pick a pivot: Pick the middle element by skipping half the length and keeping just one.
        // let it_pivot = array.iter().skip(n / 2).take(1);
        // Take the first element as the pivot.
        // let it_pivot = array.iter().take(1);
        //
        // for it in it_pivot {
        //     println!("  0. it: {:?}", it);
        // }

        // Loop over array, finding smaller elements than the pivot.
        // for it in array.iter().skip(1) {
        //     //println!("  1. it: {:?}", it);
        //     if it < it_pivot {
        //         println!("  1. it: {:?} smaller than pivot!", it);
        //     }
        // }
        // array.swap(0,1);

        // array.iter().enumerate().map(|(i,x)| {});

        // // Take the first element as pivot.
        // let a = array.iter_mut().skip(1).enumerate().fold(
        //     (0, array[0]), |acc, item| {
        //         if acc.1 > item.1 {
        //             // Element is smaller than pivot; swap them!
        //             array.swap(acc.0, item.0);
        //             // Return the accumulator as being the new index of pivot (which is now at
        //             // at the location of the fold()) with the pivot value which shouldn't change.
        //             (item.0, acc.1)
        //         } else {
        //             // Nothing to do as element is larger than pivot. Just return new accumulator.
        //             (acc.0, acc.1)
        //         }
        //     }
        // );

        let mut pivot = 0;
        for i in 1..n {
            println!("---------------");
            println!("  array[pivot={:?}]: {:?}    array[i={:?}]: {:?}", pivot, array[pivot], i, array[i]);
            if array[pivot] > array[i] {
                println!("    Swapping array[pivot={:?}]: {:?} with array[i={:?}]: {:?}", pivot, array[pivot], i, array[i]);

                array.swap(pivot, i);
                println!("  array: {:?}", array);
                if i == pivot+1 {
                    pivot = i;
                    println!("      pivot is now at {:?}", pivot);
                } else {
                    println!("      swapping i={:?} and pivot+1={:?}", i, pivot+1);
                    array.swap(i, pivot+1);
                    pivot = pivot+1;
                    println!("        pivot is now at {:?}", pivot);
                }
            }
            println!("  array: {:?}", array);
        }
        println!("array: {:?}", array);
        println!("array[pivot={:?}] = {:?}", pivot, array[pivot]);

        sort(&mut array[0..pivot+1]);
        sort(&mut array[pivot+1..n]);
    }

    println!("FINAL array: {:?}", array);
}
<commit_msg>Cleanup: No output prints<commit_after>//! Quicksort algorithm.
//!
//! The `efficient` module contains the efficient sorting algorithm "Quicksort".
//!
//! Source: https://en.wikipedia.org/wiki/Quicksort

use std::fmt::Debug;

/// Quicksort
///
/// # Details
///
///
///
/// # Scaling
///
///
///
/// # Optimizations
///
/// None
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::efficientsorts::quick::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
// pub fn sort<T: PartialOrd>(array: &mut Vec<T>) {
pub fn sort<T: PartialOrd + Debug>(array: &mut [T]) {
    let n = array.len();

    if n <= 1 {
        // Don't do anything
    } else if n == 2 {
        if array.first() > array.last() {
            array.swap(0, 1);
        }
    } else {
        // Pick a pivot: Pick the middle element by skipping half the length and keeping just one.
        // let it_pivot = array.iter().skip(n / 2).take(1);
        // Take the first element as the pivot.
        // let it_pivot = array.iter().take(1);
        //
        // for it in it_pivot {
        //     println!("  0. it: {:?}", it);
        // }

        // Loop over array, finding smaller elements than the pivot.
        // for it in array.iter().skip(1) {
        //     //println!("  1. it: {:?}", it);
        //     if it < it_pivot {
        //         println!("  1. it: {:?} smaller than pivot!", it);
        //     }
        // }
        // array.swap(0,1);

        // array.iter().enumerate().map(|(i,x)| {});

        // // Take the first element as pivot.
        // let a = array.iter_mut().skip(1).enumerate().fold(
        //     (0, array[0]), |acc, item| {
        //         if acc.1 > item.1 {
        //             // Element is smaller than pivot; swap them!
        //             array.swap(acc.0, item.0);
        //             // Return the accumulator as being the new index of pivot (which is now at
        //             // at the location of the fold()) with the pivot value which shouldn't change.
        //             (item.0, acc.1)
        //         } else {
        //             // Nothing to do as element is larger than pivot. Just return new accumulator.
        //             (acc.0, acc.1)
        //         }
        //     }
        // );

        let mut pivot = 0;
        for i in 1..n {
            if array[pivot] > array[i] {

                array.swap(pivot, i);
                if i == pivot+1 {
                    pivot = i;
                } else {
                    array.swap(i, pivot+1);
                    pivot = pivot+1;
                }
            }
        }
        sort(&mut array[0..pivot+1]);
        sort(&mut array[pivot+1..n]);
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::fmt;

type Vector3 = (i32, i32, i32);

#[derive(Clone)]
struct MoonState {
  position: Vector3,
  velocity: Vector3
}

impl fmt::Debug for MoonState {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(
      f, "pos=<x={}, y={}, z={}>, vel=<x={}, y={}, z={}>",
      self.position.0,
      self.position.1,
      self.position.2,
      self.velocity.0,
      self.velocity.1,
      self.velocity.2
    )
  }
}

impl MoonState {
  fn potential_energy(&self) -> i32 {
    norm(self.position)
  }

  fn kinetic_enery(&self) -> i32 {
    norm(self.velocity)
  }

  fn total_energy(&self) -> i32 {
    self.potential_energy() * self.kinetic_enery()
  }
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("12.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_input(input: &str) -> Vec<MoonState> {
  input.lines()
  .filter_map(|line| line.get(1..line.len() - 1))
  .filter_map(|line| {
    let mut coords = line.split(", ")
      .filter_map(|token| {
        match token.split('=').nth(1) {
          Some(x) => x.parse::<i32>().ok(),
          _ => None
        }
      });

    match (coords.nth(0), coords.nth(0), coords.nth(0)) {
      (Some(x), Some(y), Some(z)) => Some((x, y, z)),
      _ => None
    }
  })
  .map(|position| MoonState {
    position,
    velocity: (0, 0, 0)
  })
  .collect()
}

fn norm((x, y, z): Vector3) -> i32 {
  x.abs() + y.abs() + z.abs()
}

fn gcd(a: i64, b: i64) -> i64 {
  let (mut a, mut b) = (a, b);
  let mut h;

  if a == 0 {
    return b.abs();
  } else if b == 0 {
    return a.abs();
  }

  loop {
    h = a % b;
    a = b;
    b = h;

    if b == 0 {
      break a.abs();
    }
  }
}

fn lcm(a: i64, b: i64) -> i64 {
  if a == 0 && b == 0 {
    0
  } else {
    a.abs() / gcd(a, b) * b.abs()
  }
}

fn multiple_lcm(numbers: &[i64]) -> Option<i64> {
  numbers.iter()
  .fold(None, |acc, &x| match acc {
    None => Some(x),
    Some(acc) => Some(lcm(acc, x))
  })
}

fn calc_acceleration(pos1: Vector3, pos2: Vector3) -> Vector3 {
  fn get_sign(x: i32, y: i32) -> i32 {
    if x < y { 1 }
    else if x > y { -1 }
    else { 0 }
  }

  (
    get_sign(pos1.0, pos2.0),
    get_sign(pos1.1, pos2.1),
    get_sign(pos1.2, pos2.2)
  )
}

fn simulate_tick(moons: &mut Vec<MoonState>) {
  // Apply gravity

  let n = moons.len();
  let pairs = (0..n)
    .flat_map(|x| {
      (0..n)
      .map(move |y| (x, y))
    })
    .filter(|&(x, y)| x < y);

  for (i, j) in pairs {
    let moon1 = &moons[i];
    let moon2 = &moons[j];
    let acceleration = calc_acceleration(moon1.position, moon2.position);

    let moon1 = &mut moons[i];

    moon1.velocity = (
      moon1.velocity.0 + acceleration.0,
      moon1.velocity.1 + acceleration.1,
      moon1.velocity.2 + acceleration.2
    );

    let moon2 = &mut moons[j];

    moon2.velocity = (
      moon2.velocity.0 - acceleration.0,
      moon2.velocity.1 - acceleration.1,
      moon2.velocity.2 - acceleration.2
    );
  }

  // Apply velocity

  for moon in moons.iter_mut() {
    moon.position = (
      moon.position.0 + moon.velocity.0,
      moon.position.1 + moon.velocity.1,
      moon.position.2 + moon.velocity.2
    );
  }
}

fn main() {
  let input = get_input().unwrap();
  let initial_moons = parse_input(&input);
  let mut moons = initial_moons.clone();

  for _ in 0..1000 {
    simulate_tick(&mut moons);
  }

  let total_energy = moons.iter()
    .map(|moon| moon.total_energy())
    .sum::<i32>();

  println!("Part 1: {}", total_energy);

  let mut moons = initial_moons.clone();
  let (mut xf, mut yf, mut zf) = (false, false, false);
  let (mut xp, mut yp, mut zp) = (0, 0, 0);

  fn count_var<F, T>(
    counter: &mut i64,
    finished: &mut bool,
    moons: &Vec<MoonState>,
    compare: &Vec<MoonState>,
    predicate: F
  )
  where
    T: PartialEq,
    F: Fn(&MoonState) -> T
  {
    if !*finished {
      *counter += 1;

      let component_equals = moons.iter().map(&predicate)
        .zip(compare.iter().map(&predicate))
        .all(|(x, y)| x == y);

      if component_equals {
        *finished = true;
      }
    }
  }

  loop {
    simulate_tick(&mut moons);

    count_var(&mut xp, &mut xf, &moons, &initial_moons, |moon| [moon.position.0, moon.velocity.0]);
    count_var(&mut yp, &mut yf, &moons, &initial_moons, |moon| [moon.position.1, moon.velocity.1]);
    count_var(&mut zp, &mut zf, &moons, &initial_moons, |moon| [moon.position.2, moon.velocity.2]);

    if xf && yf && zf {
      break;
    }
  }

  println!("Part 2: {}", multiple_lcm(&[xp, yp, zp]).unwrap());
}
<commit_msg>Remove some unnecessary code<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::fmt;

type Vector3 = (i32, i32, i32);

#[derive(Clone)]
struct MoonState {
  position: Vector3,
  velocity: Vector3
}

impl fmt::Debug for MoonState {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(
      f, "pos=<x={}, y={}, z={}>, vel=<x={}, y={}, z={}>",
      self.position.0,
      self.position.1,
      self.position.2,
      self.velocity.0,
      self.velocity.1,
      self.velocity.2
    )
  }
}

impl MoonState {
  fn potential_energy(&self) -> i32 {
    norm(self.position)
  }

  fn kinetic_enery(&self) -> i32 {
    norm(self.velocity)
  }

  fn total_energy(&self) -> i32 {
    self.potential_energy() * self.kinetic_enery()
  }
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("12.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_input(input: &str) -> Vec<MoonState> {
  input.lines()
  .filter_map(|line| line.get(1..line.len() - 1))
  .filter_map(|line| {
    let mut coords = line.split(", ")
      .filter_map(|token| {
        match token.split('=').nth(1) {
          Some(x) => x.parse::<i32>().ok(),
          _ => None
        }
      });

    match (coords.nth(0), coords.nth(0), coords.nth(0)) {
      (Some(x), Some(y), Some(z)) => Some((x, y, z)),
      _ => None
    }
  })
  .map(|position| MoonState {
    position,
    velocity: (0, 0, 0)
  })
  .collect()
}

fn norm((x, y, z): Vector3) -> i32 {
  x.abs() + y.abs() + z.abs()
}

fn gcd(a: i64, b: i64) -> i64 {
  let (mut a, mut b) = (a, b);
  let mut h;

  if a == 0 {
    return b.abs();
  } else if b == 0 {
    return a.abs();
  }

  loop {
    h = a % b;
    a = b;
    b = h;

    if b == 0 {
      break a.abs();
    }
  }
}

fn lcm(a: i64, b: i64) -> i64 {
  if a == 0 && b == 0 {
    0
  } else {
    a.abs() / gcd(a, b) * b.abs()
  }
}

fn multiple_lcm(numbers: &[i64]) -> Option<i64> {
  numbers.iter()
  .fold(None, |acc, &x| match acc {
    None => Some(x),
    Some(acc) => Some(lcm(acc, x))
  })
}

fn calc_acceleration(pos1: Vector3, pos2: Vector3) -> Vector3 {
  fn get_sign(x: i32, y: i32) -> i32 {
    if x < y { 1 }
    else if x > y { -1 }
    else { 0 }
  }

  (
    get_sign(pos1.0, pos2.0),
    get_sign(pos1.1, pos2.1),
    get_sign(pos1.2, pos2.2)
  )
}

fn simulate_tick(moons: &mut Vec<MoonState>) {
  // Apply gravity

  let n = moons.len();
  let pairs = (0..n)
    .flat_map(|x| {
      (0..n)
      .map(move |y| (x, y))
    })
    .filter(|&(x, y)| x != y);

  for (i, j) in pairs {
    let moon1 = &moons[i];
    let moon2 = &moons[j];
    let acceleration = calc_acceleration(moon1.position, moon2.position);

    let moon1 = &mut moons[i];

    moon1.velocity = (
      moon1.velocity.0 + acceleration.0,
      moon1.velocity.1 + acceleration.1,
      moon1.velocity.2 + acceleration.2
    );
  }

  // Apply velocity

  for moon in moons.iter_mut() {
    moon.position = (
      moon.position.0 + moon.velocity.0,
      moon.position.1 + moon.velocity.1,
      moon.position.2 + moon.velocity.2
    );
  }
}

fn main() {
  let input = get_input().unwrap();
  let initial_moons = parse_input(&input);
  let mut moons = initial_moons.clone();

  for _ in 0..1000 {
    simulate_tick(&mut moons);
  }

  let total_energy = moons.iter()
    .map(|moon| moon.total_energy())
    .sum::<i32>();

  println!("Part 1: {}", total_energy);

  let mut moons = initial_moons.clone();
  let (mut xf, mut yf, mut zf) = (false, false, false);
  let (mut xp, mut yp, mut zp) = (0, 0, 0);

  fn count_var<F, T>(
    counter: &mut i64,
    finished: &mut bool,
    moons: &Vec<MoonState>,
    compare: &Vec<MoonState>,
    predicate: F
  )
  where
    T: PartialEq,
    F: Fn(&MoonState) -> T
  {
    if !*finished {
      *counter += 1;

      let component_equals = moons.iter().map(&predicate)
        .zip(compare.iter().map(&predicate))
        .all(|(x, y)| x == y);

      if component_equals {
        *finished = true;
      }
    }
  }

  loop {
    simulate_tick(&mut moons);

    count_var(&mut xp, &mut xf, &moons, &initial_moons, |moon| [moon.position.0, moon.velocity.0]);
    count_var(&mut yp, &mut yf, &moons, &initial_moons, |moon| [moon.position.1, moon.velocity.1]);
    count_var(&mut zp, &mut zf, &moons, &initial_moons, |moon| [moon.position.2, moon.velocity.2]);

    if xf && yf && zf {
      break;
    }
  }

  println!("Part 2: {}", multiple_lcm(&[xp, yp, zp]).unwrap());
}
<|endoftext|>


<commit_before>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! vmwdt is a virtual watchdog memory mapped device which detects stalls
//! on the vCPUs and resets the guest when no 'pet' events are received.
//! https://docs.google.com/document/d/1DYmk2roxlwHZsOfcJi8xDMdWOHAmomvs2SDh7KPud3Y/edit?usp=sharing&resourcekey=0-oSNabc-t040a1q0K4cyI8Q

use crate::pci::CrosvmDeviceId;
use crate::DeviceId;
use crate::{BusAccessInfo, BusDevice};
use base::{
    debug, error, gettid, warn, AsRawDescriptor, Descriptor, Error as SysError, Event, EventToken,
    SendTube, Timer, VmEventType, WaitContext,
};

use remain::sorted;
use std::convert::TryFrom;
use std::io::Error as IoError;
use std::process;
use std::sync::Arc;
use std::time::Duration;
use std::{fs, thread};
use sync::Mutex;
use thiserror::Error;

// Registers offsets
const VMWDT_REG_STATUS: u32 = 0x00;
const VMWDT_REG_LOAD_CNT: u32 = 0x04;
const VMWDT_REG_CURRENT_CNT: u32 = 0x08;
const VMWDT_REG_CLOCK_FREQ_HZ: u32 = 0x0C;

// Length of the registers
const VMWDT_REG_LEN: u64 = 0x10;

pub const VMWDT_DEFAULT_TIMEOUT_SEC: u32 = 10;
pub const VMWDT_DEFAULT_CLOCK_HZ: u32 = 2;

// Proc stat indexes
const PROCSTAT_UTIME_INDX: usize = 13;
const PROCSTAT_GUEST_TIME_INDX: usize = 42;

#[sorted]
#[derive(Error, Debug)]
pub enum VmwdtError {
    /// Error while creating event.
    #[error("failed to create event: {0}")]
    CreateEvent(SysError),
    /// Error while trying to create worker thread.
    #[error("failed to spawn thread: {0}")]
    SpawnThread(IoError),
    /// Error while trying to create timer.
    #[error("failed to create vmwdt counter due to timer fd: {0}")]
    TimerCreateError(SysError),
    #[error("failed to wait for events: {0}")]
    WaitError(SysError),
}

type VmwdtResult<T> = std::result::Result<T, VmwdtError>;

pub struct VmwdtPerCpu {
    // Flag which indicated if the watchdog is started
    is_enabled: bool,
    // Counter value decremented periodically by the timer
    counter: i32,
    // Timer used to generate periodic events at `timer_freq_hz` frequency
    timer: Timer,
    // The frequency of the `timer`
    timer_freq_hz: u64,
    // Timestamp measured in systicks which is updated with every `pet` event
    // that tells how many ticks were lost while guest is not running
    not_running_last_timestamp: u64,
}

pub struct Vmwdt {
    vm_wdts: Arc<Mutex<Vec<VmwdtPerCpu>>>,
    // The worker thread that waits on the timer fd
    worker_thread: Option<thread::JoinHandle<()>>,
    // An event used to signal background thread cancellation
    kill_evt: Event,
    // TODO: @sebastianene add separate reset event for the watchdog
    // Reset source if the device is not responding
    reset_evt_wrtube: SendTube,
}

impl Vmwdt {
    pub fn new(cpu_count: usize, reset_evt_wrtube: SendTube) -> VmwdtResult<Vmwdt> {
        let mut vec = Vec::new();
        for _ in 0..cpu_count {
            vec.push(VmwdtPerCpu {
                counter: 0,
                not_running_last_timestamp: 0,
                is_enabled: false,
                timer: Timer::new().unwrap(),
                timer_freq_hz: 0,
            });
        }
        let vm_wdts = Arc::new(Mutex::new(vec));

        // Create a new event that will be used to notify the bg thread for exit
        let kill_evt = Event::new().unwrap();
        Ok(Vmwdt {
            vm_wdts,
            worker_thread: None,
            kill_evt,
            reset_evt_wrtube,
        })
    }

    pub fn vmwdt_worker_thread(
        vm_wdts: Arc<Mutex<Vec<VmwdtPerCpu>>>,
        kill_evt: Event,
        reset_evt_wrtube: SendTube,
    ) {
        #[derive(EventToken)]
        enum Token {
            Kill,
            Timer(usize),
        }

        let wait_ctx: WaitContext<Token> = WaitContext::new().unwrap();
        wait_ctx.add(&kill_evt, Token::Kill).unwrap();
        let mut interrupt_active = false;

        let len = vm_wdts.lock().len();
        for clock_id in 0..len {
            let timer_fd = vm_wdts.lock()[clock_id].timer.as_raw_descriptor();
            wait_ctx
                .add(&Descriptor(timer_fd), Token::Timer(clock_id))
                .unwrap();
        }

        loop {
            let events = wait_ctx.wait().unwrap();
            for event in events.iter().filter(|e| e.is_readable) {
                match event.token {
                    Token::Kill => {
                        return;
                    }
                    Token::Timer(clock_id) => {
                        let cnt = {
                            let mut wdts_locked = vm_wdts.lock();
                            let mut watchdog = &mut wdts_locked[clock_id];
                            if let Err(_e) = watchdog.timer.wait() {
                                error!("error waiting for timer event");
                            }
                            watchdog.counter -= 1;
                            watchdog.counter
                        };

                        if cnt <= 0 {
                            // vCPU is not petting the watchdog fast enough, reset vm
                            warn!("clock {} detected stall {}", clock_id, cnt);

                            if !interrupt_active {
                                if let Err(_e) =
                                    reset_evt_wrtube.send::<VmEventType>(&VmEventType::Reset)
                                {
                                    error!("failed to send reset event")
                                }
                                interrupt_active = true;
                            }
                        }
                    }
                }
            }
        }
    }

    fn start(&mut self) {
        let vm_wdts = self.vm_wdts.clone();
        let kill_evt = self.kill_evt.try_clone().unwrap();
        let reset_evt_wrtube = self.reset_evt_wrtube.try_clone().unwrap();

        self.worker_thread = Some(
            thread::Builder::new()
                .name("vmwdt worker".into())
                .spawn(|| Vmwdt::vmwdt_worker_thread(vm_wdts, kill_evt, reset_evt_wrtube))
                .map_err(VmwdtError::SpawnThread)
                .unwrap(),
        );
    }

    fn ensure_started(&mut self) {
        if self.worker_thread.is_some() {
            return;
        }

        self.start();
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn get_nonrunning_time_ms(&mut self, cpu_id: usize) -> u64 {
        let ppid = process::id();
        let pid = gettid();

        // TODO: @sebastianene check if we can avoid open-read-close on each call
        let stat_path = format!("/proc/{}/task/{}/stat", ppid, pid);
        let contents = fs::read_to_string(stat_path).expect("error reading the stat");

        let coll: Vec<_> = contents.split_whitespace().collect();
        let utime = coll[PROCSTAT_UTIME_INDX].parse::<u64>();
        let guest_time = coll[PROCSTAT_GUEST_TIME_INDX].parse::<u64>();

        // The lost time since the last tick event
        let mut non_guest_time_delta: u64 = 0;
        let utime_ticks = match utime {
            Err(_e) => return 0,
            Ok(f) => f,
        };
        let gtime_ticks = match guest_time {
            Err(_e) => return 0,
            Ok(f) => f,
        };

        if utime_ticks > gtime_ticks {
            // Time that the guest is not running measured in systicks
            let non_guest_time = utime_ticks - gtime_ticks;
            non_guest_time_delta = {
                let mut vm_wdts_locked = self.vm_wdts.lock();
                let not_running_last_timestamp = vm_wdts_locked[cpu_id].not_running_last_timestamp;

                if non_guest_time > not_running_last_timestamp {
                    // Save the current timestamp
                    vm_wdts_locked[cpu_id].not_running_last_timestamp = non_guest_time;
                    non_guest_time - not_running_last_timestamp
                } else {
                    0
                }
            };
        }

        // Safe because this just returns an integer
        let ticks_per_sec = unsafe { libc::sysconf(libc::_SC_CLK_TCK) } as u64;
        non_guest_time_delta * 1000 / ticks_per_sec
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn get_nonrunning_time_ms(&mut self, cpu_id: usize) -> u64 {
        0
    }
}

impl Drop for Vmwdt {
    fn drop(&mut self) {
        if let Err(e) = self.kill_evt.write(1) {
            error!("Failed to stop the bg thread: {}", e);
            return;
        }

        if let Some(thread) = self.worker_thread.take() {
            match thread.join() {
                Ok(_) => {
                    debug!("Stopped the bg thread\n");
                }
                Err(_) => {
                    error!("Failed to stop the bg thread");
                }
            }
        }
    }
}

impl BusDevice for Vmwdt {
    fn debug_label(&self) -> String {
        "Vmwdt".to_owned()
    }

    fn device_id(&self) -> DeviceId {
        CrosvmDeviceId::VmWatchdog.into()
    }

    fn read(&mut self, _offset: BusAccessInfo, _data: &mut [u8]) {}

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        let data_array = match <&[u8; 4]>::try_from(data) {
            Ok(array) => array,
            _ => {
                error!("Bad write size: {} for vmwdt", data.len());
                return;
            }
        };

        let mut reg_val = u32::from_ne_bytes(*data_array);
        let cpu_index: usize = (info.offset / VMWDT_REG_LEN) as usize;
        let reg_offset = (info.offset % VMWDT_REG_LEN) as u32;

        if cpu_index > self.vm_wdts.lock().len() {
            error!("Bad write cpu_index {}", cpu_index);
            return;
        }

        match reg_offset {
            VMWDT_REG_STATUS => {
                self.ensure_started();
                let mut wdts_locked = self.vm_wdts.lock();
                let mut cpu_watchdog = &mut wdts_locked[cpu_index];

                cpu_watchdog.is_enabled = reg_val != 0;

                if reg_val != 0 {
                    let due = Duration::from_nanos(1);
                    let interval =
                        Duration::from_millis((1000 / cpu_watchdog.timer_freq_hz) as u64);
                    cpu_watchdog.timer.reset(due, Some(interval)).unwrap();
                } else {
                    cpu_watchdog.timer.clear().unwrap();
                }
            }
            VMWDT_REG_LOAD_CNT => {
                // Account for lost time(Time that the guest is not running)
                let not_running_time_ms = self.get_nonrunning_time_ms(cpu_index);
                let mut wdts_locked = self.vm_wdts.lock();
                let mut cpu_watchdog = &mut wdts_locked[cpu_index];

                if not_running_time_ms > 0 {
                    reg_val += (not_running_time_ms * cpu_watchdog.timer_freq_hz / 1000) as u32;
                }

                cpu_watchdog.counter = reg_val as i32;
                if cpu_watchdog.is_enabled {
                    let due = Duration::from_nanos(1);
                    let interval =
                        Duration::from_millis((1000 / cpu_watchdog.timer_freq_hz) as u64);
                    cpu_watchdog.timer.reset(due, Some(interval)).unwrap();
                }
            }
            VMWDT_REG_CURRENT_CNT => {
                warn!("invalid write to read-only VMWDT_REG_CURRENT_CNT register");
            }
            VMWDT_REG_CLOCK_FREQ_HZ => {
                let mut wdts_locked = self.vm_wdts.lock();
                let mut cpu_watchdog = &mut wdts_locked[cpu_index];

                debug!(
                    "CPU:{:x} wrote VMWDT_REG_CLOCK_FREQ_HZ {:x}",
                    cpu_index, reg_val
                );
                cpu_watchdog.timer_freq_hz = reg_val as u64;
            }
            _ => unreachable!(),
        }
    }
}
<commit_msg>devices: vmwdt: Fix rustdoc::bare_urls warnings<commit_after>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! vmwdt is a virtual watchdog memory mapped device which detects stalls
//! on the vCPUs and resets the guest when no 'pet' events are received.
//! <https://docs.google.com/document/d/1DYmk2roxlwHZsOfcJi8xDMdWOHAmomvs2SDh7KPud3Y/edit?usp=sharing&resourcekey=0-oSNabc-t040a1q0K4cyI8Q>

use crate::pci::CrosvmDeviceId;
use crate::DeviceId;
use crate::{BusAccessInfo, BusDevice};
use base::{
    debug, error, gettid, warn, AsRawDescriptor, Descriptor, Error as SysError, Event, EventToken,
    SendTube, Timer, VmEventType, WaitContext,
};

use remain::sorted;
use std::convert::TryFrom;
use std::io::Error as IoError;
use std::process;
use std::sync::Arc;
use std::time::Duration;
use std::{fs, thread};
use sync::Mutex;
use thiserror::Error;

// Registers offsets
const VMWDT_REG_STATUS: u32 = 0x00;
const VMWDT_REG_LOAD_CNT: u32 = 0x04;
const VMWDT_REG_CURRENT_CNT: u32 = 0x08;
const VMWDT_REG_CLOCK_FREQ_HZ: u32 = 0x0C;

// Length of the registers
const VMWDT_REG_LEN: u64 = 0x10;

pub const VMWDT_DEFAULT_TIMEOUT_SEC: u32 = 10;
pub const VMWDT_DEFAULT_CLOCK_HZ: u32 = 2;

// Proc stat indexes
const PROCSTAT_UTIME_INDX: usize = 13;
const PROCSTAT_GUEST_TIME_INDX: usize = 42;

#[sorted]
#[derive(Error, Debug)]
pub enum VmwdtError {
    /// Error while creating event.
    #[error("failed to create event: {0}")]
    CreateEvent(SysError),
    /// Error while trying to create worker thread.
    #[error("failed to spawn thread: {0}")]
    SpawnThread(IoError),
    /// Error while trying to create timer.
    #[error("failed to create vmwdt counter due to timer fd: {0}")]
    TimerCreateError(SysError),
    #[error("failed to wait for events: {0}")]
    WaitError(SysError),
}

type VmwdtResult<T> = std::result::Result<T, VmwdtError>;

pub struct VmwdtPerCpu {
    // Flag which indicated if the watchdog is started
    is_enabled: bool,
    // Counter value decremented periodically by the timer
    counter: i32,
    // Timer used to generate periodic events at `timer_freq_hz` frequency
    timer: Timer,
    // The frequency of the `timer`
    timer_freq_hz: u64,
    // Timestamp measured in systicks which is updated with every `pet` event
    // that tells how many ticks were lost while guest is not running
    not_running_last_timestamp: u64,
}

pub struct Vmwdt {
    vm_wdts: Arc<Mutex<Vec<VmwdtPerCpu>>>,
    // The worker thread that waits on the timer fd
    worker_thread: Option<thread::JoinHandle<()>>,
    // An event used to signal background thread cancellation
    kill_evt: Event,
    // TODO: @sebastianene add separate reset event for the watchdog
    // Reset source if the device is not responding
    reset_evt_wrtube: SendTube,
}

impl Vmwdt {
    pub fn new(cpu_count: usize, reset_evt_wrtube: SendTube) -> VmwdtResult<Vmwdt> {
        let mut vec = Vec::new();
        for _ in 0..cpu_count {
            vec.push(VmwdtPerCpu {
                counter: 0,
                not_running_last_timestamp: 0,
                is_enabled: false,
                timer: Timer::new().unwrap(),
                timer_freq_hz: 0,
            });
        }
        let vm_wdts = Arc::new(Mutex::new(vec));

        // Create a new event that will be used to notify the bg thread for exit
        let kill_evt = Event::new().unwrap();
        Ok(Vmwdt {
            vm_wdts,
            worker_thread: None,
            kill_evt,
            reset_evt_wrtube,
        })
    }

    pub fn vmwdt_worker_thread(
        vm_wdts: Arc<Mutex<Vec<VmwdtPerCpu>>>,
        kill_evt: Event,
        reset_evt_wrtube: SendTube,
    ) {
        #[derive(EventToken)]
        enum Token {
            Kill,
            Timer(usize),
        }

        let wait_ctx: WaitContext<Token> = WaitContext::new().unwrap();
        wait_ctx.add(&kill_evt, Token::Kill).unwrap();
        let mut interrupt_active = false;

        let len = vm_wdts.lock().len();
        for clock_id in 0..len {
            let timer_fd = vm_wdts.lock()[clock_id].timer.as_raw_descriptor();
            wait_ctx
                .add(&Descriptor(timer_fd), Token::Timer(clock_id))
                .unwrap();
        }

        loop {
            let events = wait_ctx.wait().unwrap();
            for event in events.iter().filter(|e| e.is_readable) {
                match event.token {
                    Token::Kill => {
                        return;
                    }
                    Token::Timer(clock_id) => {
                        let cnt = {
                            let mut wdts_locked = vm_wdts.lock();
                            let mut watchdog = &mut wdts_locked[clock_id];
                            if let Err(_e) = watchdog.timer.wait() {
                                error!("error waiting for timer event");
                            }
                            watchdog.counter -= 1;
                            watchdog.counter
                        };

                        if cnt <= 0 {
                            // vCPU is not petting the watchdog fast enough, reset vm
                            warn!("clock {} detected stall {}", clock_id, cnt);

                            if !interrupt_active {
                                if let Err(_e) =
                                    reset_evt_wrtube.send::<VmEventType>(&VmEventType::Reset)
                                {
                                    error!("failed to send reset event")
                                }
                                interrupt_active = true;
                            }
                        }
                    }
                }
            }
        }
    }

    fn start(&mut self) {
        let vm_wdts = self.vm_wdts.clone();
        let kill_evt = self.kill_evt.try_clone().unwrap();
        let reset_evt_wrtube = self.reset_evt_wrtube.try_clone().unwrap();

        self.worker_thread = Some(
            thread::Builder::new()
                .name("vmwdt worker".into())
                .spawn(|| Vmwdt::vmwdt_worker_thread(vm_wdts, kill_evt, reset_evt_wrtube))
                .map_err(VmwdtError::SpawnThread)
                .unwrap(),
        );
    }

    fn ensure_started(&mut self) {
        if self.worker_thread.is_some() {
            return;
        }

        self.start();
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn get_nonrunning_time_ms(&mut self, cpu_id: usize) -> u64 {
        let ppid = process::id();
        let pid = gettid();

        // TODO: @sebastianene check if we can avoid open-read-close on each call
        let stat_path = format!("/proc/{}/task/{}/stat", ppid, pid);
        let contents = fs::read_to_string(stat_path).expect("error reading the stat");

        let coll: Vec<_> = contents.split_whitespace().collect();
        let utime = coll[PROCSTAT_UTIME_INDX].parse::<u64>();
        let guest_time = coll[PROCSTAT_GUEST_TIME_INDX].parse::<u64>();

        // The lost time since the last tick event
        let mut non_guest_time_delta: u64 = 0;
        let utime_ticks = match utime {
            Err(_e) => return 0,
            Ok(f) => f,
        };
        let gtime_ticks = match guest_time {
            Err(_e) => return 0,
            Ok(f) => f,
        };

        if utime_ticks > gtime_ticks {
            // Time that the guest is not running measured in systicks
            let non_guest_time = utime_ticks - gtime_ticks;
            non_guest_time_delta = {
                let mut vm_wdts_locked = self.vm_wdts.lock();
                let not_running_last_timestamp = vm_wdts_locked[cpu_id].not_running_last_timestamp;

                if non_guest_time > not_running_last_timestamp {
                    // Save the current timestamp
                    vm_wdts_locked[cpu_id].not_running_last_timestamp = non_guest_time;
                    non_guest_time - not_running_last_timestamp
                } else {
                    0
                }
            };
        }

        // Safe because this just returns an integer
        let ticks_per_sec = unsafe { libc::sysconf(libc::_SC_CLK_TCK) } as u64;
        non_guest_time_delta * 1000 / ticks_per_sec
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn get_nonrunning_time_ms(&mut self, cpu_id: usize) -> u64 {
        0
    }
}

impl Drop for Vmwdt {
    fn drop(&mut self) {
        if let Err(e) = self.kill_evt.write(1) {
            error!("Failed to stop the bg thread: {}", e);
            return;
        }

        if let Some(thread) = self.worker_thread.take() {
            match thread.join() {
                Ok(_) => {
                    debug!("Stopped the bg thread\n");
                }
                Err(_) => {
                    error!("Failed to stop the bg thread");
                }
            }
        }
    }
}

impl BusDevice for Vmwdt {
    fn debug_label(&self) -> String {
        "Vmwdt".to_owned()
    }

    fn device_id(&self) -> DeviceId {
        CrosvmDeviceId::VmWatchdog.into()
    }

    fn read(&mut self, _offset: BusAccessInfo, _data: &mut [u8]) {}

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        let data_array = match <&[u8; 4]>::try_from(data) {
            Ok(array) => array,
            _ => {
                error!("Bad write size: {} for vmwdt", data.len());
                return;
            }
        };

        let mut reg_val = u32::from_ne_bytes(*data_array);
        let cpu_index: usize = (info.offset / VMWDT_REG_LEN) as usize;
        let reg_offset = (info.offset % VMWDT_REG_LEN) as u32;

        if cpu_index > self.vm_wdts.lock().len() {
            error!("Bad write cpu_index {}", cpu_index);
            return;
        }

        match reg_offset {
            VMWDT_REG_STATUS => {
                self.ensure_started();
                let mut wdts_locked = self.vm_wdts.lock();
                let mut cpu_watchdog = &mut wdts_locked[cpu_index];

                cpu_watchdog.is_enabled = reg_val != 0;

                if reg_val != 0 {
                    let due = Duration::from_nanos(1);
                    let interval =
                        Duration::from_millis((1000 / cpu_watchdog.timer_freq_hz) as u64);
                    cpu_watchdog.timer.reset(due, Some(interval)).unwrap();
                } else {
                    cpu_watchdog.timer.clear().unwrap();
                }
            }
            VMWDT_REG_LOAD_CNT => {
                // Account for lost time(Time that the guest is not running)
                let not_running_time_ms = self.get_nonrunning_time_ms(cpu_index);
                let mut wdts_locked = self.vm_wdts.lock();
                let mut cpu_watchdog = &mut wdts_locked[cpu_index];

                if not_running_time_ms > 0 {
                    reg_val += (not_running_time_ms * cpu_watchdog.timer_freq_hz / 1000) as u32;
                }

                cpu_watchdog.counter = reg_val as i32;
                if cpu_watchdog.is_enabled {
                    let due = Duration::from_nanos(1);
                    let interval =
                        Duration::from_millis((1000 / cpu_watchdog.timer_freq_hz) as u64);
                    cpu_watchdog.timer.reset(due, Some(interval)).unwrap();
                }
            }
            VMWDT_REG_CURRENT_CNT => {
                warn!("invalid write to read-only VMWDT_REG_CURRENT_CNT register");
            }
            VMWDT_REG_CLOCK_FREQ_HZ => {
                let mut wdts_locked = self.vm_wdts.lock();
                let mut cpu_watchdog = &mut wdts_locked[cpu_index];

                debug!(
                    "CPU:{:x} wrote VMWDT_REG_CLOCK_FREQ_HZ {:x}",
                    cpu_index, reg_val
                );
                cpu_watchdog.timer_freq_hz = reg_val as u64;
            }
            _ => unreachable!(),
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

fn main() {
    example::main();
}

#[cfg(feature = "security")]
mod example {
    extern crate openssl;
    extern crate kafka;
    extern crate getopts;
    extern crate env_logger;

    use std::env;
    use std::process;

    use self::kafka::client::{FetchOffset, KafkaClient, SecurityConfig};

    use self::openssl::ssl::{SslConnectorBuilder, SslMethod, SSL_VERIFY_PEER};
    use self::openssl::x509::X509_FILETYPE_PEM;

    pub fn main() {
        env_logger::init().unwrap();

        // ~ parse the command line arguments
        let cfg = match Config::from_cmdline() {
            Ok(cfg) => cfg,
            Err(e) => {
                println!("{}", e);
                process::exit(1);
            }
        };

        // ~ OpenSSL offers a variety of complex configurations. Here is an example:
        let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
        {
            let mut ctx = builder.builder_mut();
            ctx.set_cipher_list("DEFAULT").unwrap();
            ctx.set_verify(SSL_VERIFY_PEER);
            if let (Some(ccert), Some(ckey)) = (cfg.client_cert, cfg.client_key) {
                info!("loading cert-file={}, key-file={}", ccert, ckey);

                ctx.set_certificate_file(ccert, X509_FILETYPE_PEM)
                    .unwrap();
                ctx.set_private_key_file(ckey, X509_FILETYPE_PEM)
                    .unwrap();
                ctx.check_private_key().unwrap();
            }

            if let Some(ca_cert) = cfg.ca_cert {
                info!("loading ca-file={}", ca_cert);

                ctx.set_ca_file(ca_cert).unwrap();
            } else {
                // ~ allow client specify the CAs through the default paths:
                // "These locations are read from the SSL_CERT_FILE and
                // SSL_CERT_DIR environment variables if present, or defaults
                // specified at OpenSSL build time otherwise."
                ctx.set_default_verify_paths().unwrap();
            }
        }

        let connector = builder.build();

        // ~ instantiate KafkaClient with the previous OpenSSL setup
        let mut client =
            KafkaClient::new_secure(cfg.brokers,
                                    SecurityConfig::new(connector)
                                        .with_hostname_verification(cfg.verify_hostname));

        // ~ communicate with the brokers
        match client.load_metadata_all() {
            Err(e) => {
                println!("{:?}", e);
                drop(client);
                process::exit(1);
            }
            Ok(_) => {
                // ~ at this point we have successfully loaded
                // metadata via a secured connection to one of the
                // specified brokers

                if client.topics().len() == 0 {
                    println!("No topics available!");
                } else {
                    // ~ now let's communicate with all the brokers in
                    // the cluster our topics are spread over

                    let topics: Vec<String> = client.topics().names().map(Into::into).collect();
                    match client.fetch_offsets(topics.as_slice(), FetchOffset::Latest) {
                        Err(e) => {
                            println!("{:?}", e);
                            drop(client);
                            process::exit(1);
                        }
                        Ok(toffsets) => {
                            println!("Topic offsets:");
                            for (topic, mut offs) in toffsets {
                                offs.sort_by_key(|x| x.partition);
                                println!("{}", topic);
                                for off in offs {
                                    println!("\t{}: {:?}", off.partition, off.offset);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    struct Config {
        brokers: Vec<String>,
        client_cert: Option<String>,
        client_key: Option<String>,
        ca_cert: Option<String>,
        verify_hostname: bool,
    }

    impl Config {
        fn from_cmdline() -> Result<Config, String> {
            let mut opts = getopts::Options::new();
            opts.optflag("h", "help", "Print this help screen");
            opts.optopt("", "brokers", "Specify kafka brokers (comma separated)", "HOSTS");
            opts.optopt("", "ca-cert", "Specify the trusted CA certificates", "FILE");
            opts.optopt("", "client-cert", "Specify the client certificate", "FILE");
            opts.optopt("", "client-key", "Specify key for the client certificate", "FILE");
            opts.optflag("", "verify-hostname", "Performing server name verification.");

            let args: Vec<_> = env::args().collect();
            let m = match opts.parse(&args[1..]) {
                Ok(m) => m,
                Err(e) => return Err(format!("{}", e)),
            };

            if m.opt_present("help") {
                let brief = format!("{} [options]", args[0]);
                return Err(opts.usage(&brief));
            };

            let brokers = m.opt_str("brokers")
                .map(|s| {
                         s.split(',')
                             .map(|s| s.trim().to_owned())
                             .filter(|s| !s.is_empty())
                             .collect()
                     })
                .unwrap_or_else(|| vec!["localhost:9092".into()]);
            if brokers.is_empty() {
                return Err("Invalid --brokers specified!".to_owned());
            }

            Ok(Config {
                   brokers: brokers,
                   client_cert: m.opt_str("client-cert"),
                   client_key: m.opt_str("client-key"),
                   ca_cert: m.opt_str("ca-cert"),
                   verify_hostname: m.opt_present("verify-hostname"),
               })
        }
    }
}

#[cfg(not(feature = "security"))]
mod example {
    use std::process;

    pub fn main() {
        println!("example relevant only with the \"security\" feature enabled!");
        process::exit(1);
    }
}
<commit_msg>#122 Do perform hostname verification by default<commit_after>#[macro_use]
extern crate log;

fn main() {
    example::main();
}

#[cfg(feature = "security")]
mod example {
    extern crate openssl;
    extern crate kafka;
    extern crate getopts;
    extern crate env_logger;

    use std::env;
    use std::process;

    use self::kafka::client::{FetchOffset, KafkaClient, SecurityConfig};

    use self::openssl::ssl::{SslConnectorBuilder, SslMethod, SSL_VERIFY_PEER};
    use self::openssl::x509::X509_FILETYPE_PEM;

    pub fn main() {
        env_logger::init().unwrap();

        // ~ parse the command line arguments
        let cfg = match Config::from_cmdline() {
            Ok(cfg) => cfg,
            Err(e) => {
                println!("{}", e);
                process::exit(1);
            }
        };

        // ~ OpenSSL offers a variety of complex configurations. Here is an example:
        let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
        {
            let mut ctx = builder.builder_mut();
            ctx.set_cipher_list("DEFAULT").unwrap();
            ctx.set_verify(SSL_VERIFY_PEER);
            if let (Some(ccert), Some(ckey)) = (cfg.client_cert, cfg.client_key) {
                info!("loading cert-file={}, key-file={}", ccert, ckey);

                ctx.set_certificate_file(ccert, X509_FILETYPE_PEM)
                    .unwrap();
                ctx.set_private_key_file(ckey, X509_FILETYPE_PEM)
                    .unwrap();
                ctx.check_private_key().unwrap();
            }

            if let Some(ca_cert) = cfg.ca_cert {
                info!("loading ca-file={}", ca_cert);

                ctx.set_ca_file(ca_cert).unwrap();
            } else {
                // ~ allow client specify the CAs through the default paths:
                // "These locations are read from the SSL_CERT_FILE and
                // SSL_CERT_DIR environment variables if present, or defaults
                // specified at OpenSSL build time otherwise."
                ctx.set_default_verify_paths().unwrap();
            }
        }

        let connector = builder.build();

        // ~ instantiate KafkaClient with the previous OpenSSL setup
        let mut client =
            KafkaClient::new_secure(cfg.brokers,
                                    SecurityConfig::new(connector)
                                        .with_hostname_verification(cfg.verify_hostname));

        // ~ communicate with the brokers
        match client.load_metadata_all() {
            Err(e) => {
                println!("{:?}", e);
                drop(client);
                process::exit(1);
            }
            Ok(_) => {
                // ~ at this point we have successfully loaded
                // metadata via a secured connection to one of the
                // specified brokers

                if client.topics().len() == 0 {
                    println!("No topics available!");
                } else {
                    // ~ now let's communicate with all the brokers in
                    // the cluster our topics are spread over

                    let topics: Vec<String> = client.topics().names().map(Into::into).collect();
                    match client.fetch_offsets(topics.as_slice(), FetchOffset::Latest) {
                        Err(e) => {
                            println!("{:?}", e);
                            drop(client);
                            process::exit(1);
                        }
                        Ok(toffsets) => {
                            println!("Topic offsets:");
                            for (topic, mut offs) in toffsets {
                                offs.sort_by_key(|x| x.partition);
                                println!("{}", topic);
                                for off in offs {
                                    println!("\t{}: {:?}", off.partition, off.offset);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    struct Config {
        brokers: Vec<String>,
        client_cert: Option<String>,
        client_key: Option<String>,
        ca_cert: Option<String>,
        verify_hostname: bool,
    }

    impl Config {
        fn from_cmdline() -> Result<Config, String> {
            let mut opts = getopts::Options::new();
            opts.optflag("h", "help", "Print this help screen");
            opts.optopt("", "brokers", "Specify kafka brokers (comma separated)", "HOSTS");
            opts.optopt("", "ca-cert", "Specify the trusted CA certificates", "FILE");
            opts.optopt("", "client-cert", "Specify the client certificate", "FILE");
            opts.optopt("", "client-key", "Specify key for the client certificate", "FILE");
            opts.optflag("", "no-hostname-verification", "Do not perform server hostname verification (insecure!)");

            let args: Vec<_> = env::args().collect();
            let m = match opts.parse(&args[1..]) {
                Ok(m) => m,
                Err(e) => return Err(format!("{}", e)),
            };

            if m.opt_present("help") {
                let brief = format!("{} [options]", args[0]);
                return Err(opts.usage(&brief));
            };

            let brokers = m.opt_str("brokers")
                .map(|s| {
                         s.split(',')
                             .map(|s| s.trim().to_owned())
                             .filter(|s| !s.is_empty())
                             .collect()
                     })
                .unwrap_or_else(|| vec!["localhost:9092".into()]);
            if brokers.is_empty() {
                return Err("Invalid --brokers specified!".to_owned());
            }

            Ok(Config {
                   brokers: brokers,
                   client_cert: m.opt_str("client-cert"),
                   client_key: m.opt_str("client-key"),
                   ca_cert: m.opt_str("ca-cert"),
                   verify_hostname: !m.opt_present("no-hostname-verification"),
               })
        }
    }
}

#[cfg(not(feature = "security"))]
mod example {
    use std::process;

    pub fn main() {
        println!("example relevant only with the \"security\" feature enabled!");
        process::exit(1);
    }
}
<|endoftext|>


<commit_before>/* instruction.rs - Exposes a parsing object for a VR4300i instruction. */

use std::fmt;

use n64::cpu::CPU;
use n64::cpu::op::*;
use n64::cpu::GPR_NAMES;

pub struct Inst(pub u32);

impl Inst {
    /* Returns the instruction's opcode. */
    pub fn opcode(&self) -> u8 {
        return ((self.0 >> 26) & 0b111111) as u8;
    }

    /* The top-level opcode tuple. */
    fn op_tup_top(&self) -> &OpTup {
        return OP_TABLE[((self.opcode() >> 3) & 0b111) as usize][(self.opcode() & 0b111) as usize];
    }

    /* Returns the opcode's tuple. */
    fn op_tup(&self) -> &OpTup {
        let t = self.op_tup_top();
        match t.0 {
            Op::Special => {
                return SP_OP_TABLE[((self.funct() >> 3) & 0b111) as usize][(self.funct() & 0b111) as usize];
            }, Op::RegImm => {
                return RI_OP_TABLE[((self.rt() >> 3) & 0b11) as usize][(self.rt() & 0b111) as usize];
            }, Op::Cop0 => {
                let t = COP_OP_RS_TABLE[((self.rs() >> 3) & 0b11) as usize][(self.rs() & 0b111) as usize];
                match t.0 {
                    Op::Bc => {
                        /* If the instruction is Bc, we have to get the extended opcode from the RT table. */
                        return COP_OP_RT_TABLE[((self.rt() >> 3) & 0b11) as usize][(self.rt() & 0b111) as usize];
                    }, Op::Co => {
                        /* If the instruction is a Co instruction, then access it from the FN table. */
                        return COP_OP_FN_TABLE[((self.funct() >> 3) & 0b11) as usize][(self.funct() & 0b111) as usize];
                    }, _ => t
                }
            }, Op::Cop1 => {
                panic!("Attempt to resolve Cop1 instruction.")
            }, Op::Cop2 => {
                panic!("Attempt to resolve Cop2 instruction.")
            }, _ => t,
        }
    }

    /* Returns the kind of operation. */
    pub fn kind(&self) -> Op {
        return self.op_tup_top().0;
    }

    /* Returns the enumerated operation type. */
    pub fn op(&self) -> Op {
        return self.op_tup().0;
    }

    /* Returns a string of the opcode for debugging. */
    pub fn op_str(&self) -> String {
        let s = self.op_tup().1;
        match self.kind() {
            Op::Cop0 => {
                format!("{}c0", s)
            }, Op::Cop1 => {
                format!("{}c1", s)
            }, Op::Cop2 => {
                format!("{}c2", s)
            }, _ => s.to_owned()
        }
    }

    /* Returns the class of the opcode. */
    pub fn class(&self) -> OpC {
        return self.op_tup().2;
    }

    /* Returns the opcode's function. */
    pub fn function(&self) -> OpF {
        return self.op_tup().3;
    }

    /* Returns the instruction's source register. */
    pub fn rs(&self) -> usize {
        return ((self.0 >> 21) & 0b11111) as usize;
    }

    /* Returns the source register's value. */
    pub fn rsv(&self, cpu: &CPU) -> u64 {
        return cpu.rgpr(((self.0 >> 21) & 0b11111) as usize);
    }

    /* Returns the instruction's target register. */
    pub fn rt(&self) -> usize {
        return ((self.0 >> 16) & 0b11111) as usize;
    }

    /* Returns the target register's value. */
    pub fn rtv(&self, cpu: &CPU) -> u64 {
        return cpu.rgpr(((self.0 >> 16) & 0b11111) as usize);
    }

    /* Returns the instruciton's destination register. */
    pub fn rd(&self) -> usize {
        return ((self.0 >> 11) & 0b11111) as usize;
    }

    /* Writes the value to the destination register. */
    pub fn wrd(&self, cpu: &mut CPU, value: u64) {
        return cpu.wgpr(value, self.rd())
    }

    /* Returns the instruction's shift amount. */
    pub fn sa(&self) -> u16 {
        return ((self.0 >> 6) & 0b11111) as u16;
    }

    /* Returns the instruction's immediate value. */
    pub fn imm(&self) -> u16 {
        return (self.0 & 0xffff) as u16;
    }

    /* Return's the function's funct field. */
    pub fn funct(&self) -> u8 {
        return (self.0 & 0b111111) as u8;
    }

    /* The offset in a LD/ST instruction. */
    pub fn offset(&self) -> u16 {
        return (self.0 & 0xffff) as u16;
    }

    /* Returns the function's target. */
    pub fn target(&self) -> u64 {
        return (self.0 & 0x3ffffff) as u64;
    }
}

impl fmt::Display for Inst {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.class() {
            OpC::I => {
                write!(f, "{} {}, {}, {:#x}", self.op_str(), GPR_NAMES[self.rt()], GPR_NAMES[self.rs()], self.imm())
            }, OpC::L | OpC::S => {
                write!(f, "{} {}, {}({})", self.op_str(), GPR_NAMES[self.rt()], self.offset(), GPR_NAMES[self.rs()])
            }, OpC::J => {
                write!(f, "{} {:#x}\n", self.op_str(), self.target())
            }, OpC::B => {
                write!(f, "{} {}, {}, {}\n", self.op_str(), GPR_NAMES[self.rt()], GPR_NAMES[self.rs()], self.offset() as i16 as i64)
            }, OpC::R => {
                write!(f, "{} {}, {}, {}", self.op_str(), GPR_NAMES[self.rd()], GPR_NAMES[self.rt()], GPR_NAMES[self.rs()])
            }
        }
    }
}
<commit_msg>don't print an rs register for immediate instructions<commit_after>/* instruction.rs - Exposes a parsing object for a VR4300i instruction. */

use std::fmt;

use n64::cpu::CPU;
use n64::cpu::op::*;
use n64::cpu::GPR_NAMES;

pub struct Inst(pub u32);

impl Inst {
    /* Returns the instruction's opcode. */
    pub fn opcode(&self) -> u8 {
        return ((self.0 >> 26) & 0b111111) as u8;
    }

    /* The top-level opcode tuple. */
    fn op_tup_top(&self) -> &OpTup {
        return OP_TABLE[((self.opcode() >> 3) & 0b111) as usize][(self.opcode() & 0b111) as usize];
    }

    /* Returns the opcode's tuple. */
    fn op_tup(&self) -> &OpTup {
        let t = self.op_tup_top();
        match t.0 {
            Op::Special => {
                return SP_OP_TABLE[((self.funct() >> 3) & 0b111) as usize][(self.funct() & 0b111) as usize];
            }, Op::RegImm => {
                return RI_OP_TABLE[((self.rt() >> 3) & 0b11) as usize][(self.rt() & 0b111) as usize];
            }, Op::Cop0 => {
                let t = COP_OP_RS_TABLE[((self.rs() >> 3) & 0b11) as usize][(self.rs() & 0b111) as usize];
                match t.0 {
                    Op::Bc => {
                        /* If the instruction is Bc, we have to get the extended opcode from the RT table. */
                        return COP_OP_RT_TABLE[((self.rt() >> 3) & 0b11) as usize][(self.rt() & 0b111) as usize];
                    }, Op::Co => {
                        /* If the instruction is a Co instruction, then access it from the FN table. */
                        return COP_OP_FN_TABLE[((self.funct() >> 3) & 0b11) as usize][(self.funct() & 0b111) as usize];
                    }, _ => t
                }
            }, Op::Cop1 => {
                panic!("Attempt to resolve Cop1 instruction.")
            }, Op::Cop2 => {
                panic!("Attempt to resolve Cop2 instruction.")
            }, _ => t,
        }
    }

    /* Returns the kind of operation. */
    pub fn kind(&self) -> Op {
        return self.op_tup_top().0;
    }

    /* Returns the enumerated operation type. */
    pub fn op(&self) -> Op {
        return self.op_tup().0;
    }

    /* Returns a string of the opcode for debugging. */
    pub fn op_str(&self) -> String {
        let s = self.op_tup().1;
        match self.kind() {
            Op::Cop0 => {
                format!("{}c0", s)
            }, Op::Cop1 => {
                format!("{}c1", s)
            }, Op::Cop2 => {
                format!("{}c2", s)
            }, _ => s.to_owned()
        }
    }

    /* Returns the class of the opcode. */
    pub fn class(&self) -> OpC {
        return self.op_tup().2;
    }

    /* Returns the opcode's function. */
    pub fn function(&self) -> OpF {
        return self.op_tup().3;
    }

    /* Returns the instruction's source register. */
    pub fn rs(&self) -> usize {
        return ((self.0 >> 21) & 0b11111) as usize;
    }

    /* Returns the source register's value. */
    pub fn rsv(&self, cpu: &CPU) -> u64 {
        return cpu.rgpr(((self.0 >> 21) & 0b11111) as usize);
    }

    /* Returns the instruction's target register. */
    pub fn rt(&self) -> usize {
        return ((self.0 >> 16) & 0b11111) as usize;
    }

    /* Returns the target register's value. */
    pub fn rtv(&self, cpu: &CPU) -> u64 {
        return cpu.rgpr(((self.0 >> 16) & 0b11111) as usize);
    }

    /* Returns the instruciton's destination register. */
    pub fn rd(&self) -> usize {
        return ((self.0 >> 11) & 0b11111) as usize;
    }

    /* Writes the value to the destination register. */
    pub fn wrd(&self, cpu: &mut CPU, value: u64) {
        return cpu.wgpr(value, self.rd())
    }

    /* Returns the instruction's shift amount. */
    pub fn sa(&self) -> u16 {
        return ((self.0 >> 6) & 0b11111) as u16;
    }

    /* Returns the instruction's immediate value. */
    pub fn imm(&self) -> u16 {
        return (self.0 & 0xffff) as u16;
    }

    /* Return's the function's funct field. */
    pub fn funct(&self) -> u8 {
        return (self.0 & 0b111111) as u8;
    }

    /* The offset in a LD/ST instruction. */
    pub fn offset(&self) -> u16 {
        return (self.0 & 0xffff) as u16;
    }

    /* Returns the function's target. */
    pub fn target(&self) -> u64 {
        return (self.0 & 0x3ffffff) as u64;
    }
}

impl fmt::Display for Inst {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.class() {
            OpC::I => {
                write!(f, "{} {}, {:#x}", self.op_str(), GPR_NAMES[self.rt()], self.imm())
            }, OpC::L | OpC::S => {
                write!(f, "{} {}, {}({})", self.op_str(), GPR_NAMES[self.rt()], self.offset(), GPR_NAMES[self.rs()])
            }, OpC::J => {
                write!(f, "{} {:#x}\n", self.op_str(), self.target())
            }, OpC::B => {
                write!(f, "{} {}, {}, {}\n", self.op_str(), GPR_NAMES[self.rt()], GPR_NAMES[self.rs()], self.offset() as i16 as i64)
            }, OpC::R => {
                write!(f, "{} {}, {}, {}", self.op_str(), GPR_NAMES[self.rd()], GPR_NAMES[self.rt()], GPR_NAMES[self.rs()])
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(scoped)]
extern crate coroutine;
extern crate num_cpus;

use std::thread;

use coroutine::{spawn, sched};

fn main() {

    let mut threads = Vec::with_capacity(num_cpus::get());

    for i in 0..num_cpus::get() {
        let t = thread::scoped(move|| {
            spawn(move|| {
                let thread_id = i;
                spawn(move|| {
                    for count in 0..10 {
                        println!("Coroutine running in thread {}: counting {}", thread_id, count);
                        sched();
                    }
                }).join().ok().expect("Failed to join");
            }).join().ok().expect("Failed to join");
        });
        threads.push(t);
    }

    for t in threads.into_iter() {
        t.join();
    }
}
<commit_msg>remove usage of thread::scoped<commit_after>extern crate coroutine;
extern crate num_cpus;

use std::thread;

use coroutine::{spawn, sched};

fn main() {

    let mut threads = Vec::with_capacity(num_cpus::get());

    for i in 0..num_cpus::get() {
        let t = thread::spawn(move|| {
            spawn(move|| {
                let thread_id = i;
                spawn(move|| {
                    for count in 0..10 {
                        println!("Coroutine running in thread {}: counting {}", thread_id, count);
                        sched();
                    }
                }).join().ok().expect("Failed to join");
            }).join().ok().expect("Failed to join");
        });
        threads.push(t);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::mem::size_of;
use std::slice::{from_raw_parts, from_raw_parts_mut};

/// Types for which it is safe to initialize from raw data.
///
/// A type `T` is `DataInit` if and only if it can be initialized by reading its contents from a
/// byte array.  This is generally true for all plain-old-data structs.  It is notably not true for
/// any type that includes a reference.
///
/// Implementing this trait guarantees that it is safe to instantiate the struct with random data.
pub unsafe trait DataInit: Copy + Send + Sync {
    /// Converts a slice of raw data into a reference of `Self`.
    ///
    /// The value of `data` is not copied. Instead a reference is made from the given slice. The
    /// value of `Self` will depend on the representation of the type in memory, and may change in
    /// an unstable fashion.
    ///
    /// This will return `None` if the length of data does not match the size of `Self`.
    fn from_slice(data: &[u8]) -> Option<&Self> {
        if data.len() == size_of::<Self>() {
            // Safe because the DataInit trait asserts any data is valid for this type, and we
            // ensured the size of the pointer's buffer is the correct size. This aliases a pointer,
            // but because the pointer is from a const slice reference, there are no mutable
            // aliases. Finally, the reference returned can not outlive data because they have equal
            // implicit lifetime constraints.
            Some(unsafe { &*(data.as_ptr() as *const Self) })
        } else {
            None
        }
    }

    /// Converts a mutable slice of raw data into a mutable reference of `Self`.
    ///
    /// Because `Self` is made from a reference to the mutable slice`, mutations to the returned
    /// reference are immediately reflected in `data`. The value of the returned `Self` will depend
    /// on the representation of the type in memory, and may change in an unstable fashion.
    ///
    /// This will return `None` if the length of data does not match the size of `Self`.
    fn from_mut_slice(data: &mut [u8]) -> Option<&mut Self> {
        if data.len() == size_of::<Self>() {
            // Safe because the DataInit trait asserts any data is valid for this type, and we
            // ensured the size of the pointer's buffer is the correct size. This aliases a pointer,
            // but because the pointer is from a const slice reference, there are no mutable
            // aliases. Finally, the reference returned can not outlive data because they have equal
            // implicit lifetime constraints.
            Some(unsafe { &mut *(data.as_mut_ptr() as *mut Self) })
        } else {
            None
        }
    }

    /// Converts a reference to `self` into a slice of bytes.
    ///
    /// The value of `self` is not copied. Instead, the slice is made from a reference to `self`.
    /// The value of bytes in the returned slice will depend on the representation of the type in
    /// memory, and may change in an unstable fashion.
    fn as_slice(&self) -> &[u8] {
        // Safe because the entire size of self is accessible as bytes because the trait guarantees
        // it. The lifetime of the returned slice is the same as the passed reference, so that no
        // dangling pointers will result from this pointer alias.
        unsafe { from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
    }

    /// Converts a mutable reference to `self` into a mutable slice of bytes.
    ///
    /// Because the slice is made from a reference to `self`, mutations to the returned slice are
    /// immediately reflected in `self`. The value of bytes in the returned slice will depend on
    /// the representation of the type in memory, and may change in an unstable fashion.
    fn as_mut_slice(&mut self) -> &mut [u8] {
        // Safe because the entire size of self is accessible as bytes because the trait guarantees
        // it. The trait also guarantees that any combination of bytes is valid for this type, so
        // modifying them in the form of a byte slice is valid. The lifetime of the returned slice
        // is the same as the passed reference, so that no dangling pointers will result from this
        // pointer alias. Although this does alias a mutable pointer, we do so by exclusively
        // borrowing the given mutable reference.
        unsafe { from_raw_parts_mut(self as *mut Self as *mut u8, size_of::<Self>()) }
    }
}

// All intrinsic types and arays of intrinsic types are DataInit.  They are just numbers.
macro_rules! array_data_init {
    ($T:ty, $($N:expr)+) => {
        $(
            unsafe impl DataInit for [$T; $N] {}
        )+
    }
}
macro_rules! data_init_type {
    ($T:ty) => {
        unsafe impl DataInit for $T {}
        array_data_init! {
            $T,
            0  1  2  3  4  5  6  7  8  9
            10 11 12 13 14 15 16 17 18 19
            20 21 22 23 24 25 26 27 28 29
            30 31 32
        }
    };
}
data_init_type!(u8);
data_init_type!(u16);
data_init_type!(u32);
data_init_type!(u64);
data_init_type!(usize);
data_init_type!(i8);
data_init_type!(i16);
data_init_type!(i32);
data_init_type!(i64);
data_init_type!(isize);

pub mod endian;
pub use endian::*;

pub mod volatile_memory;
pub use volatile_memory::*;
<commit_msg>data_model: prevent unaligned DataInit::from_slice<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::mem::size_of;
use std::slice::{from_raw_parts, from_raw_parts_mut};

/// Types for which it is safe to initialize from raw data.
///
/// A type `T` is `DataInit` if and only if it can be initialized by reading its contents from a
/// byte array.  This is generally true for all plain-old-data structs.  It is notably not true for
/// any type that includes a reference.
///
/// Implementing this trait guarantees that it is safe to instantiate the struct with random data.
pub unsafe trait DataInit: Copy + Send + Sync {
    /// Converts a slice of raw data into a reference of `Self`.
    ///
    /// The value of `data` is not copied. Instead a reference is made from the given slice. The
    /// value of `Self` will depend on the representation of the type in memory, and may change in
    /// an unstable fashion.
    ///
    /// This will return `None` if the length of data does not match the size of `Self`, or if the
    /// data is not aligned for the type of `Self`.
    fn from_slice(data: &[u8]) -> Option<&Self> {
        // Early out to avoid an unneeded `align_to` call.
        if data.len() != size_of::<Self>() {
            return None;
        }

        // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
        // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
        // we don't have any unaligned references. This aliases a pointer, but because the pointer
        // is from a const slice reference, there are no mutable aliases. Finally, the reference
        // returned can not outlive data because they have equal implicit lifetime constraints.
        match unsafe { data.align_to::<Self>() } {
            ([], [mid], []) => Some(mid),
            _ => None,
        }
    }

    /// Converts a mutable slice of raw data into a mutable reference of `Self`.
    ///
    /// Because `Self` is made from a reference to the mutable slice`, mutations to the returned
    /// reference are immediately reflected in `data`. The value of the returned `Self` will depend
    /// on the representation of the type in memory, and may change in an unstable fashion.
    ///
    /// This will return `None` if the length of data does not match the size of `Self`, or if the
    /// data is not aligned for the type of `Self`.
    fn from_mut_slice(data: &mut [u8]) -> Option<&mut Self> {
        // Early out to avoid an unneeded `align_to_mut` call.
        if data.len() != size_of::<Self>() {
            return None;
        }

        // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
        // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
        // we don't have any unaligned references. This aliases a pointer, but because the pointer
        // is from a mut slice reference, we borrow the passed in mutable reference. Finally, the
        // reference returned can not outlive data because they have equal implicit lifetime
        // constraints.
        match unsafe { data.align_to_mut::<Self>() } {
            ([], [mid], []) => Some(mid),
            _ => None,
        }
    }

    /// Converts a reference to `self` into a slice of bytes.
    ///
    /// The value of `self` is not copied. Instead, the slice is made from a reference to `self`.
    /// The value of bytes in the returned slice will depend on the representation of the type in
    /// memory, and may change in an unstable fashion.
    fn as_slice(&self) -> &[u8] {
        // Safe because the entire size of self is accessible as bytes because the trait guarantees
        // it. The lifetime of the returned slice is the same as the passed reference, so that no
        // dangling pointers will result from this pointer alias.
        unsafe { from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
    }

    /// Converts a mutable reference to `self` into a mutable slice of bytes.
    ///
    /// Because the slice is made from a reference to `self`, mutations to the returned slice are
    /// immediately reflected in `self`. The value of bytes in the returned slice will depend on
    /// the representation of the type in memory, and may change in an unstable fashion.
    fn as_mut_slice(&mut self) -> &mut [u8] {
        // Safe because the entire size of self is accessible as bytes because the trait guarantees
        // it. The trait also guarantees that any combination of bytes is valid for this type, so
        // modifying them in the form of a byte slice is valid. The lifetime of the returned slice
        // is the same as the passed reference, so that no dangling pointers will result from this
        // pointer alias. Although this does alias a mutable pointer, we do so by exclusively
        // borrowing the given mutable reference.
        unsafe { from_raw_parts_mut(self as *mut Self as *mut u8, size_of::<Self>()) }
    }
}

// All intrinsic types and arays of intrinsic types are DataInit.  They are just numbers.
macro_rules! array_data_init {
    ($T:ty, $($N:expr)+) => {
        $(
            unsafe impl DataInit for [$T; $N] {}
        )+
    }
}
macro_rules! data_init_type {
    ($($T:ident),*) => {
        $(
            unsafe impl DataInit for $T {}
            array_data_init! {
                $T,
                0  1  2  3  4  5  6  7  8  9
                10 11 12 13 14 15 16 17 18 19
                20 21 22 23 24 25 26 27 28 29
                30 31 32
            }
        )*
        #[cfg(test)]
        mod data_init_tests {
            use std::mem::{size_of, align_of};
            use DataInit;

            #[test]
            fn from_slice_alignment() {
                let mut v = [0u8; 32];
                $(
                    let pre_len =  {
                        let (pre, _, _) = unsafe { v.align_to::<$T>() };
                        pre.len()
                    };
                    {
                        let aligned_v = &mut v[pre_len..pre_len + size_of::<$T>()];
                        {
                            let from_aligned = $T::from_slice(aligned_v);
                            assert_eq!(from_aligned, Some(&0));
                        }
                        {
                            let from_aligned_mut = $T::from_mut_slice(aligned_v);
                            assert_eq!(from_aligned_mut, Some(&mut 0));
                        }
                    }
                    for i in 1..size_of::<$T>() {
                        let begin = pre_len + i;
                        let end = begin + size_of::<$T>();
                        let unaligned_v = &mut v[begin..end];
                        {
                            let from_unaligned = $T::from_slice(unaligned_v);
                            if align_of::<$T>() != 1 {
                                assert_eq!(from_unaligned, None);
                            }
                        }
                        {
                            let from_unaligned_mut = $T::from_mut_slice(unaligned_v);
                            if align_of::<$T>() != 1 {
                                assert_eq!(from_unaligned_mut, None);
                            }
                        }
                    }
                )*

            }
        }
    };
}
data_init_type!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);

pub mod endian;
pub use endian::*;

pub mod volatile_memory;
pub use volatile_memory::*;
<|endoftext|>