<commit_before>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod extra;

use extra::enum_set::{EnumSet};
use std::c_str::{CString};
use std::libc::{c_int, c_char, c_void, c_uchar};
use std::ptr;
use std::result::{Result};

mod native;

pub type compile_options = c_int;
pub type exec_options = c_int;
pub type fullinfo_field = c_int;
pub struct pcre;
pub type pcre_error = c_int;
pub struct pcre_extra;
pub type study_options = c_int;

pub static PCRE_UTF8: c_int = 0x00000800;
pub static PCRE_NO_UTF8_CHECK: c_int = 0x00002000;

pub static PCRE_ERROR_NOMATCH: pcre_error = -1;
pub static PCRE_ERROR_NULL: pcre_error = -2;

pub static PCRE_INFO_OPTIONS: fullinfo_field = 0;
pub static PCRE_INFO_SIZE: fullinfo_field = 1;
pub static PCRE_INFO_CAPTURECOUNT: fullinfo_field = 2;
pub static PCRE_INFO_BACKREFMAX: fullinfo_field = 3;
pub static PCRE_INFO_FIRSTBYTE: fullinfo_field = 4;
pub static PCRE_INFO_FIRSTCHAR: fullinfo_field = 4;
pub static PCRE_INFO_FIRSTTABLE: fullinfo_field = 5;
pub static PCRE_INFO_LASTLITERAL: fullinfo_field = 6;
pub static PCRE_INFO_NAMEENTRYSIZE: fullinfo_field = 7;
pub static PCRE_INFO_NAMECOUNT: fullinfo_field = 8;
pub static PCRE_INFO_NAMETABLE: fullinfo_field = 9;
pub static PCRE_INFO_STUDYSIZE: fullinfo_field = 10;
pub static PCRE_INFO_DEFAULT_TABLES: fullinfo_field = 11;
pub static PCRE_INFO_OKPARTIAL: fullinfo_field = 12;
pub static PCRE_INFO_JCHANGED: fullinfo_field = 13;
pub static PCRE_INFO_HASCRORLF: fullinfo_field = 14;
pub static PCRE_INFO_MINLENGTH: fullinfo_field = 15;
pub static PCRE_INFO_JIT: fullinfo_field = 16;
pub static PCRE_INFO_JITSIZE: fullinfo_field = 17;
pub static PCRE_INFO_MAXLOOKBEHIND: fullinfo_field = 18;
pub static PCRE_INFO_FIRSTCHARACTER: fullinfo_field = 19;
pub static PCRE_INFO_FIRSTCHARACTERFLAGS: fullinfo_field = 20;
pub static PCRE_INFO_REQUIREDCHAR: fullinfo_field = 21;
pub static PCRE_INFO_REQUIREDCHARFLAGS: fullinfo_field = 22;
pub static PCRE_INFO_MATCHLIMIT: fullinfo_field = 23;
pub static PCRE_INFO_RECURSIONLIMIT: fullinfo_field = 24;

pub unsafe fn pcre_compile(pattern: *c_char, options: &EnumSet<::CompileOption>, tableptr: *c_uchar) -> Result<*mut pcre, (Option<~str>, c_int)> {
    assert!(ptr::is_not_null(pattern));
    let converted_options = options.iter().fold(0, |converted_options, option| converted_options | (option as compile_options)) | PCRE_UTF8 | PCRE_NO_UTF8_CHECK;
    let mut err: *c_char = ptr::null();
    let mut erroffset: c_int = 0;
    let code = native::pcre_compile(pattern, converted_options, &mut err, &mut erroffset, tableptr);

    if ptr::is_null(code) {
        // "Otherwise, if  compilation  of  a  pattern fails, pcre_compile() returns
        // NULL, and sets the variable pointed to by errptr to point to a textual
        // error message. This is a static string that is part of the library. You
        // must not try to free it."
        // http://pcre.org/pcre.txt
        let err_cstring = CString::new(err, false);

        match err_cstring.as_str() {
            None => Err((None, erroffset)),
            Some(err_str) => Err((Some(err_str.to_owned()), erroffset))
        }
    } else {
        assert!(ptr::is_not_null(code));
        assert_eq!(erroffset, 0);

        Ok(code)
    }
}

pub unsafe fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: &EnumSet<::ExecOption>, ovector: *mut c_int, ovecsize: c_int) -> c_int {
    assert!(ptr::is_not_null(code));
    assert!(ovecsize >= 0 && ovecsize % 3 == 0);
    let converted_options = options.iter().fold(0, |converted_options, option| converted_options | (option as compile_options)) | PCRE_NO_UTF8_CHECK;
    let rc = native::pcre_exec(code, extra, subject, length, startoffset, converted_options, ovector, ovecsize);
    if rc == PCRE_ERROR_NOMATCH {
        return -1;
    } else if rc < 0 && rc != PCRE_ERROR_NULL {
        fail!("pcre_exec");
    }

    rc
}

pub unsafe fn pcre_free(ptr: *mut c_void) {
    native::pcre_free(ptr);
}

pub unsafe fn pcre_free_study(extra: *mut pcre_extra) {
    native::pcre_free_study(extra);
}

pub unsafe fn pcre_fullinfo(code: *pcre, extra: *pcre_extra, what: fullinfo_field, where: *mut c_void) {
    assert!(ptr::is_not_null(code));
    let rc = native::pcre_fullinfo(code, extra, what, where);
    if rc < 0 && rc != PCRE_ERROR_NULL {
        fail!("pcre_fullinfo");
    }
}

pub unsafe fn pcre_refcount(code: *mut ::detail::pcre, adjust: c_int) -> c_int {
    assert!(ptr::is_not_null(code));
    let curr_refcount = native::pcre_refcount(code, 0);
    if curr_refcount + adjust < 0 {
        fail!("refcount underflow");
    } else if curr_refcount + adjust > 65535 {
        fail!("refcount overflow");
    }
    native::pcre_refcount(code, adjust)
}

pub unsafe fn pcre_study(code: *::detail::pcre, options: &EnumSet<::StudyOption>) -> *mut ::detail::pcre_extra {
    assert!(ptr::is_not_null(code));
    let converted_options = options.iter().fold(0, |converted_options, option| converted_options | (option as study_options));
    let mut err: *c_char = ptr::null();
    let extra = native::pcre_study(code, converted_options, &mut err);
    // "The third argument for pcre_study() is a pointer for an error message. If
    // studying succeeds (even if no data is returned), the variable it points to is
    // set to NULL. Otherwise it is set to point to a textual error message. This is
    // a static string that is part of the library. You must not try to free it."
    // http://pcre.org/pcre.txt
    if ptr::is_not_null(err) {
        let err_cstring = CString::new(err, false);
        match err_cstring.as_str() {
            None          => error!("pcre_study() failed"),
            Some(err_str) => error!("pcre_study() failed: {}", err_str)
        }
        fail!("pcre_study");
    }
    assert!(ptr::is_null(err));

    extra
}

pub fn pcre_version() -> ~str {
    let version_cstring = unsafe { CString::new(native::pcre_version(), false) };
    version_cstring.as_str().unwrap().to_owned()
}
<commit_msg>Fix dead code warnings<commit_after>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod extra;

use extra::enum_set::{EnumSet};
use std::c_str::{CString};
use std::libc::{c_int, c_char, c_void, c_uchar};
use std::ptr;
use std::result::{Result};

mod native;

pub type compile_options = c_int;
pub type exec_options = c_int;
pub type fullinfo_field = c_int;
pub struct pcre;
pub type pcre_error = c_int;
pub struct pcre_extra;
pub type study_options = c_int;

pub static PCRE_UTF8: c_int = 0x00000800;
pub static PCRE_NO_UTF8_CHECK: c_int = 0x00002000;

pub static PCRE_ERROR_NOMATCH: pcre_error = -1;
pub static PCRE_ERROR_NULL: pcre_error = -2;

pub static PCRE_INFO_CAPTURECOUNT: fullinfo_field = 2;
pub static PCRE_INFO_NAMEENTRYSIZE: fullinfo_field = 7;
pub static PCRE_INFO_NAMECOUNT: fullinfo_field = 8;
pub static PCRE_INFO_NAMETABLE: fullinfo_field = 9;

pub unsafe fn pcre_compile(pattern: *c_char, options: &EnumSet<::CompileOption>, tableptr: *c_uchar) -> Result<*mut pcre, (Option<~str>, c_int)> {
    assert!(ptr::is_not_null(pattern));
    let converted_options = options.iter().fold(0, |converted_options, option| converted_options | (option as compile_options)) | PCRE_UTF8 | PCRE_NO_UTF8_CHECK;
    let mut err: *c_char = ptr::null();
    let mut erroffset: c_int = 0;
    let code = native::pcre_compile(pattern, converted_options, &mut err, &mut erroffset, tableptr);

    if ptr::is_null(code) {
        // "Otherwise, if  compilation  of  a  pattern fails, pcre_compile() returns
        // NULL, and sets the variable pointed to by errptr to point to a textual
        // error message. This is a static string that is part of the library. You
        // must not try to free it."
        // http://pcre.org/pcre.txt
        let err_cstring = CString::new(err, false);

        match err_cstring.as_str() {
            None => Err((None, erroffset)),
            Some(err_str) => Err((Some(err_str.to_owned()), erroffset))
        }
    } else {
        assert!(ptr::is_not_null(code));
        assert_eq!(erroffset, 0);

        Ok(code)
    }
}

pub unsafe fn pcre_exec(code: *pcre, extra: *pcre_extra, subject: *c_char, length: c_int, startoffset: c_int, options: &EnumSet<::ExecOption>, ovector: *mut c_int, ovecsize: c_int) -> c_int {
    assert!(ptr::is_not_null(code));
    assert!(ovecsize >= 0 && ovecsize % 3 == 0);
    let converted_options = options.iter().fold(0, |converted_options, option| converted_options | (option as compile_options)) | PCRE_NO_UTF8_CHECK;
    let rc = native::pcre_exec(code, extra, subject, length, startoffset, converted_options, ovector, ovecsize);
    if rc == PCRE_ERROR_NOMATCH {
        return -1;
    } else if rc < 0 && rc != PCRE_ERROR_NULL {
        fail!("pcre_exec");
    }

    rc
}

