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; extern crate riscv;
use core::{mem, ptr, slice, str, convert::TryFrom}; use core::{mem, ptr, slice, str, convert::TryFrom};
use cslice::{CSlice, AsCSlice}; use cslice::CSlice;
use io::Cursor; use io::Cursor;
use dyld::Library; use dyld::Library;
use board_artiq::{mailbox, rpc_queue}; use board_artiq::{mailbox, rpc_queue};
@ -190,13 +190,12 @@ fn terminate(exceptions: &'static [Option<eh_artiq::Exception<'static>>],
} }
#[unwind(aborts)] #[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 { send(&CacheGetRequest {
key: str::from_utf8(key.as_ref()).unwrap() key: str::from_utf8(key.as_ref()).unwrap()
}); });
recv!(&CacheGetReply { value } => { recv!(&CacheGetReply { value } => {
*ret = value.as_c_slice(); value
ret
}) })
} }

View File

@ -1,4 +1,5 @@
use core::fmt; use core::fmt;
use cslice::CSlice;
use dyld; use dyld;
pub const KERNELCPU_EXEC_ADDRESS: usize = 0x45000000; pub const KERNELCPU_EXEC_ADDRESS: usize = 0x45000000;
@ -53,7 +54,7 @@ pub enum Message<'a> {
RpcFlush, RpcFlush,
CacheGetRequest { key: &'a str }, CacheGetRequest { key: &'a str },
CacheGetReply { value: &'static [i32] }, CacheGetReply { value: *const CSlice<'static, i32> },
CachePutRequest { key: &'a str, value: &'a [i32] }, CachePutRequest { key: &'a str, value: &'a [i32] },
CachePutReply { succeeded: bool }, 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) => { Tag::List(it) => {
#[repr(C)] #[repr(C)]
struct List { elements: *mut (), length: u32 } struct List { elements: *mut (), length: u32 }
consume_value!(List, |ptr| { consume_value!(*mut List, |ptr| {
(*ptr).length = reader.read_u32()?;
let length = (*ptr).length as usize;
let tag = it.clone().next().expect("truncated tag"); let tag = it.clone().next().expect("truncated tag");
let padding = if let Tag::Int64 | Tag::Float64 = tag { 4 } else { 0 }; 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; (*ptr).elements = data;
match tag { match tag {
Tag::Bool => { Tag::Bool => {
@ -221,11 +222,11 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
Tag::List(it) => { Tag::List(it) => {
#[repr(C)] #[repr(C)]
struct List { elements: *const (), length: u32 } struct List { elements: *const (), length: u32 }
consume_value!(List, |ptr| { consume_value!(&List, |ptr| {
let length = (*ptr).length as usize; let length = (**ptr).length as usize;
writer.write_u32((*ptr).length)?; writer.write_u32((**ptr).length)?;
let tag = it.clone().next().expect("truncated tag"); let tag = it.clone().next().expect("truncated tag");
let mut data = (*ptr).elements; let mut data = (**ptr).elements;
writer.write_u8(tag.as_u8())?; writer.write_u8(tag.as_u8())?;
match tag { match tag {
// we cannot use NativeEndian::from_slice_i32 as the data is not mutable, // 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 alloc::{vec::Vec, string::String, collections::btree_map::BTreeMap};
use cslice::{CSlice, AsCSlice};
use core::mem::transmute;
#[derive(Debug)]
struct Entry { struct Entry {
data: Vec<i32>, data: Vec<i32>,
slice: CSlice<'static, i32>,
borrowed: bool 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 { 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 { impl Cache {
pub fn new() -> 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) { match self.entries.get_mut(key) {
None => &[], None => &self.empty,
Some(ref mut entry) => { Some(ref mut entry) => {
entry.borrowed = true; entry.borrowed = true;
&entry.data[..] &entry.slice
} }
} }
} }
@ -32,12 +55,21 @@ impl Cache {
Some(ref mut entry) => { Some(ref mut entry) => {
if entry.borrowed { return Err(()) } if entry.borrowed { return Err(()) }
entry.data = Vec::from(data); entry.data = Vec::from(data);
unsafe {
entry.slice = transmute::<CSlice<'_, i32>, CSlice<'static, i32>>(
entry.data.as_c_slice());
}
return Ok(()) 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 { self.entries.insert(String::from(key), Entry {
data: Vec::from(data), data,
slice,
borrowed: false borrowed: false
}); });
Ok(()) Ok(())

View File

@ -418,7 +418,7 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex,
kern_send(io, &kern::CacheGetReply { kern_send(io, &kern::CacheGetReply {
// Zing! This transmute is only safe because we dynamically track // Zing! This transmute is only safe because we dynamically track
// whether the kernel has borrowed any values from the cache. // whether the kernel has borrowed any values from the cache.
value: unsafe { mem::transmute::<*const [i32], &'static [i32]>(value) } value: unsafe { mem::transmute(value) }
}) })
} }