From ebfeb1869fff1f11a40bba05e19a0b4e09cb02bd Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 10 Mar 2022 16:08:20 +0800 Subject: [PATCH] firmware: use &CSlice for lists --- artiq/firmware/ksupport/lib.rs | 7 ++- artiq/firmware/libproto_artiq/kernel_proto.rs | 3 +- artiq/firmware/libproto_artiq/rpc_proto.rs | 21 ++++---- artiq/firmware/runtime/cache.rs | 48 +++++++++++++++---- artiq/firmware/runtime/session.rs | 2 +- 5 files changed, 57 insertions(+), 24 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 1a1528494..2e7346c19 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -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>], } #[unwind(aborts)] -extern fn cache_get<'a>(ret: &'a mut CSlice, key: &CSlice) -> &'a CSlice<'a, i32> { +extern fn cache_get<'a>(key: &CSlice) -> *const CSlice<'a, i32> { send(&CacheGetRequest { key: str::from_utf8(key.as_ref()).unwrap() }); recv!(&CacheGetReply { value } => { - *ret = value.as_c_slice(); - ret + value }) } diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index 3021447ec..8b07ea46b 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -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 }, diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index a93a0e82c..5750d524e 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -70,16 +70,17 @@ unsafe fn recv_value(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(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, diff --git a/artiq/firmware/runtime/cache.rs b/artiq/firmware/runtime/cache.rs index a950fab3b..ba6898653 100644 --- a/artiq/firmware/runtime/cache.rs +++ b/artiq/firmware/runtime/cache.rs @@ -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, + 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 + entries: BTreeMap, + 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<'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<'static, i32>>( + entry.data.as_c_slice()); + } return Ok(()) } } + let data = Vec::from(data); + let slice = unsafe { + transmute::, CSlice<'static, i32>>(data.as_c_slice()) + }; self.entries.insert(String::from(key), Entry { - data: Vec::from(data), + data, + slice, borrowed: false }); Ok(()) diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index bf374eb5d..aec47afe1 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -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) } }) }