firmware: use &CSlice for lists

This commit is contained in:
pca006132 2022-03-10 16:08:20 +08:00 committed by Sébastien Bourdeauducq
parent eb6817c8f1
commit ebfeb1869f
5 changed files with 57 additions and 24 deletions

View File

@ -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
})
}

View File

@ -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 },

View File

@ -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,

View File

@ -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(())

View File

@ -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) }
})
}