pub unsafe fn pcre_free(ptr: *mut c_void) {
    native::pcre_free(ptr);
}

pub unsafe fn pcre_free_study(extra: *mut pcre_extra) {
    native::pcre_free_study(extra);
}

pub unsafe fn pcre_fullinfo(code: *pcre, extra: *pcre_extra, what: fullinfo_field, where: *mut c_void) {
    assert!(ptr::is_not_null(code));
    let rc = native::pcre_fullinfo(code, extra, what, where);
    if rc < 0 && rc != PCRE_ERROR_NULL {
        fail!("pcre_fullinfo");
    }
}

pub unsafe fn pcre_refcount(code: *mut ::detail::pcre, adjust: c_int) -> c_int {
    assert!(ptr::is_not_null(code));
    let curr_refcount = native::pcre_refcount(code, 0);
    if curr_refcount + adjust < 0 {
        fail!("refcount underflow");
    } else if curr_refcount + adjust > 65535 {
        fail!("refcount overflow");
    }
    native::pcre_refcount(code, adjust)
}

pub unsafe fn pcre_study(code: *::detail::pcre, options: &EnumSet<::StudyOption>) -> *mut ::detail::pcre_extra {
    assert!(ptr::is_not_null(code));
    let converted_options = options.iter().fold(0, |converted_options, option| converted_options | (option as study_options));
    let mut err: *c_char = ptr::null();
    let extra = native::pcre_study(code, converted_options, &mut err);
    // "The third argument for pcre_study() is a pointer for an error message. If
    // studying succeeds (even if no data is returned), the variable it points to is
    // set to NULL. Otherwise it is set to point to a textual error message. This is
    // a static string that is part of the library. You must not try to free it."
    // http://pcre.org/pcre.txt
    if ptr::is_not_null(err) {
        let err_cstring = CString::new(err, false);
        match err_cstring.as_str() {
            None          => error!("pcre_study() failed"),
            Some(err_str) => error!("pcre_study() failed: {}", err_str)
        }
        fail!("pcre_study");
    }
    assert!(ptr::is_null(err));

    extra
}

pub fn pcre_version() -> ~str {
    let version_cstring = unsafe { CString::new(native::pcre_version(), false) };
    version_cstring.as_str().unwrap().to_owned()
}
<|endoftext|>


<commit_before>use core::intrinsics::{breakpoint, volatile_load, volatile_store};
use core::mem;
use core::raw;

use common::{RingBuffer, Queue};

#[allow(improper_ctypes)]
extern {
    pub fn switch_to_user(user_stack: *mut u8, mem_base: *mut u8) -> *mut u8;
}

/// Size of each processes's memory region in bytes
pub const PROC_MEMORY_SIZE : usize = 8192;
pub const NUM_PROCS : usize = 1;

static mut FREE_MEMORY_IDX: usize = 0;

#[link_section = ".app_memory"]
static mut MEMORIES: [[u8; PROC_MEMORY_SIZE]; NUM_PROCS] = [[0; PROC_MEMORY_SIZE]; NUM_PROCS];

pub static mut PROCS : [Option<Process<'static>>; NUM_PROCS] = [None];

pub fn schedule(callback: Callback, appid: ::AppId) -> bool {
    let procs = unsafe { &mut PROCS };
    let idx = appid.idx();
    if idx >= procs.len() {
        return false
    }

    match procs[idx] {
        None => false,
        Some(ref mut p) => {
            // TODO(alevy): validate appid liveness
            p.callbacks.enqueue(callback)
        }
    }
}

#[derive(Copy,Clone,PartialEq,Eq)]
pub enum State {
    Running,
    Waiting
}

#[derive(Copy,Clone)]
pub struct Callback {
    pub r0: usize,
    pub r1: usize,
    pub r2: usize,
    pub r3: usize,
    pub pc: usize
}

#[repr(C,packed)]
struct LoadInfo {
    entry_loc: usize,        /* Entry point for user application */
    init_data_loc: usize,    /* Data initialization information in flash */
    init_data_size: usize,    /* Size of initialization information */
    got_start_offset: usize,  /* Offset to start of GOT */
    got_end_offset: usize,    /* Offset to end of GOT */
    bss_start_offset: usize,  /* Offset to start of BSS */
    bss_end_offset: usize    /* Offset to end of BSS */
}

pub struct Process<'a> {
    /// The process's memory.
    memory: &'a mut [u8],

    exposed_memory_start: *mut u8,

    /// The offset in `memory` to use for the process stack.
    cur_stack: *mut u8,

    wait_pc: usize,

    pub state: State,

    pub callbacks: RingBuffer<'a, Callback>
}

impl<'a> Process<'a> {
    pub unsafe fn create(start_addr: *const usize) -> Option<Process<'a>> {
        let cur_idx = FREE_MEMORY_IDX;
        if cur_idx <= MEMORIES.len() {
            FREE_MEMORY_IDX += 1;
            let memory = &mut MEMORIES[cur_idx];

            let stack_bottom = &mut memory[PROC_MEMORY_SIZE - 4] as *mut u8;

            // Take callback buffer from bottom of process memory
            let callback_len = 10;
            let callback_buf = mem::transmute(raw::Slice {
                data: &mut memory[0] as *mut u8 as *mut Option<Callback>,
                len: callback_len
            });
            let callback_size = mem::size_of::<Option<Callback>>();

            let callbacks = RingBuffer::new(callback_buf);

            let exposed_memory_start =
                    &mut memory[callback_len * callback_size] as *mut u8;

            let mut result = Process {
                memory: memory,
                exposed_memory_start: exposed_memory_start,
                cur_stack: stack_bottom as *mut u8,
                wait_pc: 0,
                state: State::Waiting,
                callbacks: callbacks
            };

            result.load(start_addr);

            Some(result)
        } else {
            None
        }
    }

    unsafe fn load(&mut self, start_addr: *const usize) {
        let load_info : &LoadInfo = mem::transmute(start_addr);
        let exposed_memory_start = self.exposed_memory_start;

        // Zero out BSS
        ::core::intrinsics::write_bytes(
            exposed_memory_start.offset(load_info.bss_start_offset as isize),
            0,
            load_info.bss_end_offset - load_info.bss_start_offset);

        // Copy data into Data section
        let init_data : &[u8] = mem::transmute(raw::Slice{
            data: (load_info.init_data_loc + start_addr as usize) as *mut u8,
            len: load_info.init_data_size
        });

        let target_data : &mut [u8] = mem::transmute(raw::Slice{
            data: exposed_memory_start,
            len: load_info.init_data_size
        });

        target_data.clone_from_slice(init_data);

        // Fixup Global Offset Table
        let mut got_cur = exposed_memory_start.offset(load_info.got_start_offset as isize) as *mut usize;
        let got_end = exposed_memory_start.offset(load_info.got_end_offset as isize) as *mut usize;
        while got_cur != got_end {
            let entry = *got_cur;
            if (entry & 0x80000000) == 0 {
                // Regular data (memory relative)
                *got_cur = entry + (exposed_memory_start as usize);
            } else {
                // rodata or function pointer (code relative)
                *got_cur = (entry ^ 0x80000000) + (start_addr as usize);
            }
            got_cur = got_cur.offset(1);
        }

        // Entry point is offset from app code
        let init_fn = start_addr as usize + load_info.entry_loc;

        let heap_start = exposed_memory_start.offset(load_info.init_data_size as isize);

        self.callbacks.enqueue(Callback {
            pc: init_fn as usize,
            r0: heap_start as usize,
            r1: 0,
            r2: 0,
            r3: 0
        });
    }

    pub fn in_exposed_bounds(&self, buf_start_addr: *const u8, size: usize)
            -> bool {
        use core::raw::Repr;

        let buf_end_addr = ((buf_start_addr as usize) + size) as *const u8;

        let mem = self.memory.repr();
        let mem_end = ((mem.data as usize) + mem.len) as *const u8;

        buf_start_addr >= self.exposed_memory_start && buf_end_addr <= mem_end
    }

    pub unsafe fn alloc(&mut self, size: usize) -> Option<&mut [u8]> {
        use core::raw::Slice;

        let mem_len = self.memory.len();
        let end_mem = &mut self.memory[mem_len - 1] as *mut u8;
        let new_start = self.exposed_memory_start.offset(size as isize);
        if new_start >= end_mem {
            None
        } else {
            let buf = Slice {
                data: self.exposed_memory_start,
                len: size
            };
            self.exposed_memory_start = new_start;
            Some(mem::transmute(buf))
        }
    }

    pub unsafe fn free<T>(&mut self, _: *mut T) {}

    pub fn pop_syscall_stack(&mut self) {
        let pspr = self.cur_stack as *const usize;
        unsafe {
            self.wait_pc = volatile_load(pspr.offset(6));
            self.cur_stack =
                (self.cur_stack as *mut usize).offset(8) as *mut u8;
        }
    }

    /// Context switch to the process.
    pub unsafe fn switch_to_callback(&mut self, callback: Callback) {
        // Fill in initial stack expected by SVC handler
        // Top minus 8 u32s for r0-r3, r12, lr, pc and xPSR
        let stack_bottom = (self.cur_stack as *mut usize).offset(-8);
        volatile_store(stack_bottom.offset(7), 0x01000000);
        volatile_store(stack_bottom.offset(6), callback.pc | 1);
        // Set the LR register to the saved PC so the callback returns to
        // wherever wait was called. Set lowest bit to one because of THUMB
        // instruction requirements.
        volatile_store(stack_bottom.offset(5), self.wait_pc | 0x1);
        volatile_store(stack_bottom, callback.r0);
        volatile_store(stack_bottom.offset(1), callback.r1);
        volatile_store(stack_bottom.offset(2), callback.r2);
        volatile_store(stack_bottom.offset(3), callback.r3);

        self.cur_stack = stack_bottom as *mut u8;
        self.switch_to();
    }

    /// Context switch to the process.
    pub unsafe fn switch_to(&mut self) {
        if self.cur_stack < self.exposed_memory_start {
            breakpoint();
        }
        let psp = switch_to_user(self.cur_stack, self.exposed_memory_start);
        self.cur_stack = psp;
    }

    pub fn svc_number(&self) -> Option<u8> {
        let psp = self.cur_stack as *const *const u16;
        unsafe {
            let pcptr = volatile_load((psp as *const *const u16).offset(6));
            let svc_instr = volatile_load(pcptr.offset(-1));
            Some((svc_instr & 0xff) as u8)
        }
    }

    pub fn lr(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(5)) }
    }

    pub fn r0(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr) }
    }

    pub fn set_r0(&mut self, val: isize) {
        let pspr = self.cur_stack as *mut isize;
        unsafe { volatile_store(pspr, val) }
    }

    pub fn r1(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(1)) }
    }

    pub fn r2(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(2)) }
    }

    pub fn r3(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(3)) }
    }

}

