forked from M-Labs/artiq
firmware: use &CSlice for lists
This commit is contained in:
parent
eb6817c8f1
commit
ebfeb1869f
@ -15,7 +15,7 @@ extern crate proto_artiq;
|
||||
extern crate riscv;
|
||||
|
||||
use core::{mem, ptr, slice, str, convert::TryFrom};
|
||||
use cslice::{CSlice, AsCSlice};
|
||||
use cslice::CSlice;
|
||||
use io::Cursor;
|
||||
use dyld::Library;
|
||||
use board_artiq::{mailbox, rpc_queue};
|
||||
@ -190,13 +190,12 @@ fn terminate(exceptions: &'static [Option<eh_artiq::Exception<'static>>],
|
||||
}
|
||||
|
||||
#[unwind(aborts)]
|
||||
extern fn cache_get<'a>(ret: &'a mut CSlice<i32>, key: &CSlice<u8>) -> &'a CSlice<'a, i32> {
|
||||
extern fn cache_get<'a>(key: &CSlice<u8>) -> *const CSlice<'a, i32> {
|
||||
send(&CacheGetRequest {
|
||||
key: str::from_utf8(key.as_ref()).unwrap()
|
||||
});
|
||||
recv!(&CacheGetReply { value } => {
|
||||
*ret = value.as_c_slice();
|
||||
ret
|
||||
value
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::fmt;
|
||||
use cslice::CSlice;
|
||||
use dyld;
|
||||
|
||||
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x45000000;
|
||||
@ -53,7 +54,7 @@ pub enum Message<'a> {
|
||||
RpcFlush,
|
||||
|
||||
CacheGetRequest { key: &'a str },
|
||||
CacheGetReply { value: &'static [i32] },
|
||||
CacheGetReply { value: *const CSlice<'static, i32> },
|
||||
CachePutRequest { key: &'a str, value: &'a [i32] },
|
||||
CachePutReply { succeeded: bool },
|
||||
|
||||
|
@ -70,16 +70,17 @@ unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
||||
Tag::List(it) => {
|
||||
#[repr(C)]
|
||||
struct List { elements: *mut (), length: u32 }
|
||||
consume_value!(List, |ptr| {
|
||||
(*ptr).length = reader.read_u32()?;
|
||||
let length = (*ptr).length as usize;
|
||||
|
||||
consume_value!(*mut List, |ptr| {
|
||||
let tag = it.clone().next().expect("truncated tag");
|
||||
let padding = if let Tag::Int64 | Tag::Float64 = tag { 4 } else { 0 };
|
||||
let mut data = alloc(tag.size() * length + padding)?;
|
||||
|
||||
data = data.offset(alignment_offset(tag.alignment() as isize, data as isize));
|
||||
let length = reader.read_u32()? as usize;
|
||||
let data = alloc(tag.size() * length + padding + 8)? as *mut u8;
|
||||
*ptr = data as *mut List;
|
||||
let ptr = data as *mut List;
|
||||
let mut data = data.offset(8 + alignment_offset(tag.alignment() as isize, data as isize)) as *mut ();
|
||||
|
||||
(*ptr).length = length as u32;
|
||||
(*ptr).elements = data;
|
||||
match tag {
|
||||
Tag::Bool => {
|
||||
@ -221,11 +222,11 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||
Tag::List(it) => {
|
||||
#[repr(C)]
|
||||
struct List { elements: *const (), length: u32 }
|
||||
consume_value!(List, |ptr| {
|
||||
let length = (*ptr).length as usize;
|
||||
writer.write_u32((*ptr).length)?;
|
||||
consume_value!(&List, |ptr| {
|
||||
let length = (**ptr).length as usize;
|
||||
writer.write_u32((**ptr).length)?;
|
||||
let tag = it.clone().next().expect("truncated tag");
|
||||
let mut data = (*ptr).elements;
|
||||
let mut data = (**ptr).elements;
|
||||
writer.write_u8(tag.as_u8())?;
|
||||
match tag {
|
||||
// we cannot use NativeEndian::from_slice_i32 as the data is not mutable,
|
||||
|
@ -1,27 +1,50 @@
|
||||
use alloc::{vec::Vec, string::String, collections::btree_map::BTreeMap};
|
||||
use cslice::{CSlice, AsCSlice};
|
||||
use core::mem::transmute;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Entry {
|
||||
data: Vec<i32>,
|
||||
slice: CSlice<'static, i32>,
|
||||
borrowed: bool
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
impl core::fmt::Debug for Entry {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("Entry")
|
||||
.field("data", &self.data)
|
||||
.field("borrowed", &self.borrowed)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Cache {
|
||||
entries: BTreeMap<String, Entry>
|
||||
entries: BTreeMap<String, Entry>,
|
||||
empty: CSlice<'static, i32>,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Cache {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("Cache")
|
||||
.field("entries", &self.entries)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
pub fn new() -> Cache {
|
||||
Cache { entries: BTreeMap::new() }
|
||||
let empty_vec = vec![];
|
||||
let empty = unsafe {
|
||||
transmute::<CSlice<'_, i32>, CSlice<'static, i32>>(empty_vec.as_c_slice())
|
||||
};
|
||||
Cache { entries: BTreeMap::new(), empty }
|
||||
}
|
||||
|
||||
pub fn get(&mut self, key: &str) -> *const [i32] {
|
||||
pub fn get(&mut self, key: &str) -> *const CSlice<'static, i32> {
|
||||
match self.entries.get_mut(key) {
|
||||
None => &[],
|
||||
None => &self.empty,
|
||||
Some(ref mut entry) => {
|
||||
entry.borrowed = true;
|
||||
&entry.data[..]
|
||||
&entry.slice
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,12 +55,21 @@ impl Cache {
|
||||
Some(ref mut entry) => {
|
||||
if entry.borrowed { return Err(()) }
|
||||
entry.data = Vec::from(data);
|
||||
unsafe {
|
||||
entry.slice = transmute::<CSlice<'_, i32>, CSlice<'static, i32>>(
|
||||
entry.data.as_c_slice());
|
||||
}
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let data = Vec::from(data);
|
||||
let slice = unsafe {
|
||||
transmute::<CSlice<'_, i32>, CSlice<'static, i32>>(data.as_c_slice())
|
||||
};
|
||||
self.entries.insert(String::from(key), Entry {
|
||||
data: Vec::from(data),
|
||||
data,
|
||||
slice,
|
||||
borrowed: false
|
||||
});
|
||||
Ok(())
|
||||
|
@ -418,7 +418,7 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex,
|
||||
kern_send(io, &kern::CacheGetReply {
|
||||
// Zing! This transmute is only safe because we dynamically track
|
||||
// whether the kernel has borrowed any values from the cache.
|
||||
value: unsafe { mem::transmute::<*const [i32], &'static [i32]>(value) }
|
||||
value: unsafe { mem::transmute(value) }
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user