<commit_msg>Fixed subtle but bad bug in app loader<commit_after>use core::intrinsics::{breakpoint, volatile_load, volatile_store};
use core::mem;
use core::raw;

use common::{RingBuffer, Queue};

#[allow(improper_ctypes)]
extern {
    pub fn switch_to_user(user_stack: *mut u8, mem_base: *mut u8) -> *mut u8;
}

/// Size of each processes's memory region in bytes
pub const PROC_MEMORY_SIZE : usize = 8192;
pub const NUM_PROCS : usize = 1;

static mut FREE_MEMORY_IDX: usize = 0;

#[link_section = ".app_memory"]
static mut MEMORIES: [[u8; PROC_MEMORY_SIZE]; NUM_PROCS] = [[0; PROC_MEMORY_SIZE]; NUM_PROCS];

pub static mut PROCS : [Option<Process<'static>>; NUM_PROCS] = [None];

pub fn schedule(callback: Callback, appid: ::AppId) -> bool {
    let procs = unsafe { &mut PROCS };
    let idx = appid.idx();
    if idx >= procs.len() {
        return false
    }

    match procs[idx] {
        None => false,
        Some(ref mut p) => {
            // TODO(alevy): validate appid liveness
            p.callbacks.enqueue(callback)
        }
    }
}

#[derive(Copy,Clone,PartialEq,Eq)]
pub enum State {
    Running,
    Waiting
}

#[derive(Copy,Clone)]
pub struct Callback {
    pub r0: usize,
    pub r1: usize,
    pub r2: usize,
    pub r3: usize,
    pub pc: usize
}

#[repr(C,packed)]
struct LoadInfo {
    entry_loc: usize,        /* Entry point for user application */
    init_data_loc: usize,    /* Data initialization information in flash */
    init_data_size: usize,    /* Size of initialization information */
    got_start_offset: usize,  /* Offset to start of GOT */
    got_end_offset: usize,    /* Offset to end of GOT */
    bss_start_offset: usize,  /* Offset to start of BSS */
    bss_end_offset: usize    /* Offset to end of BSS */
}

pub struct Process<'a> {
    /// The process's memory.
    memory: &'a mut [u8],

    exposed_memory_start: *mut u8,

    /// The offset in `memory` to use for the process stack.
    cur_stack: *mut u8,

    wait_pc: usize,

    pub state: State,

    pub callbacks: RingBuffer<'a, Callback>
}

impl<'a> Process<'a> {
    pub unsafe fn create(start_addr: *const usize) -> Option<Process<'a>> {
        let cur_idx = FREE_MEMORY_IDX;
        if cur_idx <= MEMORIES.len() {
            FREE_MEMORY_IDX += 1;
            let memory = &mut MEMORIES[cur_idx];

            let stack_bottom = &mut memory[PROC_MEMORY_SIZE - 4] as *mut u8;

            // Take callback buffer from bottom of process memory
            let callback_len = 10;
            let callback_buf = mem::transmute(raw::Slice {
                data: &mut memory[0] as *mut u8 as *mut Option<Callback>,
                len: callback_len
            });
            let callback_size = mem::size_of::<Option<Callback>>();

            let callbacks = RingBuffer::new(callback_buf);

            let exposed_memory_start =
                    &mut memory[callback_len * callback_size] as *mut u8;

            let mut result = Process {
                memory: memory,
                exposed_memory_start: exposed_memory_start,
                cur_stack: stack_bottom as *mut u8,
                wait_pc: 0,
                state: State::Waiting,
                callbacks: callbacks
            };

            result.load(start_addr);

            Some(result)
        } else {
            None
        }
    }

    unsafe fn load(&mut self, start_addr: *const usize) {
        let load_info : &LoadInfo = mem::transmute(start_addr);
        let exposed_memory_start = self.exposed_memory_start;

        // Zero out BSS
        ::core::intrinsics::write_bytes(
            exposed_memory_start.offset(load_info.bss_start_offset as isize),
            0,
            load_info.bss_end_offset - load_info.bss_start_offset);

        // Copy data into Data section
        let init_data : &[u8] = mem::transmute(raw::Slice{
            data: (load_info.init_data_loc + start_addr as usize) as *mut u8,
            len: load_info.init_data_size
        });

        let target_data : &mut [u8] = mem::transmute(raw::Slice{
            data: exposed_memory_start,
            len: load_info.init_data_size
        });

        target_data.clone_from_slice(init_data);

        // Fixup Global Offset Table
        let mut got_cur = exposed_memory_start.offset(load_info.got_start_offset as isize) as *mut usize;
        let got_end = exposed_memory_start.offset(load_info.got_end_offset as isize) as *mut usize;
        while got_cur != got_end {
            let entry = *got_cur;
            if (entry & 0x80000000) == 0 {
                // Regular data (memory relative)
                *got_cur = entry + (exposed_memory_start as usize);
            } else {
                // rodata or function pointer (code relative)
                *got_cur = (entry ^ 0x80000000) + (start_addr as usize);
            }
            got_cur = got_cur.offset(1);
        }

        // Entry point is offset from app code
        let init_fn = start_addr as usize + load_info.entry_loc;

        let heap_start = exposed_memory_start.offset(load_info.bss_end_offset as isize);

        self.callbacks.enqueue(Callback {
            pc: init_fn as usize,
            r0: heap_start as usize,
            r1: 0,
            r2: 0,
            r3: 0
        });
    }

    pub fn in_exposed_bounds(&self, buf_start_addr: *const u8, size: usize)
            -> bool {
        use core::raw::Repr;

        let buf_end_addr = ((buf_start_addr as usize) + size) as *const u8;

        let mem = self.memory.repr();
        let mem_end = ((mem.data as usize) + mem.len) as *const u8;

        buf_start_addr >= self.exposed_memory_start && buf_end_addr <= mem_end
    }

    pub unsafe fn alloc(&mut self, size: usize) -> Option<&mut [u8]> {
        use core::raw::Slice;

        let mem_len = self.memory.len();
        let end_mem = &mut self.memory[mem_len - 1] as *mut u8;
        let new_start = self.exposed_memory_start.offset(size as isize);
        if new_start >= end_mem {
            None
        } else {
            let buf = Slice {
                data: self.exposed_memory_start,
                len: size
            };
            self.exposed_memory_start = new_start;
            Some(mem::transmute(buf))
        }
    }

    pub unsafe fn free<T>(&mut self, _: *mut T) {}

    pub fn pop_syscall_stack(&mut self) {
        let pspr = self.cur_stack as *const usize;
        unsafe {
            self.wait_pc = volatile_load(pspr.offset(6));
            self.cur_stack =
                (self.cur_stack as *mut usize).offset(8) as *mut u8;
        }
    }

    /// Context switch to the process.
    pub unsafe fn switch_to_callback(&mut self, callback: Callback) {
        // Fill in initial stack expected by SVC handler
        // Top minus 8 u32s for r0-r3, r12, lr, pc and xPSR
        let stack_bottom = (self.cur_stack as *mut usize).offset(-8);
        volatile_store(stack_bottom.offset(7), 0x01000000);
        volatile_store(stack_bottom.offset(6), callback.pc | 1);
        // Set the LR register to the saved PC so the callback returns to
        // wherever wait was called. Set lowest bit to one because of THUMB
        // instruction requirements.
        volatile_store(stack_bottom.offset(5), self.wait_pc | 0x1);
        volatile_store(stack_bottom, callback.r0);
        volatile_store(stack_bottom.offset(1), callback.r1);
        volatile_store(stack_bottom.offset(2), callback.r2);
        volatile_store(stack_bottom.offset(3), callback.r3);

        self.cur_stack = stack_bottom as *mut u8;
        self.switch_to();
    }

    /// Context switch to the process.
    pub unsafe fn switch_to(&mut self) {
        if self.cur_stack < self.exposed_memory_start {
            breakpoint();
        }
        let psp = switch_to_user(self.cur_stack, self.exposed_memory_start);
        self.cur_stack = psp;
    }

    pub fn svc_number(&self) -> Option<u8> {
        let psp = self.cur_stack as *const *const u16;
        unsafe {
            let pcptr = volatile_load((psp as *const *const u16).offset(6));
            let svc_instr = volatile_load(pcptr.offset(-1));
            Some((svc_instr & 0xff) as u8)
        }
    }

    pub fn lr(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(5)) }
    }

    pub fn r0(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr) }
    }

    pub fn set_r0(&mut self, val: isize) {
        let pspr = self.cur_stack as *mut isize;
        unsafe { volatile_store(pspr, val) }
    }

    pub fn r1(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(1)) }
    }

    pub fn r2(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(2)) }
    }

    pub fn r3(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(3)) }
    }

}

<|endoftext|>


<commit_before>use core::intrinsics::{breakpoint, volatile_load, volatile_store};
use core::mem;
use core::raw::{Repr,Slice};

use common::{RingBuffer, Queue};

use container;

#[allow(improper_ctypes)]
extern {
    pub fn switch_to_user(user_stack: *const u8, mem_base: *const u8) -> *mut u8;
}

/// Size of each processes's memory region in bytes
pub const PROC_MEMORY_SIZE : usize = 8192;
pub const NUM_PROCS : usize = 2;

static mut FREE_MEMORY_IDX: usize = 0;

#[link_section = ".app_memory"]
static mut MEMORIES: [[u8; PROC_MEMORY_SIZE]; NUM_PROCS] = [[0; PROC_MEMORY_SIZE]; NUM_PROCS];

pub static mut PROCS : [Option<Process<'static>>; NUM_PROCS] = [None, None];

pub fn schedule(callback: Callback, appid: ::AppId) -> bool {
    let procs = unsafe { &mut PROCS };
    let idx = appid.idx();
    if idx >= procs.len() {
        return false
    }

    match procs[idx] {
        None => false,
        Some(ref mut p) => {
            // TODO(alevy): validate appid liveness
            p.callbacks.enqueue(callback)
        }
    }
}

#[derive(Copy,Clone,PartialEq,Eq)]
pub enum Error {
    NoSuchApp,
    OutOfMemory,
    AddressOutOfBounds
}

#[derive(Copy,Clone,PartialEq,Eq)]
pub enum State {
    Running,
    Waiting
}

#[derive(Copy,Clone,Debug)]
pub struct Callback {
    pub r0: usize,
    pub r1: usize,
    pub r2: usize,
    pub r3: usize,
    pub pc: usize
}

#[repr(C,packed)]
struct LoadInfo {
    rel_data_size: usize,
    entry_loc: usize,        /* Entry point for user application */
    init_data_loc: usize,    /* Data initialization information in flash */
    init_data_size: usize,    /* Size of initialization information */
    got_start_offset: usize,  /* Offset to start of GOT */
    got_end_offset: usize,    /* Offset to end of GOT */
    bss_start_offset: usize,  /* Offset to start of BSS */
    bss_end_offset: usize    /* Offset to end of BSS */
}

pub struct Process<'a> {
    /// The process's memory.
    memory: Slice<u8>,

    app_memory_break: *const u8,
    kernel_memory_break: *const u8,

    /// Process text segment
    text: Slice<u8>,

    /// The offset in `memory` to use for the process stack.
    cur_stack: *const u8,

    wait_pc: usize,
    psr: usize,

    pub state: State,

    pub callbacks: RingBuffer<'a, Callback>
}

#[inline(never)]
pub unsafe fn load_processes(mut start_addr: *const usize) ->
        &'static mut [Option<Process<'static>>] {
    for op in PROCS.iter_mut() {
        if *start_addr != 0 {
            let prog_start = start_addr.offset(1);
            let length = *start_addr as isize;
            start_addr = (start_addr as *const u8).offset(length) as *const usize;

            *op = Process::create(prog_start);
        } else {
            *op = None;
        }
    }
    &mut PROCS
}

impl<'a> Process<'a> {
    pub const fn mem_start(&self) -> *const u8 {
        self.memory.data
    }

    pub fn mem_end(&self) -> *const u8 {
        unsafe {
            self.memory.data.offset(self.memory.len as isize)
        }
    }

    pub unsafe fn create(start_addr: *const usize) -> Option<Process<'a>> {
        let cur_idx = FREE_MEMORY_IDX;
        if cur_idx <= MEMORIES.len() {
            FREE_MEMORY_IDX += 1;
            let memory = MEMORIES[cur_idx].repr();

            let mut kernel_memory_break = {
                // make room for container pointers
                let psz = mem::size_of::<*const usize>();
                let num_ctrs = volatile_load(&container::CONTAINER_COUNTER);
                let container_ptrs_size = num_ctrs * psz;
                let res = memory.data.offset((memory.len - container_ptrs_size) as isize);
                // set all ptrs to null
                let opts : &mut [*const usize] = mem::transmute(Slice {
                    data: res as *mut *const usize,
                    len: num_ctrs
                });
                for opt in opts.iter_mut() {
                    *opt = ::core::ptr::null()
                }
                res
            };

            // Take callback buffer from of memory
            let callback_size = mem::size_of::<Option<Callback>>();
            let callback_len = 10;
            let callback_offset = callback_len * callback_size;
            // Set kernel break to beginning of callback buffer
            kernel_memory_break =
                kernel_memory_break.offset(-(callback_offset as isize));
            let callback_buf = mem::transmute(Slice {
                data: kernel_memory_break as *const Option<Callback>,
                len: callback_len
            });

            let callbacks = RingBuffer::new(callback_buf);

            let load_result = load(start_addr, memory.data);

            let stack_bottom = load_result.app_mem_start.offset(512);

            let mut process = Process {
                memory: memory,
                app_memory_break: stack_bottom,
                kernel_memory_break: kernel_memory_break,
                text: Slice {
                    data: load_result.text_start,
                    len: load_result.text_len },
                cur_stack: stack_bottom,
                wait_pc: 0,
                psr: 0x01000000,
                state: State::Waiting,
                callbacks: callbacks
            };

            process.callbacks.enqueue(Callback {
                pc: load_result.init_fn,
                r0: load_result.app_mem_start as usize,
                r1: process.app_memory_break as usize,
                r2: process.kernel_memory_break as usize,
                r3: 0
            });

            Some(process)
        } else {
            None
        }
    }

    pub fn sbrk(&mut self, increment: isize) -> Result<*const u8, Error> {
        let new_break = unsafe { self.app_memory_break.offset(increment) };
        self.brk(new_break)
    }

    pub fn brk(&mut self, new_break: *const u8) -> Result<*const u8, Error> {
        if new_break < self.mem_start() || new_break >= self.mem_end() {
            Err(Error::AddressOutOfBounds)
        } else if new_break > self.kernel_memory_break {
            Err(Error::OutOfMemory)
        } else {
            let old_break = self.app_memory_break;
            self.app_memory_break = new_break;
            Ok(old_break)
        }
    }

    pub fn in_exposed_bounds(&self, buf_start_addr: *const u8, size: usize)
            -> bool {

        let buf_end_addr = ((buf_start_addr as usize) + size) as *const u8;

        let mem_end =
            ((self.memory.data as usize) + self.memory.len) as *const u8;

        buf_start_addr >= self.memory.data && buf_end_addr <= mem_end
    }

    pub unsafe fn alloc(&mut self, size: usize) -> Option<&mut [u8]> {
        let new_break = self.kernel_memory_break.offset(-(size as isize));
        if new_break < self.app_memory_break {
            None
        } else {
            self.kernel_memory_break = new_break;
            Some(mem::transmute(Slice {
                data: new_break as *mut u8,
                len: size
            }))
        }
    }

    pub unsafe fn free<T>(&mut self, _: *mut T) {}

    pub unsafe fn container_for<T>(&mut self, container_num: usize)
            -> *mut *mut T {
        let container_num = container_num as isize;
        let ptr = (self.mem_end() as *mut usize)
                        .offset(-(container_num + 1));
        ptr as *mut *mut T
    }

    pub unsafe fn container_for_or_alloc<T: Default>(&mut self,
                                                     container_num: usize)
            -> Option<*mut T> {
        let ctr_ptr = self.container_for::<T>(container_num);
        if (*ctr_ptr).is_null() {
            self.alloc(mem::size_of::<T>()).map(|root_arr| {
                let root_ptr = root_arr.repr().data as *mut T;
                *root_ptr = Default::default();
                volatile_store(ctr_ptr, root_ptr);
                root_ptr
            })
        } else {
            Some(*ctr_ptr)
        }
    }

    pub fn pop_syscall_stack(&mut self) {
        let pspr = self.cur_stack as *const usize;
        unsafe {
            self.wait_pc = volatile_load(pspr.offset(6));
            self.psr = volatile_load(pspr.offset(7));
            self.cur_stack =
                (self.cur_stack as *mut usize).offset(8) as *mut u8;
        }
    }

    /// Context switch to the process.
    pub unsafe fn switch_to_callback(&mut self, callback: Callback) {
        // Fill in initial stack expected by SVC handler
        // Top minus 8 u32s for r0-r3, r12, lr, pc and xPSR
        let stack_bottom = (self.cur_stack as *mut usize).offset(-8);
        volatile_store(stack_bottom.offset(7), self.psr);
        volatile_store(stack_bottom.offset(6), callback.pc | 1);
        // Set the LR register to the saved PC so the callback returns to
        // wherever wait was called. Set lowest bit to one because of THUMB
        // instruction requirements.
        volatile_store(stack_bottom.offset(5), self.wait_pc | 0x1);
        volatile_store(stack_bottom, callback.r0);
        volatile_store(stack_bottom.offset(1), callback.r1);
        volatile_store(stack_bottom.offset(2), callback.r2);
        volatile_store(stack_bottom.offset(3), callback.r3);

        self.cur_stack = stack_bottom as *mut u8;
        self.switch_to();
    }

    /// Context switch to the process.
    pub unsafe fn switch_to(&mut self) {
        if self.cur_stack < self.memory.data {
            breakpoint();
        }
        let psp = switch_to_user(self.cur_stack, self.memory.data);
        self.cur_stack = psp;
    }

    pub fn svc_number(&self) -> Option<u8> {
        let psp = self.cur_stack as *const *const u16;
        unsafe {
            let pcptr = volatile_load((psp as *const *const u16).offset(6));
            let svc_instr = volatile_load(pcptr.offset(-1));
            Some((svc_instr & 0xff) as u8)
        }
    }

    pub fn lr(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(5)) }
    }

    pub fn r0(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr) }
    }

    pub fn set_r0(&mut self, val: isize) {
        let pspr = self.cur_stack as *mut isize;
        unsafe { volatile_store(pspr, val) }
    }

    pub fn r1(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(1)) }
    }

    pub fn r2(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(2)) }
    }

    pub fn r3(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(3)) }
    }

}

struct LoadResult {
    text_start: *const u8,
    text_len: usize,
    init_fn: usize,
    app_mem_start: *const u8
}

unsafe fn load(start_addr: *const usize, mem_base: *const u8) -> LoadResult {
    let mut result = LoadResult {
        text_start: 0 as *const u8,
        text_len: 0,
        init_fn: 0,
        app_mem_start: 0 as *const u8
    };

    let mut start_addr = start_addr as *const u8;
    let load_info : &LoadInfo = mem::transmute(start_addr);
    start_addr = start_addr.offset(mem::size_of::<LoadInfo>() as isize);

    let rel_data : &mut [usize] = mem::transmute(Slice{
        data: start_addr,
        len: load_info.rel_data_size / 4
    });
    start_addr = start_addr.offset(load_info.rel_data_size as isize);

    // Update text location in self
    result.text_start = start_addr;
    result.text_len = load_info.init_data_loc;

    // Zero out BSS
    ::core::intrinsics::write_bytes(
        mem_base.offset(load_info.bss_start_offset as isize) as *mut u8,
        0,
        load_info.bss_end_offset - load_info.bss_start_offset);

    // Copy data into Data section
    let init_data : &[u8] = mem::transmute(Slice{
        data: (load_info.init_data_loc + start_addr as usize) as *mut u8,
        len: load_info.init_data_size
    });

    let target_data : &mut [u8] = mem::transmute(Slice{
        data: mem_base,
        len: load_info.init_data_size
    });

    target_data.clone_from_slice(init_data);

    let fixup = |addr: *mut usize| {
        let entry = *addr;
        if (entry & 0x80000000) == 0 {
            // Regular data (memory relative)
            *addr = entry + (mem_base as usize);
        } else {
            // rodata or function pointer (code relative)
            *addr = (entry ^ 0x80000000) + (start_addr as usize);
        }
    };

    // Fixup Global Offset Table
    let mut got_cur = mem_base.offset(
        load_info.got_start_offset as isize) as *mut usize;
    let got_end = mem_base.offset(
        load_info.got_end_offset as isize) as *mut usize;
    while got_cur != got_end {
        fixup(got_cur);
        got_cur = got_cur.offset(1);
    }

    // Fixup relocation data
    for (i, addr) in rel_data.iter().enumerate() {
        if i % 2 == 0 { // Only the first of every 2 entries is an address
            fixup(mem_base.offset(*addr as isize) as *mut usize);
        }
    }

    // Entry point is offset from app code
    result.init_fn = start_addr as usize + load_info.entry_loc;

    let mut aligned_mem_start = load_info.bss_end_offset as isize;
    aligned_mem_start += (8 - (aligned_mem_start % 8)) % 8;
    result.app_mem_start = mem_base.offset(aligned_mem_start);

    result
}

<commit_msg>WORKAROUND: Decrease process memory to 2K<commit_after>use core::intrinsics::{breakpoint, volatile_load, volatile_store};
use core::mem;
use core::raw::{Repr,Slice};

use common::{RingBuffer, Queue};

use container;

#[allow(improper_ctypes)]
extern {
    pub fn switch_to_user(user_stack: *const u8, mem_base: *const u8) -> *mut u8;
}

/// Size of each processes's memory region in bytes
pub const PROC_MEMORY_SIZE : usize = 2048;
pub const NUM_PROCS : usize = 2;

static mut FREE_MEMORY_IDX: usize = 0;

#[link_section = ".app_memory"]
static mut MEMORIES: [[u8; PROC_MEMORY_SIZE]; NUM_PROCS] = [[0; PROC_MEMORY_SIZE]; NUM_PROCS];

pub static mut PROCS : [Option<Process<'static>>; NUM_PROCS] = [None, None];

pub fn schedule(callback: Callback, appid: ::AppId) -> bool {
    let procs = unsafe { &mut PROCS };
    let idx = appid.idx();
    if idx >= procs.len() {
        return false
    }

    match procs[idx] {
        None => false,
        Some(ref mut p) => {
            // TODO(alevy): validate appid liveness
            p.callbacks.enqueue(callback)
        }
    }
}

#[derive(Copy,Clone,PartialEq,Eq)]
pub enum Error {
    NoSuchApp,
    OutOfMemory,
    AddressOutOfBounds
}

#[derive(Copy,Clone,PartialEq,Eq)]
pub enum State {
    Running,
    Waiting
}

#[derive(Copy,Clone,Debug)]
pub struct Callback {
    pub r0: usize,
    pub r1: usize,
    pub r2: usize,
    pub r3: usize,
    pub pc: usize
}

#[repr(C,packed)]
struct LoadInfo {
    rel_data_size: usize,
    entry_loc: usize,        /* Entry point for user application */
    init_data_loc: usize,    /* Data initialization information in flash */
    init_data_size: usize,    /* Size of initialization information */
    got_start_offset: usize,  /* Offset to start of GOT */
    got_end_offset: usize,    /* Offset to end of GOT */
    bss_start_offset: usize,  /* Offset to start of BSS */
    bss_end_offset: usize    /* Offset to end of BSS */
}

pub struct Process<'a> {
    /// The process's memory.
    memory: Slice<u8>,

    app_memory_break: *const u8,
    kernel_memory_break: *const u8,

    /// Process text segment
    text: Slice<u8>,

    /// The offset in `memory` to use for the process stack.
    cur_stack: *const u8,

    wait_pc: usize,
    psr: usize,

    pub state: State,

    pub callbacks: RingBuffer<'a, Callback>
}

#[inline(never)]
pub unsafe fn load_processes(mut start_addr: *const usize) ->
        &'static mut [Option<Process<'static>>] {
    for op in PROCS.iter_mut() {
        if *start_addr != 0 {
            let prog_start = start_addr.offset(1);
            let length = *start_addr as isize;
            start_addr = (start_addr as *const u8).offset(length) as *const usize;

            *op = Process::create(prog_start);
        } else {
            *op = None;
        }
    }
    &mut PROCS
}

impl<'a> Process<'a> {
    pub const fn mem_start(&self) -> *const u8 {
        self.memory.data
    }

    pub fn mem_end(&self) -> *const u8 {
        unsafe {
            self.memory.data.offset(self.memory.len as isize)
        }
    }

    pub unsafe fn create(start_addr: *const usize) -> Option<Process<'a>> {
        let cur_idx = FREE_MEMORY_IDX;
        if cur_idx <= MEMORIES.len() {
            FREE_MEMORY_IDX += 1;
            let memory = MEMORIES[cur_idx].repr();

            let mut kernel_memory_break = {
                // make room for container pointers
                let psz = mem::size_of::<*const usize>();
                let num_ctrs = volatile_load(&container::CONTAINER_COUNTER);
                let container_ptrs_size = num_ctrs * psz;
                let res = memory.data.offset((memory.len - container_ptrs_size) as isize);
                // set all ptrs to null
                let opts : &mut [*const usize] = mem::transmute(Slice {
                    data: res as *mut *const usize,
                    len: num_ctrs
                });
                for opt in opts.iter_mut() {
                    *opt = ::core::ptr::null()
                }
                res
            };

            // Take callback buffer from of memory
            let callback_size = mem::size_of::<Option<Callback>>();
            let callback_len = 10;
            let callback_offset = callback_len * callback_size;
            // Set kernel break to beginning of callback buffer
            kernel_memory_break =
                kernel_memory_break.offset(-(callback_offset as isize));
            let callback_buf = mem::transmute(Slice {
                data: kernel_memory_break as *const Option<Callback>,
                len: callback_len
            });

            let callbacks = RingBuffer::new(callback_buf);

            let load_result = load(start_addr, memory.data);

            let stack_bottom = load_result.app_mem_start.offset(512);

            let mut process = Process {
                memory: memory,
                app_memory_break: stack_bottom,
                kernel_memory_break: kernel_memory_break,
                text: Slice {
                    data: load_result.text_start,
                    len: load_result.text_len },
                cur_stack: stack_bottom,
                wait_pc: 0,
                psr: 0x01000000,
                state: State::Waiting,
                callbacks: callbacks
            };

            process.callbacks.enqueue(Callback {
                pc: load_result.init_fn,
                r0: load_result.app_mem_start as usize,
                r1: process.app_memory_break as usize,
                r2: process.kernel_memory_break as usize,
                r3: 0
            });

            Some(process)
        } else {
            None
        }
    }

    pub fn sbrk(&mut self, increment: isize) -> Result<*const u8, Error> {
        let new_break = unsafe { self.app_memory_break.offset(increment) };
        self.brk(new_break)
    }

    pub fn brk(&mut self, new_break: *const u8) -> Result<*const u8, Error> {
        if new_break < self.mem_start() || new_break >= self.mem_end() {
            Err(Error::AddressOutOfBounds)
        } else if new_break > self.kernel_memory_break {
            Err(Error::OutOfMemory)
        } else {
            let old_break = self.app_memory_break;
            self.app_memory_break = new_break;
            Ok(old_break)
        }
    }

    pub fn in_exposed_bounds(&self, buf_start_addr: *const u8, size: usize)
            -> bool {

        let buf_end_addr = ((buf_start_addr as usize) + size) as *const u8;

        let mem_end =
            ((self.memory.data as usize) + self.memory.len) as *const u8;

        buf_start_addr >= self.memory.data && buf_end_addr <= mem_end
    }

    pub unsafe fn alloc(&mut self, size: usize) -> Option<&mut [u8]> {
        let new_break = self.kernel_memory_break.offset(-(size as isize));
        if new_break < self.app_memory_break {
            None
        } else {
            self.kernel_memory_break = new_break;
            Some(mem::transmute(Slice {
                data: new_break as *mut u8,
                len: size
            }))
        }
    }

    pub unsafe fn free<T>(&mut self, _: *mut T) {}

    pub unsafe fn container_for<T>(&mut self, container_num: usize)
            -> *mut *mut T {
        let container_num = container_num as isize;
        let ptr = (self.mem_end() as *mut usize)
                        .offset(-(container_num + 1));
        ptr as *mut *mut T
    }

    pub unsafe fn container_for_or_alloc<T: Default>(&mut self,
                                                     container_num: usize)
            -> Option<*mut T> {
        let ctr_ptr = self.container_for::<T>(container_num);
        if (*ctr_ptr).is_null() {
            self.alloc(mem::size_of::<T>()).map(|root_arr| {
                let root_ptr = root_arr.repr().data as *mut T;
                *root_ptr = Default::default();
                volatile_store(ctr_ptr, root_ptr);
                root_ptr
            })
        } else {
            Some(*ctr_ptr)
        }
    }

    pub fn pop_syscall_stack(&mut self) {
        let pspr = self.cur_stack as *const usize;
        unsafe {
            self.wait_pc = volatile_load(pspr.offset(6));
            self.psr = volatile_load(pspr.offset(7));
            self.cur_stack =
                (self.cur_stack as *mut usize).offset(8) as *mut u8;
        }
    }

    /// Context switch to the process.
    pub unsafe fn switch_to_callback(&mut self, callback: Callback) {
        // Fill in initial stack expected by SVC handler
        // Top minus 8 u32s for r0-r3, r12, lr, pc and xPSR
        let stack_bottom = (self.cur_stack as *mut usize).offset(-8);
        volatile_store(stack_bottom.offset(7), self.psr);
        volatile_store(stack_bottom.offset(6), callback.pc | 1);
        // Set the LR register to the saved PC so the callback returns to
        // wherever wait was called. Set lowest bit to one because of THUMB
        // instruction requirements.
        volatile_store(stack_bottom.offset(5), self.wait_pc | 0x1);
        volatile_store(stack_bottom, callback.r0);
        volatile_store(stack_bottom.offset(1), callback.r1);
        volatile_store(stack_bottom.offset(2), callback.r2);
        volatile_store(stack_bottom.offset(3), callback.r3);

        self.cur_stack = stack_bottom as *mut u8;
        self.switch_to();
    }

    /// Context switch to the process.
    pub unsafe fn switch_to(&mut self) {
        if self.cur_stack < self.memory.data {
            breakpoint();
        }
        let psp = switch_to_user(self.cur_stack, self.memory.data);
        self.cur_stack = psp;
    }

    pub fn svc_number(&self) -> Option<u8> {
        let psp = self.cur_stack as *const *const u16;
        unsafe {
            let pcptr = volatile_load((psp as *const *const u16).offset(6));
            let svc_instr = volatile_load(pcptr.offset(-1));
            Some((svc_instr & 0xff) as u8)
        }
    }

    pub fn lr(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(5)) }
    }

    pub fn r0(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr) }
    }

    pub fn set_r0(&mut self, val: isize) {
        let pspr = self.cur_stack as *mut isize;
        unsafe { volatile_store(pspr, val) }
    }

    pub fn r1(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(1)) }
    }

    pub fn r2(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(2)) }
    }

    pub fn r3(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(3)) }
    }

}

struct LoadResult {
    text_start: *const u8,
    text_len: usize,
    init_fn: usize,
    app_mem_start: *const u8
}

unsafe fn load(start_addr: *const usize, mem_base: *const u8) -> LoadResult {
    let mut result = LoadResult {
        text_start: 0 as *const u8,
        text_len: 0,
        init_fn: 0,
        app_mem_start: 0 as *const u8
    };

    let mut start_addr = start_addr as *const u8;
    let load_info : &LoadInfo = mem::transmute(start_addr);
    start_addr = start_addr.offset(mem::size_of::<LoadInfo>() as isize);

    let rel_data : &mut [usize] = mem::transmute(Slice{
        data: start_addr,
        len: load_info.rel_data_size / 4
    });
    start_addr = start_addr.offset(load_info.rel_data_size as isize);

    // Update text location in self
    result.text_start = start_addr;
    result.text_len = load_info.init_data_loc;

    // Zero out BSS
    ::core::intrinsics::write_bytes(
        mem_base.offset(load_info.bss_start_offset as isize) as *mut u8,
        0,
        load_info.bss_end_offset - load_info.bss_start_offset);

    // Copy data into Data section
    let init_data : &[u8] = mem::transmute(Slice{
        data: (load_info.init_data_loc + start_addr as usize) as *mut u8,
        len: load_info.init_data_size
    });

    let target_data : &mut [u8] = mem::transmute(Slice{
        data: mem_base,
        len: load_info.init_data_size
    });

    target_data.clone_from_slice(init_data);

    let fixup = |addr: *mut usize| {
        let entry = *addr;
        if (entry & 0x80000000) == 0 {
            // Regular data (memory relative)
            *addr = entry + (mem_base as usize);
        } else {
            // rodata or function pointer (code relative)
            *addr = (entry ^ 0x80000000) + (start_addr as usize);
        }
    };

    // Fixup Global Offset Table
    let mut got_cur = mem_base.offset(
        load_info.got_start_offset as isize) as *mut usize;
    let got_end = mem_base.offset(
        load_info.got_end_offset as isize) as *mut usize;
    while got_cur != got_end {
        fixup(got_cur);
        got_cur = got_cur.offset(1);
    }

    // Fixup relocation data
    for (i, addr) in rel_data.iter().enumerate() {
        if i % 2 == 0 { // Only the first of every 2 entries is an address
            fixup(mem_base.offset(*addr as isize) as *mut usize);
        }
    }

    // Entry point is offset from app code
    result.init_fn = start_addr as usize + load_info.entry_loc;

    let mut aligned_mem_start = load_info.bss_end_offset as isize;
    aligned_mem_start += (8 - (aligned_mem_start % 8)) % 8;
    result.app_mem_start = mem_base.offset(aligned_mem_start);

    result
}

<|endoftext|>


<commit_before>use super::*;
use crate::ram::cell::*;
use crate::ram::chunk::Chunks;
use crate::ram::schema::*;
use crate::ram::types::*;
use crate::server::ServerMeta;
use bifrost_hasher::hash_str;
use env_logger;
use std;
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;

pub const CHUNK_SIZE: usize = 1 * 8 * 1024 * 1024;

#[test]
pub fn round_robin_segment() {
    let num = AtomicU8::new(std::u8::MAX);
    assert_eq!(num.load(Ordering::SeqCst), 255);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 255);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 0);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 1);
}

#[test]
pub fn cell_rw() {
    let _ = env_logger::try_init();
    info!("START");
    let id1 = Id::new(1, 1);
    let id2 = Id::new(1, 2);
    let fields = default_fields();
    let schema = Schema::new("dummy", None, fields, false, false);
    let mut data_map = OwnedMap::new();
    data_map.insert(&String::from("id"), OwnedValue::I64(100));
    data_map.insert(&String::from("score"), OwnedValue::U64(70));
    data_map.insert(
        &String::from("name"),
        OwnedValue::String(String::from("Jack")),
    );
    let mut data = OwnedValue::Map(data_map);
    let schemas = LocalSchemasCache::new_local("");
    schemas.new_schema(schema.clone());
    let mut cell = OwnedCell {
        header: CellHeader::new(schema.id, &id1),
        data,
    };
    let chunks = Chunks::new(
        1,
        CHUNK_SIZE,
        Arc::new(ServerMeta { schemas }),
        None,
        None,
        None,
    );
    let header = chunks.write_cell(&mut cell).unwrap();
    let cell_1_ptr = chunks.address_of(&Id::from_header(&header));
    {
        let stored_cell = chunks.read_cell(&id1).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
    data_map = OwnedMap::new();
    data_map.insert(&String::from("id"), OwnedValue::I64(2));
    data_map.insert(&String::from("score"), OwnedValue::U64(80));
    data_map.insert(
        &String::from("name"),
        OwnedValue::String(String::from("John")),
    );
    data = OwnedValue::Map(data_map);
    cell = OwnedCell {
        header: CellHeader::new(schema.id, &id2),
        data,
    };
    let header = chunks.write_cell(&mut cell).unwrap();
    let cell_2_ptr = chunks.address_of(&Id::from_header(&header));
    {
        let stored_cell = chunks.read_cell(&id2).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &80);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
    }
    {
        let stored_cell = chunks.read_cell(&id1).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
    data_map = OwnedMap::new();
    data_map.insert(&String::from("id"), OwnedValue::I64(2));
    data_map.insert(&String::from("score"), OwnedValue::U64(95));
    data_map.insert(
        &String::from("name"),
        OwnedValue::String(String::from("John")),
    );
    data = OwnedValue::Map(data_map);
    cell = OwnedCell {
        header: CellHeader::new(schema.id, &id2),
        data,
    };
    let header = chunks.update_cell(&mut cell).unwrap();
    let _cell_2_ptr = chunks.address_of(&Id::from_header(&header));
    {
        let stored_cell = chunks.read_cell(&id2).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &95);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
    }
    {
        let stored_cell = chunks.read_cell(&id1).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
    chunks
        .update_cell_by(&id2, |cell| {
            let mut data_map = OwnedMap::new();
            data_map.insert(&String::from("id"), OwnedValue::I64(2));
            data_map.insert(&String::from("score"), OwnedValue::U64(100));
            data_map.insert(
                &String::from("name"),
                OwnedValue::String(String::from("John")),
            );
            let data = OwnedValue::Map(data_map);
            let mut cell = cell.to_owned();
            cell.data = data;
            Some(cell)
        })
        .unwrap();
    {
        let stored_cell = chunks.read_cell(&id2).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
    }
    {
        let sel_cell = chunks.read_selected(&id2, &[
            hash_str("score"),
            hash_str("name")
        ]).unwrap();
        assert_eq!(sel_cell["score"].u64().unwrap(), &100);
        assert_eq!(sel_cell["name"].string().unwrap(), "John");
    }
    chunks.remove_cell(&id1).unwrap();
    assert!(chunks.read_cell(&id1).is_err());
}

#[test]
pub fn simple_cell_rw() {
    let _ = env_logger::try_init();
    let id1 = Id::new(1, 1);
    let fields = simple_fields();
    let schema = Schema::new("simple", None, fields, false, true);
    let data = OwnedValue::U64(128);
    let schemas = LocalSchemasCache::new_local("");
    schemas.new_schema(schema.clone());
    let mut cell = OwnedCell {
        header: CellHeader::new(schema.id, &id1),
        data
    };
    let chunks = Chunks::new(
        1,
        CHUNK_SIZE,
        Arc::new(ServerMeta { schemas }),
        None,
        None,
        None
    );
    chunks.write_cell(&mut cell).unwrap();
    {
        let stored_cell = chunks.read_cell(&id1).unwrap();
        assert_eq!(stored_cell.data.u64(), Some(&128));
    }
}

#[test]
pub fn array_dyn_map() {
    let _ = env_logger::try_init();
    let id1 = Id::new(1, 1);
    let fields = Field::new(
        &String::from("*"),
        Type::Map,
        false,
        false,
        Some(vec![
            Field::new(
                &String::from("fixed"),
                Type::U32,
                false,
                false,
                None,
                vec![]
            ),
            dyn_map_field("dynamic")
        ]),
        vec![]
    );
    let schema = Schema::new("array_dyn_map", None, fields, false, true);
    let schemas = LocalSchemasCache::new_local("");
    schemas.new_schema(schema.clone());
    let chunks = Chunks::new(
        1,
        CHUNK_SIZE,
        Arc::new(ServerMeta { schemas }),
        None,
        None,
        None
    );
    let data = data_map_value!(
        fixed: OwnedValue::U32(42),
        dynamic: dyn_map_value()
    );
    let mut cell = OwnedCell {
        header: CellHeader::new(schema.id, &id1),
        data
    };
    chunks.write_cell(&mut cell).unwrap();
    {
        let read_cell = chunks.read_cell(&id1).unwrap().to_owned();
        assert_eq!(cell.data, read_cell.data);
    }
    {
        unimplemented!() // READ
    }
}

#[test]
pub fn complex_cell_sel_read() {
    let _ = env_logger::try_init();
    let id1 = Id::new(1, 1);
    let fields = complex_fields();
    let schema = Schema::new("complex", None, fields, false, true);
    let schemas = LocalSchemasCache::new_local("");
    schemas.new_schema(schema.clone());
    let chunks = Chunks::new(
        1,
        CHUNK_SIZE,
        Arc::new(ServerMeta { schemas }),
        None,
        None,
        None
    );
    let data = data_map_value!(
        id: OwnedValue::I64(128),
        strings: OwnedValue::PrimArray(OwnedPrimArray::String(vec![
            String::from("aaaa"),
            String::from("bbbb"),
            String::from("cccc")
        ])),
        num: OwnedValue::U64(256),
        nums: OwnedValue::PrimArray(OwnedPrimArray::U64(vec![
            512, 1024, 2048
        ])),
        sub: data_map_value!(
            sub1: OwnedValue::U32(4096),
            sub2: OwnedValue::PrimArray(OwnedPrimArray::U32(vec![
                8192, 16384
            ])),
            sub3: OwnedValue::U32(1),
            sub4: data_map_value!(
                sub4sub1: OwnedValue::U32(2),
                sub4sub2: OwnedValue::PrimArray(OwnedPrimArray::U32(vec![
                    3, 4, 5
                ])),
                sub4sub3: OwnedValue::PrimArray(OwnedPrimArray::U64(vec![
                    6, 7
                ])),
                sub4sub4: OwnedValue::U16(8)
            ),
            sub5: dyn_map_value(),
            subend: OwnedValue::U32(24)
        )
    );
    let mut cell = OwnedCell {
        header: CellHeader::new(schema.id, &id1),
        data
    };
    chunks.write_cell(&mut cell).unwrap();
    {
        let read_cell = chunks.read_cell(&id1).unwrap().to_owned();
        assert_eq!(cell.data, read_cell.data);
    }
}

fn dyn_map_value() -> OwnedValue {
    OwnedValue::Array(vec![
        data_map_value!(
            sub5sub1: OwnedValue::U32(9),
            sub5sub2: OwnedValue::PrimArray(OwnedPrimArray::U32(vec![
                10, 11
            ])),
            sub5sub3: OwnedValue::PrimArray(OwnedPrimArray::U64(vec![
                12, 13, 14
            ])),
            sub5sub4: OwnedValue::U16(15)
        ),
        data_map_value!(
            sub5sub1: OwnedValue::U32(16),
            sub5sub2: OwnedValue::PrimArray(OwnedPrimArray::U32(vec![
                17, 18, 19, 20
            ])),
            sub5sub3: OwnedValue::PrimArray(OwnedPrimArray::U64(vec![
                21, 22
            ])),
            sub5sub4: OwnedValue::U16(23)
        )
    ])
}<commit_msg>remove unimpl<commit_after>use super::*;
use crate::ram::cell::*;
use crate::ram::chunk::Chunks;
use crate::ram::schema::*;
use crate::ram::types::*;
use crate::server::ServerMeta;
use bifrost_hasher::hash_str;
use env_logger;
use std;
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;

pub const CHUNK_SIZE: usize = 1 * 8 * 1024 * 1024;

#[test]
pub fn round_robin_segment() {
    let num = AtomicU8::new(std::u8::MAX);
    assert_eq!(num.load(Ordering::SeqCst), 255);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 255);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 0);
    assert_eq!(num.fetch_add(1, Ordering::SeqCst), 1);
}

#[test]
pub fn cell_rw() {
    let _ = env_logger::try_init();
    info!("START");
    let id1 = Id::new(1, 1);
    let id2 = Id::new(1, 2);
    let fields = default_fields();
    let schema = Schema::new("dummy", None, fields, false, false);
    let mut data_map = OwnedMap::new();
    data_map.insert(&String::from("id"), OwnedValue::I64(100));
    data_map.insert(&String::from("score"), OwnedValue::U64(70));
    data_map.insert(
        &String::from("name"),
        OwnedValue::String(String::from("Jack")),
    );
    let mut data = OwnedValue::Map(data_map);
    let schemas = LocalSchemasCache::new_local("");
    schemas.new_schema(schema.clone());
    let mut cell = OwnedCell {
        header: CellHeader::new(schema.id, &id1),
        data,
    };
    let chunks = Chunks::new(
        1,
        CHUNK_SIZE,
        Arc::new(ServerMeta { schemas }),
        None,
        None,
        None,
    );
    let header = chunks.write_cell(&mut cell).unwrap();
    let cell_1_ptr = chunks.address_of(&Id::from_header(&header));
    {
        let stored_cell = chunks.read_cell(&id1).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
    data_map = OwnedMap::new();
    data_map.insert(&String::from("id"), OwnedValue::I64(2));
    data_map.insert(&String::from("score"), OwnedValue::U64(80));
    data_map.insert(
        &String::from("name"),
        OwnedValue::String(String::from("John")),
    );
    data = OwnedValue::Map(data_map);
    cell = OwnedCell {
        header: CellHeader::new(schema.id, &id2),
        data,
    };
    let header = chunks.write_cell(&mut cell).unwrap();
    let cell_2_ptr = chunks.address_of(&Id::from_header(&header));
    {
        let stored_cell = chunks.read_cell(&id2).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &80);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
    }
    {
        let stored_cell = chunks.read_cell(&id1).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
    data_map = OwnedMap::new();
    data_map.insert(&String::from("id"), OwnedValue::I64(2));
    data_map.insert(&String::from("score"), OwnedValue::U64(95));
    data_map.insert(
        &String::from("name"),
        OwnedValue::String(String::from("John")),
    );
    data = OwnedValue::Map(data_map);
    cell = OwnedCell {
        header: CellHeader::new(schema.id, &id2),
        data,
    };
    let header = chunks.update_cell(&mut cell).unwrap();
    let _cell_2_ptr = chunks.address_of(&Id::from_header(&header));
    {
        let stored_cell = chunks.read_cell(&id2).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &95);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
    }
    {
        let stored_cell = chunks.read_cell(&id1).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
    chunks
        .update_cell_by(&id2, |cell| {
            let mut data_map = OwnedMap::new();
            data_map.insert(&String::from("id"), OwnedValue::I64(2));
            data_map.insert(&String::from("score"), OwnedValue::U64(100));
            data_map.insert(
                &String::from("name"),
                OwnedValue::String(String::from("John")),
            );
            let data = OwnedValue::Map(data_map);
            let mut cell = cell.to_owned();
            cell.data = data;
            Some(cell)
        })
        .unwrap();
    {
        let stored_cell = chunks.read_cell(&id2).unwrap();
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
    }
    {
        let sel_cell = chunks.read_selected(&id2, &[
            hash_str("score"),
            hash_str("name")
        ]).unwrap();
        assert_eq!(sel_cell["score"].u64().unwrap(), &100);
        assert_eq!(sel_cell["name"].string().unwrap(), "John");
    }
    chunks.remove_cell(&id1).unwrap();
    assert!(chunks.read_cell(&id1).is_err());
}

#[test]
pub fn simple_cell_rw() {
    let _ = env_logger::try_init();
    let id1 = Id::new(1, 1);
    let fields = simple_fields();
    let schema = Schema::new("simple", None, fields, false, true);
    let data = OwnedValue::U64(128);
    let schemas = LocalSchemasCache::new_local("");
    schemas.new_schema(schema.clone());
    let mut cell = OwnedCell {
        header: CellHeader::new(schema.id, &id1),
        data
    };
    let chunks = Chunks::new(
        1,
        CHUNK_SIZE,
        Arc::new(ServerMeta { schemas }),
        None,
        None,
        None
    );
    chunks.write_cell(&mut cell).unwrap();
    {
        let stored_cell = chunks.read_cell(&id1).unwrap();
        assert_eq!(stored_cell.data.u64(), Some(&128));
    }
}

#[test]
pub fn array_dyn_map() {
    let _ = env_logger::try_init();
    let id1 = Id::new(1, 1);
    let fields = Field::new(
        &String::from("*"),
        Type::Map,
        false,
        false,
        Some(vec![
            Field::new(
                &String::from("fixed"),
                Type::U32,
                false,
                false,
                None,
                vec![]
            ),
            dyn_map_field("dynamic")
        ]),
        vec![]
    );
    let schema = Schema::new("array_dyn_map", None, fields, false, true);
    let schemas = LocalSchemasCache::new_local("");
    schemas.new_schema(schema.clone());
    let chunks = Chunks::new(
        1,
        CHUNK_SIZE,
        Arc::new(ServerMeta { schemas }),
        None,
        None,
        None
    );
    let data = data_map_value!(
        fixed: OwnedValue::U32(42),
        dynamic: dyn_map_value()
    );
    let mut cell = OwnedCell {
        header: CellHeader::new(schema.id, &id1),
        data
    };
    chunks.write_cell(&mut cell).unwrap();
    {
        let read_cell = chunks.read_cell(&id1).unwrap().to_owned();
        assert_eq!(cell.data, read_cell.data);
    }
}

#[test]
pub fn complex_cell_sel_read() {
    let _ = env_logger::try_init();
    let id1 = Id::new(1, 1);
    let fields = complex_fields();
    let schema = Schema::new("complex", None, fields, false, true);
    let schemas = LocalSchemasCache::new_local("");
    schemas.new_schema(schema.clone());
    let chunks = Chunks::new(
        1,
        CHUNK_SIZE,
        Arc::new(ServerMeta { schemas }),
        None,
        None,
        None
    );
    let data = data_map_value!(
        id: OwnedValue::I64(128),
        strings: OwnedValue::PrimArray(OwnedPrimArray::String(vec![
            String::from("aaaa"),
            String::from("bbbb"),
            String::from("cccc")
        ])),
        num: OwnedValue::U64(256),
        nums: OwnedValue::PrimArray(OwnedPrimArray::U64(vec![
            512, 1024, 2048
        ])),
        sub: data_map_value!(
            sub1: OwnedValue::U32(4096),
            sub2: OwnedValue::PrimArray(OwnedPrimArray::U32(vec![
                8192, 16384
            ])),
            sub3: OwnedValue::U32(1),
            sub4: data_map_value!(
                sub4sub1: OwnedValue::U32(2),
                sub4sub2: OwnedValue::PrimArray(OwnedPrimArray::U32(vec![
                    3, 4, 5
                ])),
                sub4sub3: OwnedValue::PrimArray(OwnedPrimArray::U64(vec![
                    6, 7
                ])),
                sub4sub4: OwnedValue::U16(8)
            ),
            sub5: dyn_map_value(),
            subend: OwnedValue::U32(24)
        )
    );
    let mut cell = OwnedCell {
        header: CellHeader::new(schema.id, &id1),
        data
    };
    chunks.write_cell(&mut cell).unwrap();
    {
        let read_cell = chunks.read_cell(&id1).unwrap().to_owned();
        assert_eq!(cell.data, read_cell.data);
    }
}

fn dyn_map_value() -> OwnedValue {
    OwnedValue::Array(vec![
        data_map_value!(
            sub5sub1: OwnedValue::U32(9),
            sub5sub2: OwnedValue::PrimArray(OwnedPrimArray::U32(vec![
                10, 11
            ])),
            sub5sub3: OwnedValue::PrimArray(OwnedPrimArray::U64(vec![
                12, 13, 14
            ])),
            sub5sub4: OwnedValue::U16(15)
        ),
        data_map_value!(
            sub5sub1: OwnedValue::U32(16),
            sub5sub2: OwnedValue::PrimArray(OwnedPrimArray::U32(vec![
                17, 18, 19, 20
            ])),
            sub5sub3: OwnedValue::PrimArray(OwnedPrimArray::U64(vec![
                21, 22
            ])),
            sub5sub4: OwnedValue::U16(23)
        )
    ])
}<|endoftext|>


<commit_before>use std;
use std::collections::HashMap;
use std::process::Command;

use super::*;
use super::value::{Identifier, Obj, Value};

pub struct Context {
    pub vars: HashMap<String, Value>,
    pub msgs: HashMap<String, Obj>,
}

impl Context {
    pub fn set_env(&self, cmd: &mut Command) {
        for (k, v) in Value::to_env(&self.vars) {
            cmd.env(k, v);
        }
        for (topic, msg) in &self.msgs {
            for (k, v) in Value::to_env(&msg) {
                cmd.env(vec![topic.clone(), k.to_string()].join("__"), v);
            }
        }
        let path = std::env::var_os("PATH").unwrap_or(std::ffi::OsString::new());
        let exe_path = std::env::current_exe().unwrap();
        let exec_dir = std::path::Path::new(&exe_path).parent().unwrap();
        let mut new_path = std::env::split_paths(&path).collect::<Vec<_>>();
        new_path.insert(0, exec_dir.to_path_buf());
        cmd.env("PATH", std::env::join_paths(new_path).unwrap());
    }

    pub fn get_msg<'a>(&'a mut self, topic: &str, key: &Identifier) -> Option<&'a Value> {
        match self.msgs.get(topic) {
            Some(ref obj) => key.get(obj),
            None => None,
        }
    }

    pub fn get_var<'b>(&'b mut self, key: &Identifier) -> Option<&'b Value> {
        key.get(&mut self.vars)
    }

    pub fn set_var(&mut self, key: &Identifier, value: Value) {
        key.set(&mut self.vars, value)
    }

    pub fn unset_var(&mut self, key: &Identifier) {
        key.unset(&mut self.vars)
    }
}
<commit_msg>Clean up imports.<commit_after>use std;
use std::collections::HashMap;
use std::process::Command;

use super::value::{Identifier, Obj, Value};

pub struct Context {
    pub vars: HashMap<String, Value>,
    pub msgs: HashMap<String, Obj>,
}

impl Context {
    pub fn set_env(&self, cmd: &mut Command) {
        for (k, v) in Value::to_env(&self.vars) {
            cmd.env(k, v);
        }
        for (topic, msg) in &self.msgs {
            for (k, v) in Value::to_env(&msg) {
                cmd.env(vec![topic.clone(), k.to_string()].join("__"), v);
            }
        }
        let path = std::env::var_os("PATH").unwrap_or(std::ffi::OsString::new());
        let exe_path = std::env::current_exe().unwrap();
        let exec_dir = std::path::Path::new(&exe_path).parent().unwrap();
        let mut new_path = std::env::split_paths(&path).collect::<Vec<_>>();
        new_path.insert(0, exec_dir.to_path_buf());
        cmd.env("PATH", std::env::join_paths(new_path).unwrap());
    }

    pub fn get_msg<'a>(&'a mut self, topic: &str, key: &Identifier) -> Option<&'a Value> {
        match self.msgs.get(topic) {
            Some(ref obj) => key.get(obj),
            None => None,
        }
    }

    pub fn get_var<'b>(&'b mut self, key: &Identifier) -> Option<&'b Value> {
        key.get(&mut self.vars)
    }

    pub fn set_var(&mut self, key: &Identifier, value: Value) {
        key.set(&mut self.vars, value)
    }

    pub fn unset_var(&mut self, key: &Identifier) {
        key.unset(&mut self.vars)
    }
}
<|endoftext|>


<commit_before>///! Provides the simplest and worst sampling method, the Uniform sampler takes
///! a single sample at the center of each pixel in its region

use sampler::Sampler;

/// Uniform sampler that takes one sample per pixel at the center of each pixel
#[deriving(Copy, Show)]
pub struct Uniform {
    /// Current coordinates of the pixel to sample (x, y)
    current: (u32, u32),
    /// Coordinates of the start of region being sampled (x, y)
    start: (u32, u32),
    /// Coordinates of the end of the region being sampled (x, y)
    end: (u32, u32),
    /// Dimensions of the region being sampled
    dimensions: (u32, u32),
}

impl Uniform {
    /// Create a uniform sampler to sample the image in `dimension.0 * dimension.1`
    /// sized blocks, selected in Morton order via `select_block`
    pub fn new(dimensions: (u32, u32)) -> Uniform {
        Uniform { current: (0, 0), start: (0, 0),
                  end: dimensions, dimensions: dimensions }
    }
}

impl Sampler for Uniform {
    fn get_samples(&mut self, samples: &mut Vec<(f32, f32)>) {
        samples.clear();
        if !self.has_samples() {
            return;
        }
        samples.push((self.current.0 as f32 + 0.5, self.current.1 as f32 + 0.5));
        self.current.0 += 1;
        if self.current.0 == self.end.0 {
            self.current.0 = self.start.0;
            self.current.1 += 1;
        }
    }
    fn max_spp(&self) -> uint { 1 }
    fn has_samples(&self) -> bool { self.current.1 != self.end.1 }
    fn dimensions(&self) -> (u32, u32) { self.dimensions }
    fn select_block(&mut self, start: &(u32, u32)) {
        self.start.0 = start.0 * self.dimensions.0;
        self.start.1 = start.1 * self.dimensions.1;
        self.end.0 = self.start.0 + self.dimensions.0;
        self.end.1 = self.start.1 + self.dimensions.1;
        self.current.0 = self.start.0;
        self.current.1 = self.start.1;
    }
}

<commit_msg>Fix doc comments in sampler::uniform<commit_after>//! Provides the simplest and worst sampling method, the Uniform sampler takes
//! a single sample at the center of each pixel in its region

use sampler::Sampler;

/// Uniform sampler that takes one sample per pixel at the center of each pixel
#[deriving(Copy, Show)]
pub struct Uniform {
    /// Current coordinates of the pixel to sample (x, y)
    current: (u32, u32),
    /// Coordinates of the start of region being sampled (x, y)
    start: (u32, u32),
    /// Coordinates of the end of the region being sampled (x, y)
    end: (u32, u32),
    /// Dimensions of the region being sampled
    dimensions: (u32, u32),
}

impl Uniform {
    /// Create a uniform sampler to sample the image in `dimension.0 * dimension.1`
    /// sized blocks, selected in Morton order via `select_block`
    pub fn new(dimensions: (u32, u32)) -> Uniform {
        Uniform { current: (0, 0), start: (0, 0),
                  end: dimensions, dimensions: dimensions }
    }
}

impl Sampler for Uniform {
    fn get_samples(&mut self, samples: &mut Vec<(f32, f32)>) {
        samples.clear();
        if !self.has_samples() {
            return;
        }
        samples.push((self.current.0 as f32 + 0.5, self.current.1 as f32 + 0.5));
        self.current.0 += 1;
        if self.current.0 == self.end.0 {
            self.current.0 = self.start.0;
            self.current.1 += 1;
        }
    }
    fn max_spp(&self) -> uint { 1 }
    fn has_samples(&self) -> bool { self.current.1 != self.end.1 }
    fn dimensions(&self) -> (u32, u32) { self.dimensions }
    fn select_block(&mut self, start: &(u32, u32)) {
        self.start.0 = start.0 * self.dimensions.0;
        self.start.1 = start.1 * self.dimensions.1;
        self.end.0 = self.start.0 + self.dimensions.0;
        self.end.1 = self.start.1 + self.dimensions.1;
        self.current.0 = self.start.0;
        self.current.1 = self.start.1;
    }
}

<|endoftext|>