diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6665666331a97419c9d16c4b1f85730201985f88 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.10) + +set(CMAKE_CXX_STANDARD 14) + +#set(triple x86_64-pc-linux-gnu) + +#set(CMAKE_C_COMPILER gcc) +#set(CMAKE_C_COMPILER_TARGET ${triple}) +#set(CMAKE_CXX_COMPILER g++) +#set(CMAKE_CXX_COMPILER_TARGET ${triple}) + + +project(cmake_zebu_runtime_helpers) + +add_library(runtime_c_x64 STATIC src/runtime/runtime_c_x64_sysv.c) +add_library(runtime_asm_x64 STATIC src/runtime/runtime_asm_x64_sysv.S) +set_target_properties(runtime_asm_x64 PROPERTIES LINKER_LANGUAGE C) +add_library(runtime_c_aarch64 STATIC src/runtime/runtime_c_aarch64_sysv.c) +add_library(runtime_asm_aarch64 STATIC src/runtime/runtime_asm_aarch64_sysv.S) +set_target_properties(runtime_asm_aarch64 PROPERTIES LINKER_LANGUAGE C) diff --git a/Cargo.toml b/Cargo.toml index c779837902531de7b41fa1cc8f60dbc339f5d7b2..165aac9215710cb473a3d2465e49241bc293a552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,23 +40,26 @@ rodal = { git = "https://gitlab.anu.edu.au/mu/rodal", branch = "master", version libc="*" field-offset = "*" libloading = "*" -lazy_static = "0.2.11" -log = "0.3.8" -stderrlog = "0.2.3" +lazy_static = "*" +log = "*" +stderrlog = "*" num = "*" hprof = "*" memmap = "*" -memsec = "0.1.9" +memsec = "*" serde = { version = "*", features = ["derive"]} bincode = "*" serde_derive = "*" time = "*" maplit = "*" -docopt = "0.8.1" +docopt = "*" petgraph = "*" extprim = "*" num-traits = "*" built = "*" mu_gc = { path = "src/gc"} cfg-if = "*" -rand = "*" \ No newline at end of file +rand = "*" +rusty-asm = "*" +timer = "*" +chrono = "*" diff --git a/init_test_env.sh b/init_test_env.sh index 3b154b395c10a6f0f5287e4a64925d7b8897c98d..a451ab494ed03b1d592f42ed2029362152122662 100755 --- a/init_test_env.sh +++ b/init_test_env.sh @@ -1,8 +1,10 @@ #!/bin/sh export MU_ZEBU=$PWD -export ZEBU_BUILD=release +export ZEBU_BUILD=debug export CARGO_HOME=~/.cargo export CC=clang export CXX=clang++ export RUST_TEST_THREADS=1 +export RUST_BACKTRACE=1 +export MU_LOG_LEVEL=trace export LD_LIBRARY_PATH=$MU_ZEBU/target/$ZEBU_BUILD/deps/:$LD_LIBRARY_PATH diff --git a/src/ast/build.rs b/src/ast/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..209db6a061a8b1679694609482fe82f5c61c9e3e --- /dev/null +++ b/src/ast/build.rs @@ -0,0 +1,16 @@ +// Copyright 2019 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +fn main() { +} \ No newline at end of file diff --git a/src/ast/src/inst.rs b/src/ast/src/inst.rs index 21361ee1a7fe330816476967d283ffb22e86354f..522df5e6110d6fdd00d263d078180538327d4876 100644 --- a/src/ast/src/inst.rs +++ b/src/ast/src/inst.rs @@ -87,6 +87,10 @@ impl Instruction { | NewStack(_) | NewThread { .. } | NewRTThread { .. } + | NewFutex + | DeleteFutex(_) + | LockFutex(_) + | UnlockFutex(_) | AllocAU(_) | AllocAUHybrid(_,_) | NewReg(_) @@ -104,6 +108,11 @@ impl Instruction { | AffinityIsset(_,_) | GetTime | SetTime(_) + | NewTimer + | SetTimer(_,_,_,_) + | CancelTimer(_) + | DeleteTimer(_) + | Sleep(_) | NewFrameCursor(_) | GetIRef(_) | GetFieldIRef { .. } @@ -176,12 +185,21 @@ impl Instruction { | NewStack(_) | NewThread { .. } | NewRTThread { .. } + | NewFutex + | DeleteFutex(_) + | LockFutex(_) + | UnlockFutex(_) | NotifyThread(_) | SetPriority(_, _) | AffinityClear(_, _) | AffinitySet(_, _) // | AffinityZero(_) | SetTime(_) + | NewTimer + | SetTimer(_,_,_,_) + | CancelTimer(_) + | DeleteTimer(_) + | Sleep(_) | NewFrameCursor(_) | Fence(_) | Return(_) @@ -278,6 +296,10 @@ impl Instruction { | eDelete(_) | NewThread { .. } | NewRTThread { .. } + | NewFutex + | DeleteFutex(_) + | LockFutex(_) + | UnlockFutex(_) | NotifyThread(_) | SetPriority(_, _) | GetPriority(_) @@ -286,6 +308,11 @@ impl Instruction { | AffinityIsset(_, _) | GetTime | SetTime(_) + | NewTimer + | SetTimer(_,_,_,_) + | CancelTimer(_) + | DeleteTimer(_) + | Sleep(_) | NewFrameCursor(_) | GetIRef(_) | GetFieldIRef { .. } @@ -376,6 +403,10 @@ impl Instruction { | NewStack(_) | NewThread { .. } | NewRTThread { .. } + | NewFutex + | DeleteFutex(_) + | LockFutex(_) + | UnlockFutex(_) | NotifyThread(_) | SetPriority(_,_) // FIXME - Not sure about these | GetPriority(_) @@ -386,6 +417,11 @@ impl Instruction { // | AffinityZero(_) | SetTime(_) | GetTime + | NewTimer + | SetTimer(_,_,_,_) + | CancelTimer(_) + | DeleteTimer(_) + | Sleep(_) | NewFrameCursor(_) | GetIRef(_) | GetFieldIRef { .. } @@ -466,7 +502,11 @@ impl Instruction { NewStack(_) | NewThread { .. } | NewRTThread { .. } | - NotifyThread(_) | + NewFutex + | DeleteFutex(_) + | LockFutex(_) + | UnlockFutex(_) + | NotifyThread(_) | SetPriority(_,_) | NewFrameCursor(_) | GetIRef(_) | @@ -661,7 +701,7 @@ impl Instruction { // ), &Instruction_::eAlloc(ref ty) => { format!("COMMINST @uvm.eAlloc({})", ty.id()) - } + }, &Instruction_::eAllocHybrid(ref ty, var_len) => format!( "COMMINST @uvm.eAllocHybrid({}, {})", ty.id(), @@ -673,7 +713,7 @@ impl Instruction { // ), &Instruction_::eDelete(obj) => { format!("COMMINST @uvm.eDelete({})", ops[obj]) - } + }, // &Instruction_::eDeleteT( obj) => format!( // "COMMINST @uvm.eDeleteT({})", // ops[obj] @@ -693,7 +733,27 @@ impl Instruction { "NEWTHREAD {}{} {}", ops[stack], thread_local, new_stack_clause, ) - } + }, + + &Instruction_::NewFutex => format!("NEWFUTEX"), + &Instruction_::DeleteFutex(futexref) => { + format!( + "DELETEFUTEX {}", + ops[futexref] + ) + }, + &Instruction_::LockFutex(futexref) => { + format!( + "LockFUTEX {}", + ops[futexref] + ) + }, + &Instruction_::UnlockFutex(futexref) => { + format!( + "UNLOCKFUTEX {}", + ops[futexref] + ) + }, &Instruction_::NewRTThread { attr, @@ -711,11 +771,11 @@ impl Instruction { "NEWRTTHREAD {}, {}, {}, {}", ops[attr], ops[stack], thread_local, new_stack_clause, ) - } + }, &Instruction_::NotifyThread(thread) => { format!("COMMINST @uvm.notifythread({})", ops[thread]) - } + }, &Instruction_::SetPriority(thread, priority) => format!( "COMMINST @uvm.setpriority({}, {})", ops[thread], ops[priority] @@ -742,6 +802,28 @@ impl Instruction { "COMMINST @uvm.settime({})", ops[time] ), + &Instruction_::NewTimer => format!( + "COMMINST @uvm.newtimer" + ), + &Instruction_::SetTimer(tmr, tm, func, args) => format!( + "COMMINST @uvm.settimer({}, {}, {}, {})", + ops[tmr], + ops[tm], + ops[func], + ops[args] + ), + &Instruction_::CancelTimer(tmr) => format!( + "COMMINST @uvm.canceltimer({})", + ops[tmr] + ), + &Instruction_::DeleteTimer(tmr) => format!( + "COMMINST @uvm.deletetimer({})", + ops[tmr] + ), + &Instruction_::Sleep(dur) => format!( + "COMMINST @uvm.sleep_ns({})", + ops[dur] + ), &Instruction_::NewFrameCursor(stack) => { format!("COMMINST @uvm.meta.new_cursor({})", ops[stack]) } @@ -1222,6 +1304,11 @@ pub enum Instruction_ { args: Vec }, + NewFutex, + DeleteFutex(OpIndex), + LockFutex(OpIndex), + UnlockFutex(OpIndex), + // #[cfg(feature = "realtime")] /// notify a thread to start running /// args: threadref for the target thread @@ -1262,6 +1349,12 @@ pub enum Instruction_ { GetTime, SetTime(OpIndex), + NewTimer, + SetTimer(OpIndex, OpIndex, OpIndex, OpIndex), + CancelTimer(OpIndex), + DeleteTimer(OpIndex), + Sleep(OpIndex), + /// create a frame cursor reference /// args: stackref of a Mu stack NewFrameCursor(OpIndex), // stack diff --git a/src/ast/src/ir.rs b/src/ast/src/ir.rs index 556ce560f925b7d0d4816a98d16fcd552dc409f4..41d74cd554d319af2c96a5815fc58e6a8d50f125 100644 --- a/src/ast/src/ir.rs +++ b/src/ast/src/ir.rs @@ -133,12 +133,12 @@ impl fmt::Display for MuFunction { } } -/// MuFunctionVersion represents a specific definition of a Mu function -/// It owns the tree structure of MuIRs for the function version // FIXME: currently part of compilation information is also stored in this data // structure we should move them (see Issue #18) rodal_named!(MuFunctionVersion); +/// MuFunctionVersion represents a specific definition of a Mu function +/// It owns the tree structure of MuIRs for the function version pub struct MuFunctionVersion { pub hdr: MuEntityHeader, diff --git a/src/ast/src/ir_rt_linux.rs b/src/ast/src/ir_rt_linux.rs new file mode 100644 index 0000000000000000000000000000000000000000..813bfcbf541c2745c9ff12fccb67bd5e877a6b03 --- /dev/null +++ b/src/ast/src/ir_rt_linux.rs @@ -0,0 +1,22 @@ +// Copyright 2019 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate libc; + +pub type SysThreadID = libc::pthread_t; +pub type SysThreadAttr = libc::pthread_attr_t; +pub type SysPriority = libc::c_int; +pub type SysTime = libc::timespec; +pub type SysAffinityMask = libc::cpu_set_t; +pub type SysAffinitySize = libc::size_t; diff --git a/src/ast/src/types.rs b/src/ast/src/types.rs index 740178ce4654b9119954c64dbe9a7f81a6b1c7d0..10a8483874d7ea3a87332ccad34e0605c4f52733 100644 --- a/src/ast/src/types.rs +++ b/src/ast/src/types.rs @@ -70,6 +70,8 @@ lazy_static! { P(MuType::new(new_internal_id(), MuType_::stackref())); pub static ref THREADREF_TYPE: P = P(MuType::new(new_internal_id(), MuType_::threadref())); + pub static ref FUTEXREF_TYPE: P = + P(MuType::new(new_internal_id(), MuType_::futexref())); } #[cfg(not(feature = "realtime"))] @@ -90,6 +92,7 @@ lazy_static! { IREF_VOID_TYPE.clone(), STACKREF_TYPE.clone(), THREADREF_TYPE.clone(), + FUTEXREF_TYPE.clone(), UPTR_U8_TYPE.clone(), UPTR_U64_TYPE.clone() ]; @@ -130,6 +133,7 @@ lazy_static! { RTATTR_TYPE.clone(), UPTR_RTATTR_TYPE.clone(), REGREF_TYPE.clone(), + FUTEXREF_TYPE.clone(), ]; } @@ -244,7 +248,7 @@ impl MuType { pub fn is_opaque_reference(&self) -> bool { match self.v { - MuType_::FuncRef(_) | MuType_::StackRef | MuType_::ThreadRef => { + MuType_::FuncRef(_) | MuType_::StackRef | MuType_::ThreadRef | MuType_::FutexRef => { true } @@ -306,6 +310,7 @@ impl MuType { | MuType_::ThreadRef | MuType_::StackRef | MuType_::Tagref64 + | MuType_::FutexRef | MuType_::UPtr(_) => true, #[cfg(feature = "realtime")] MuType_::RTAttr @@ -536,7 +541,7 @@ impl MuType { use types::MuType_::*; match self.v { Int(len) => Some(len), - Ref(_) | IRef(_) | WeakRef(_) | UPtr(_) | ThreadRef | StackRef + Ref(_) | IRef(_) | WeakRef(_) | UPtr(_) | ThreadRef | StackRef | FutexRef | Tagref64 | FuncRef(_) | UFuncPtr(_) => Some(64), #[cfg(feature = "realtime")] @@ -573,17 +578,17 @@ impl MuType { } // #[cfg(feature = "realtime")] - pub fn containsIRef(&self) -> bool { + pub fn contains_iref(&self) -> bool { let res = match &self.v { MuType_::IRef(_) => true, MuType_::Array(ty, size) => ty.is_iref() && *size > 0, MuType_::Struct(tag) => { - let structMap = STRUCT_TAG_MAP.read().unwrap(); - let _struct: &StructType_ = structMap.get(tag).unwrap(); + let struct_map = STRUCT_TAG_MAP.read().unwrap(); + let _struct: &StructType_ = struct_map.get(tag).unwrap(); let _types = _struct.get_tys(); for _type in _types { - if _type.is_iref() || _type.containsIRef() { + if _type.is_iref() || _type.contains_iref() { return true; } } @@ -597,12 +602,12 @@ impl MuType { let var_ty = _hybrid.get_var_ty(); for _type in fix_tys.iter() { - if _type.is_iref() || _type.containsIRef() { + if _type.is_iref() || _type.contains_iref() { return true; } } - if var_ty.is_iref() || var_ty.containsIRef() { + if var_ty.is_iref() || var_ty.contains_iref() { return true; } @@ -667,6 +672,8 @@ pub enum MuType_ { /// ufuncptr<@sig> UFuncPtr(P), + FutexRef, + /// RTMu-specific /// Real-Time Threads' attributes #[cfg(feature = "realtime")] @@ -690,12 +697,12 @@ impl MuType_ { #[cfg(not(feature = "realtime"))] rodal_enum!(MuType_{(Int: size), Float, Double, (Ref: ty), (IRef: ty), (WeakRef: ty), (UPtr: ty), - (Struct: tag), (Array: ty, size), (Hybrid: tag), Void, ThreadRef, StackRef, Tagref64, + (Struct: tag), (Array: ty, size), (Hybrid: tag), Void, ThreadRef, StackRef, FutexRef, Tagref64, (Vector: ty, size), (FuncRef: ty), (UFuncPtr: ty)}); #[cfg(feature = "realtime")] rodal_enum!(MuType_{(Int: size), Float, Double, (Ref: ty), (IRef: ty), (WeakRef: ty), (UPtr: ty), - (Struct: tag), (Array: ty, size), (Hybrid: tag), Void, ThreadRef, RegionRef, TimerRef, TimeVal, RTAttr, StackRef, Tagref64, + (Struct: tag), (Array: ty, size), (Hybrid: tag), Void, ThreadRef, RegionRef, TimerRef, FutexRef, TimeVal, RTAttr, StackRef, Tagref64, (Vector: ty, size), (FuncRef: ty), (UFuncPtr: ty)}); impl fmt::Display for MuType { @@ -708,7 +715,7 @@ impl fmt::Display for MuType_ { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &MuType_::Int(n) => write!(f, "int<{}>", n), - &MuType_::Float => write!(f, "float"), + &MuType_::Float => write!(f,"float"), &MuType_::Double => write!(f, "double"), &MuType_::Ref(ref ty) => write!(f, "ref<{}>", ty), &MuType_::IRef(ref ty) => write!(f, "iref<{}>", ty), @@ -719,6 +726,7 @@ impl fmt::Display for MuType_ { } &MuType_::Void => write!(f, "void"), &MuType_::ThreadRef => write!(f, "threadref"), + &MuType_::FutexRef => write!(f, "futexref"), #[cfg(feature = "realtime")] &MuType_::RTAttr => write!(f, "rtattr"), @@ -901,6 +909,9 @@ impl MuType_ { pub fn threadref() -> MuType_ { MuType_::ThreadRef } + pub fn futexref() -> MuType_ { + MuType_::FutexRef + } #[cfg(feature = "realtime")] pub fn rtattr() -> MuType_ { diff --git a/src/compiler/backend/arch/x86_64/asm_backend.rs b/src/compiler/backend/arch/x86_64/asm_backend.rs index 40aa15fe8fcd22945fe5dc345278bd9bde401405..7dce4e04993a5d0a4d0db1d90ac8ae66a8414db3 100644 --- a/src/compiler/backend/arch/x86_64/asm_backend.rs +++ b/src/compiler/backend/arch/x86_64/asm_backend.rs @@ -4103,7 +4103,7 @@ fn check_align(align: ByteSize) -> ByteSize { /// writes alignment in bytes for linux #[cfg(target_os = "linux")] fn write_align(f: &mut File, align: ByteSize) { - use std::io::Write; + // use std::io::Write; f.write_fmt(format_args!("\t.align {}\n", check_align(align))) .unwrap(); } @@ -4126,7 +4126,7 @@ fn write_align(f: &mut File, align: ByteSize) { /// writes a constant to assembly output fn write_const(f: &mut File, constant: P, loc: P) { - use std::io::Write; + // use std::io::Write; // label let label = match loc.v { @@ -4147,7 +4147,7 @@ fn write_const(f: &mut File, constant: P, loc: P) { /// writes a constant value based on its type and value fn write_const_value(f: &mut File, constant: P) { - use std::io::Write; + // use std::io::Write; let ref ty = constant.ty; @@ -4415,7 +4415,7 @@ pub fn emit_context_with_reloc( // Deserializing from this is extremely slow, we need to fix this. See Issue // #41 trace!("start serializing vm"); - use rodal; + // use rodal; // use std::time::Instant; // let now = Instant::now(); @@ -4462,7 +4462,7 @@ fn write_obj_header(f: &mut File, obj: &ObjectEncode) { /// writes raw bytes from memory between from_address (inclusive) to to_address /// (exclusive) fn write_data_bytes(f: &mut File, from: Address, to: Address) { - use std::io::Write; + // use std::io::Write; if from < to { f.write("\t.byte ".as_bytes()).unwrap(); diff --git a/src/compiler/backend/arch/x86_64/inst_sel.rs b/src/compiler/backend/arch/x86_64/inst_sel.rs index 9cf786efc63e30b12d55561d3db878f309b8374a..e27573507a9880e03d779cca3eca8e24a2058ffe 100644 --- a/src/compiler/backend/arch/x86_64/inst_sel.rs +++ b/src/compiler/backend/arch/x86_64/inst_sel.rs @@ -1863,7 +1863,7 @@ impl<'a> InstructionSelection { | MemoryOrder::SeqCst | MemoryOrder::NotAtomic => {} _ => panic!( - "unsupported ofrder {:?} for LOAD", + "unsupported order {:?} for LOAD", order ) } @@ -2127,7 +2127,7 @@ impl<'a> InstructionSelection { // FIXME: the semantic of Pin/Unpin is different from spec // See Issue #33 Instruction_::CommonInst_Pin(op) => { - use runtime::mm::GC_MOVES_OBJECT; + // use runtime::mm::GC_MOVES_OBJECT; trace!("instsel on PIN"); // call pin() in GC @@ -2156,7 +2156,7 @@ impl<'a> InstructionSelection { } } Instruction_::CommonInst_Unpin(op) => { - use runtime::mm::GC_MOVES_OBJECT; + // use runtime::mm::GC_MOVES_OBJECT; trace!("instsel on UNPIN"); // call unpin() in GC @@ -2372,9 +2372,7 @@ impl<'a> InstructionSelection { let tmp_region = self.emit_ireg(region, f_content, f_context, vm); - let ty_info = vm.get_backend_type_info(ty.id()); - - if ty.containsIRef() { + if ty.contains_iref() { let ty_id: MuID = ty.id(); let tmp_id = self.make_int64_const(ty_id as u64, vm); @@ -2416,7 +2414,7 @@ impl<'a> InstructionSelection { assert!(ty.is_hybrid()); let ty_info = vm.get_backend_type_info(ty.id()); - let ty_align = ty_info.alignment; + // let ty_align = ty_info.alignment; let fix_part_size = ty_info.size; let var_ty_size = match ty_info.elem_size { Some(sz) => sz, @@ -2434,7 +2432,7 @@ impl<'a> InstructionSelection { self.emit_ireg(region, f_content, f_context, vm); // if the type contains iref to heap objects - if ty.containsIRef() { + if ty.contains_iref() { let ty_id: MuID = ty.id(); let tmp_id = self.make_int64_const(ty_id as u64, vm); @@ -2506,10 +2504,10 @@ impl<'a> InstructionSelection { trace!("instsel on eAlloc: {}", ty.print_details()); assert!(!ty.is_hybrid()); - let ty_info = vm.get_backend_type_info(ty.id()); + // let ty_info = vm.get_backend_type_info(ty.id()); let tmp_res = self.get_result_value(node); - if ty.containsIRef() { + if ty.contains_iref() { let ty_id: MuID = ty.id(); let tmp_id = self.make_int64_const(ty_id as u64, vm); @@ -2550,7 +2548,7 @@ impl<'a> InstructionSelection { assert!(ty.is_hybrid()); let ty_info = vm.get_backend_type_info(ty.id()); - let ty_align = ty_info.alignment; + // let ty_align = ty_info.alignment; let fix_part_size = ty_info.size; let var_ty_size = match ty_info.elem_size { Some(sz) => sz, @@ -2564,7 +2562,7 @@ impl<'a> InstructionSelection { let tmp_res = self.get_result_value(node); // if the type contains iref to heap objects - if ty.containsIRef() { + if ty.contains_iref() { let ty_id: MuID = ty.id(); let tmp_id = self.make_int64_const(ty_id as u64, vm); @@ -2882,6 +2880,80 @@ impl<'a> InstructionSelection { // vm, // ); // } + + Instruction_::NewFutex => { + trace!("instsel on NewFutex"); + + let res = self.get_result_value(node); + + self.emit_runtime_entry( + &entrypoints::NEW_FUTEX, + vec![], + Some(vec![res]), + Some(node), + f_content, + f_context, + vm + ); + } + Instruction_::DeleteFutex(futexref) => { + trace!("instsel on DeleteFutex"); + + let ref ops = inst.ops; + let ref futexref = ops[futexref]; + + let tmp_futex = + self.emit_ireg(futexref, f_content, f_context, vm); + + self.emit_runtime_entry( + &entrypoints::DELETE_FUTEX, + vec![tmp_futex], + None, + Some(node), + f_content, + f_context, + vm + ); + } + Instruction_::LockFutex(futexref) => { + trace!("instsel on LockFutex"); + + let ref ops = inst.ops; + let ref futexref = ops[futexref]; + + let tmp_futex = + self.emit_ireg(futexref, f_content, f_context, vm); + + self.emit_runtime_entry( + &entrypoints::LOCK_FUTEX, + vec![tmp_futex], + None, + Some(node), + f_content, + f_context, + vm + ); + } + Instruction_::UnlockFutex(futexref) => { + trace!("instsel on UnlockFutex"); + + let ref ops = inst.ops; + let ref futexref = ops[futexref]; + + let tmp_futex = + self.emit_ireg(futexref, f_content, f_context, vm); + + self.emit_runtime_entry( + &entrypoints::UNLOCK_FUTEX, + vec![tmp_futex], + None, + Some(node), + f_content, + f_context, + vm + ); + } + #[cfg(feature = "realtime")] Instruction_::GetPriority(thread) => { trace!("instsel on GetPriority"); @@ -3041,6 +3113,110 @@ impl<'a> InstructionSelection { ); } + #[cfg(feature = "realtime")] + Instruction_::NewTimer => { + trace!("instsel on NewTimer"); + + let res = self.get_result_value(node); + + self.emit_runtime_entry( + &entrypoints::NEWTIMER, + vec![], + Some(vec![res.clone()]), + Some(node), + f_content, + f_context, + vm + ); + } + + #[cfg(feature = "realtime")] + Instruction_::SetTimer(tmr, tm, func, args) => { + trace!("instsel on SetTimer"); + + let ref ops = inst.ops; + let ref tmr = ops[tmr]; + let ref tm = ops[tm]; + let ref func = ops[func]; + let ref args = ops[args]; + + let tmp_tmr= self.emit_ireg(tmr, f_content, f_context, vm); + let tmp_tm= self.emit_ireg(tm, f_content, f_context, vm); + let tmp_func= self.emit_ireg(func, f_content, f_context, vm); + let tmp_args= self.emit_ireg(args, f_content, f_context, vm); + + self.emit_runtime_entry( + &entrypoints::SETTIMER, + vec![tmp_tmr, tmp_tm, tmp_func, tmp_args], + None, + Some(node), + f_content, + f_context, + vm + ); + } + + #[cfg(feature = "realtime")] + Instruction_::CancelTimer(tmr) => { + trace!("instsel on CancelTimer"); + + let ref ops = inst.ops; + let ref tmr = ops[tmr]; + + let tmp_tmr= self.emit_ireg(tmr, f_content, f_context, vm); + + self.emit_runtime_entry( + &entrypoints::CANCELTIMER, + vec![tmp_tmr], + None, + Some(node), + f_content, + f_context, + vm + ); + } + + #[cfg(feature = "realtime")] + Instruction_::DeleteTimer(tmr) => { + trace!("instsel on DeleteTimer"); + + let ref ops = inst.ops; + let ref tmr = ops[tmr]; + + let tmp_tmr= self.emit_ireg(tmr, f_content, f_context, vm); + + self.emit_runtime_entry( + &entrypoints::DELETETIMER, + vec![tmp_tmr], + None, + Some(node), + f_content, + f_context, + vm + ); + } + + #[cfg(feature = "realtime")] + Instruction_::Sleep(dur) => { + trace!("instsel on Sleep"); + + let ref ops = inst.ops; + let ref dur = ops[dur]; + +// let (time_h, time_l) = + let tmp_dur = self.emit_ireg(dur, f_content, f_context, vm); + + self.emit_runtime_entry( + &entrypoints::SLEEP, + vec![tmp_dur], + Some(vec![]), + Some(node), + f_content, + f_context, + vm + ); + } + Instruction_::CurrentStack => { trace!("instsel on CURRENT_STACK"); @@ -3296,8 +3472,8 @@ impl<'a> InstructionSelection { vm: &VM ) { use compiler::backend::x86_64::callconv::swapstack; - use compiler::backend::x86_64::callconv::CallConvResult; - use compiler::backend::x86_64::{ARGUMENT_FPRS, ARGUMENT_GPRS}; + // use compiler::backend::x86_64::callconv::CallConvResult; + // use compiler::backend::x86_64::{ARGUMENT_FPRS, ARGUMENT_GPRS}; let ref ops = inst.ops; @@ -5440,7 +5616,7 @@ impl<'a> InstructionSelection { conv: CallConvention, vm: &VM ) -> ByteSize { - use compiler::backend::x86_64::callconv; + // use compiler::backend::x86_64::callconv; let stack_arg_tys = stack_vals.iter().map(|x| x.ty.clone()).collect(); let (stack_arg_size_with_padding, stack_arg_offsets) = match conv { diff --git a/src/compiler/backend/arch/x86_64/mod.rs b/src/compiler/backend/arch/x86_64/mod.rs index e3d0b00e55ec44f0fbbfddcce4daf1036b12dbe1..0751abfde751b3d087ae6e23d7d76c008ab24f31 100644 --- a/src/compiler/backend/arch/x86_64/mod.rs +++ b/src/compiler/backend/arch/x86_64/mod.rs @@ -717,11 +717,17 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize { NewStack(_) | NewThread { .. } | NewRTThread { .. } + | NewFutex | DeleteFutex(_) | LockFutex(_) | UnlockFutex(_) | NotifyThread(_) | SetPriority(_, _) | GetPriority(_) | GetTime | SetTime(_) + | NewTimer + | SetTimer(_,_,_,_) + | CancelTimer(_) + | DeleteTimer(_) + | Sleep(_) | AffinityClear(_, _) | AffinitySet(_, _) | AffinityIsset(_, _) diff --git a/src/compiler/backend/mod.rs b/src/compiler/backend/mod.rs index 0c4bba5b0db76abb634ba738bbfedff2d5266c4d..3ce858681cf4f2629c05598cac7f66884c3e5dfd 100644 --- a/src/compiler/backend/mod.rs +++ b/src/compiler/backend/mod.rs @@ -270,6 +270,9 @@ impl BackendType { TypeEncode::short_noref(MINIMAL_ALIGNMENT, 1) } + MuType_::FutexRef => { + TypeEncode::short_noref(MINIMAL_ALIGNMENT, 1) + }, // RTMu-specific #[cfg(feature = "realtime")] MuType_::RegionRef @@ -400,6 +403,7 @@ impl BackendType { | MuType_::UFuncPtr(_) | MuType_::FuncRef(_) | MuType_::ThreadRef + | MuType_::FutexRef | MuType_::StackRef => { debug_assert!(pointer_aligned); res.push(WordType::NonRef); @@ -534,6 +538,7 @@ impl BackendType { | MuType_::UFuncPtr(_) | MuType_::FuncRef(_) | MuType_::ThreadRef + | MuType_::FutexRef | MuType_::StackRef => BackendType { ty: ty.clone(), size: 8, @@ -780,7 +785,7 @@ impl BackendType { MuType_::Array(_type, len) => { trace!("get_iref_offsets(Array({:?},{:?}))", _type, len); let mut cur_offset: ByteSize = 0; - for i in 0..*len { + for _i in 0..*len { BackendType::append_iref_offsets_internal( vm, _type, @@ -905,17 +910,17 @@ impl BackendType { for addr in addr_sub_list { addr_list.push(addr + *cur_offset) } - *cur_offset += (type_info.size as ByteSize); + *cur_offset += type_info.size as ByteSize; } MuType_::IRef(_) => { let type_info = vm.get_backend_type_info(mutype.id()); *cur_offset = align_up(*cur_offset as ByteSize, type_info.alignment) as ByteSize; - unsafe { - addr_list.push(*cur_offset); - } - *cur_offset += (type_info.size as ByteSize); + + addr_list.push(*cur_offset); + + *cur_offset += type_info.size as ByteSize; } MuType_::Hybrid(_) => { panic!("Hybrid must not be contained inside any types!"); @@ -925,7 +930,7 @@ impl BackendType { *cur_offset = align_up(*cur_offset as ByteSize, type_info.alignment) as ByteSize; - *cur_offset += (type_info.size as ByteSize); + *cur_offset += type_info.size as ByteSize; } } } @@ -941,7 +946,7 @@ impl fmt::Display for BackendType { ) .unwrap(); if self.struct_layout.is_some() { - use utils::vec_utils; + // use utils::vec_utils; let layout = self.struct_layout.as_ref().unwrap(); write!(f, "field offsets: ({})", vec_utils::as_str(layout)) @@ -981,6 +986,7 @@ impl RegGroup { | MuType_::StackRef | MuType_::Tagref64 | MuType_::FuncRef(_) + | MuType_::FutexRef | MuType_::UFuncPtr(_) => RegGroup::GPR, #[cfg(feature = "realtime")] diff --git a/src/compiler/passes/tree_gen.rs b/src/compiler/passes/tree_gen.rs index 5d42af6fc1184e44e6ed0110af93f25b307b9b0a..bb0677f0dbd6d73b9d04f4870f0ab5a227a74fd5 100644 --- a/src/compiler/passes/tree_gen.rs +++ b/src/compiler/passes/tree_gen.rs @@ -91,6 +91,7 @@ fn is_suitable_child(inst: &Instruction) -> bool { | NewStack(_) | NewThread { .. } | NewRTThread { .. } + | NewFutex | DeleteFutex(_) | LockFutex(_) | UnlockFutex(_) | NotifyThread(_) | SetPriority(_, _) | GetPriority(_) @@ -99,6 +100,11 @@ fn is_suitable_child(inst: &Instruction) -> bool { | AffinityClear(_, _) | GetTime | SetTime(_) + | NewTimer + | SetTimer(_,_,_,_) + | CancelTimer(_) + | DeleteTimer(_) + | Sleep(_) | NewFrameCursor(_) | Select { .. } | Fence(_) diff --git a/src/gc/src/heap/gc/clib_x64_sel4_rumprun.c b/src/gc/src/heap/gc/clib_x64_sel4_rumprun.c new file mode 100644 index 0000000000000000000000000000000000000000..ba02551510a119841d4955be3cadc0300f037603 --- /dev/null +++ b/src/gc/src/heap/gc/clib_x64_sel4_rumprun.c @@ -0,0 +1,140 @@ +// Copyright 2017 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +uintptr_t immmix_get_stack_ptr() { + uintptr_t rsp; + // get current rsp, rbp (this C func frame) + __asm__( + "mov %%rsp, %0 \n" + : "=rm" (rsp) + ); + + return rsp; +} + +int get_registers_count() { + return 16; +} + +uintptr_t* get_registers () { + uintptr_t rax, rbx, rcx, rdx, rbp, rsp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15; + + __asm__( + "mov %%rax, %0 \n" + "mov %%rbx, %1 \n" + "mov %%rcx, %2 \n" + "mov %%rdx, %3 \n" + "mov %%rbp, %4 \n" + "mov %%rsp, %5 \n" + "mov %%rsi, %5 \n" + "mov %%rdi, %6 \n" + "mov %%r8, %7 \n" + "mov %%r9, %8 \n" + "mov %%r10, %10\n" + "mov %%r11, %11\n" + "mov %%r12, %12\n" + "mov %%r13, %13\n" + "mov %%r14, %14\n" + "mov %%r15, %15\n" + : "=m" (rax), + "=m" (rbx), + "=m" (rcx), + "=m" (rdx), + "=m" (rbp), + "=m" (rsp), + "=m" (rsi), + "=m" (rdi), + "=m" (r8), + "=m" (r9), + "=m" (r10), + "=m" (r11), + "=m" (r12), + "=m" (r13), + "=m" (r14), + "=m" (r15) + : + : + ); + + uintptr_t* ret = (uintptr_t*) malloc(sizeof(uintptr_t) * 16); + ret[0] = rax; + ret[1] = rbx; + ret[2] = rcx; + ret[3] = rdx; + ret[4] = rbp; + ret[5] = rsp; + ret[6] = rsi; + ret[7] = rdi; + ret[8] = r8; + ret[9] = r9; + ret[10] = r10; + ret[11] = r11; + ret[12] = r12; + ret[13] = r13; + ret[14] = r14; + ret[15] = r15; + return ret; +} + +// __thread uintptr_t low_water_mark; + +int lwm_initialized = 0; + +static pthread_key_t low_water_mark; + +void set_low_water_mark () { + uintptr_t rsp; + + if(lwm_initialized == 0){ + lwm_initialized = 1; + int result = pthread_key_create(&low_water_mark, NULL); + if(result != 0){ + printf("set_low_water_mark(): PThread key create failed with error code = %d\n", result); + assert(0); + } + } + + // get current rsp, rbp (this C func frame) + __asm__( + "mov %%rsp, %0 \n" + : "=rm" (rsp) + ); + + int result = pthread_setspecific(low_water_mark, (const void *) rsp); + if(result != 0){ + printf("set_low_water_mark(): PThread set specific failed with error code = %d\n", result); + assert(0); + } +} + +uintptr_t get_low_water_mark() { + + if(lwm_initialized == 0){ + printf("get_low_water_mark(): PThread key MUST be initialized before first use!!\n"); + } + void * result = pthread_getspecific(low_water_mark); + if(result == NULL){ + printf("get_low_water_mark(): NO pthread key found for current thread!!\n"); + assert(0); + } + + return (uintptr_t) result; +} diff --git a/src/gc/src/heap/immix/immix_space.rs b/src/gc/src/heap/immix/immix_space.rs index af88a84ac6ecf2b5f6536b42ecc4014af22d9f15..66fb0d35793392ea1dc03b3c0b73b7cd76588338 100644 --- a/src/gc/src/heap/immix/immix_space.rs +++ b/src/gc/src/heap/immix/immix_space.rs @@ -338,7 +338,7 @@ impl ImmixSpace { space.total_blocks = space_size >> LOG_BYTES_IN_BLOCK; unsafe { // use ptr::write to avoid destruction of the old values - use std::ptr; + // use std::ptr; ptr::write( &mut space.usable_blocks as *mut Mutex>>, diff --git a/src/linkutils/aot.rs b/src/linkutils/aot.rs index e98f7fdda2b492d6168d56af808b8e61e7fac310..b85d5589c45f90455370efb8b045e5b906dc4057 100644 --- a/src/linkutils/aot.rs +++ b/src/linkutils/aot.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate time; +//extern crate time; use ast::ir::MuName; use compiler::backend; @@ -54,7 +54,7 @@ pub fn link_primordial(funcs: Vec, out: &str, vm: &VM) -> PathBuf { trace!("copying from {:?} to {:?}", source, dest); match fs::copy(source.as_path(), dest.as_path()) { Ok(_) => {} - Err(e) => panic!("failed to copy: {}", e) + Err(e) => panic!("failed to copy: {}", e), } // include the primordial C main @@ -80,7 +80,7 @@ pub fn link_primordial(funcs: Vec, out: &str, vm: &VM) -> PathBuf { files, &vm.vm_options.flag_bootimage_external_lib, &vm.vm_options.flag_bootimage_external_libpath, - out_path + out_path, ) } @@ -114,7 +114,7 @@ pub fn link_test_primordial(funcs: Vec, out: &str, vm: &VM) -> PathBuf { trace!("copying from {:?} to {:?}", source, dest); match fs::copy(source.as_path(), dest.as_path()) { Ok(_) => {} - Err(e) => panic!("failed to copy: {}", e) + Err(e) => panic!("failed to copy: {}", e), } // include the primordial C main @@ -140,7 +140,7 @@ pub fn link_test_primordial(funcs: Vec, out: &str, vm: &VM) -> PathBuf { files, &vm.vm_options.flag_bootimage_external_lib, &vm.vm_options.flag_bootimage_external_libpath, - out_path + out_path, ) } @@ -150,7 +150,7 @@ fn link_executable_internal( files: Vec, lib: &Vec, libpath: &Vec, - out: PathBuf + out: PathBuf, ) -> PathBuf { info!("output as {:?}", out.as_path()); @@ -179,9 +179,10 @@ fn link_executable_internal( } // dylibs used for linux if cfg!(target_os = "linux") { - cc.arg("-lpthread"); + cc.arg("-pthread"); cc.arg("-ldl"); cc.arg("-lm"); + cc.arg("-lrt"); } else if cfg!(target_os = "macos") { // TODO macos args need to be updated cc.arg("-liconv"); @@ -225,7 +226,7 @@ pub fn link_dylib_with_extra_srcs( funcs: Vec, srcs: Vec, out: &str, - vm: &VM + vm: &VM, ) -> PathBuf { let files = { let mut ret = vec![]; @@ -250,7 +251,7 @@ pub fn link_dylib_with_extra_srcs( files, &vm.vm_options.flag_bootimage_external_lib, &vm.vm_options.flag_bootimage_external_libpath, - out_path + out_path, ) } @@ -259,7 +260,7 @@ fn link_dylib_internal( files: Vec, lib: &Vec, libpath: &Vec, - out: PathBuf + out: PathBuf, ) -> PathBuf { let mut object_files: Vec = vec![]; @@ -326,7 +327,7 @@ fn link_dylib_internal( // (Issue #52) pub fn compile_fnc<'a>( fnc_name: &'static str, - build_fnc: &'a Fn() -> VM + build_fnc: &'a Fn() -> VM, ) -> ll::Library { VM::start_logging_trace(); @@ -337,7 +338,7 @@ pub fn compile_fnc<'a>( let funcs = vm.funcs().read().unwrap(); let func = match funcs.get(&func_id) { Some(func) => func.read().unwrap(), - None => panic!("cannot find function {}", fnc_name) + None => panic!("cannot find function {}", fnc_name), }; let cur_ver = match func.cur_ver { @@ -345,13 +346,13 @@ pub fn compile_fnc<'a>( None => panic!( "function {} does not have a defined current version", fnc_name - ) + ), }; let func_vers = vm.func_vers().read().unwrap(); let mut func_ver = match func_vers.get(&cur_ver) { Some(fv) => fv.write().unwrap(), - None => panic!("cannot find function version {}", cur_ver) + None => panic!("cannot find function version {}", cur_ver), }; compiler.compile(&mut func_ver); } @@ -369,7 +370,7 @@ pub fn compile_fnc<'a>( pub fn compile_fncs<'a>( entry: &'static str, fnc_names: Vec<&'static str>, - build_fnc: &'a Fn() -> VM + build_fnc: &'a Fn() -> VM, ) -> ll::Library { VM::start_logging_trace(); @@ -395,7 +396,7 @@ pub fn compile_fncs<'a>( let dylib = aot::link_dylib( fnc_names.iter().map(|x| Mu(x)).collect(), libname, - &vm + &vm, ); ll::Library::new(dylib.as_os_str()).unwrap() } @@ -423,7 +424,7 @@ pub fn run_test(vm: &VM, test_name: &str, tester_name: &str) { Arc::new(tester_name.to_string()), ], output_name.as_str(), - vm + vm, ); self::super::exec_path(executable); } @@ -432,7 +433,7 @@ pub fn run_test_2f( vm: &VM, test_name: &str, dep_name: &str, - tester_name: &str + tester_name: &str, ) { let output_name = test_name.to_string() + "_" + tester_name; let executable = link_test_primordial( @@ -442,7 +443,7 @@ pub fn run_test_2f( Arc::new(tester_name.to_string()), ], output_name.as_str(), - vm + vm, ); self::super::exec_path(executable); } @@ -454,15 +455,9 @@ pub fn run_test_2f( /// and the `func_names[1]` is the tester function's name /// and `func_names[2..]` are names of other dependent functions /// -pub fn run_test_generic( - vm: &VM, - func_names: Vec>, -) { - let output_name = (*func_names[0]).clone() + "_" + (*func_names[1].clone()).as_str(); - let executable = link_test_primordial( - func_names, - output_name.as_str(), - vm - ); +pub fn run_test_generic(vm: &VM, func_names: Vec>) { + let output_name = + (*func_names[0]).clone() + "_" + (*func_names[1].clone()).as_str(); + let executable = link_test_primordial(func_names, output_name.as_str(), vm); self::super::exec_path(executable); -} \ No newline at end of file +} diff --git a/src/linkutils/mod.rs b/src/linkutils/mod.rs index e7c2bef50122cb6d0a5658c4c8cc4518b44002af..629cf6a725566b15a5730ec3cc2e965abcf1d6ff 100644 --- a/src/linkutils/mod.rs +++ b/src/linkutils/mod.rs @@ -19,7 +19,7 @@ extern crate libloading as ll; use ast::ir::*; use compiler::*; -use std::sync::Arc; +// use std::sync::Arc; use std::os::unix::process::ExitStatusExt; use std::path::PathBuf; diff --git a/src/runtime/entrypoints.rs b/src/runtime/entrypoints.rs index fc9d4794e048181b91638edea7b6615c6377c3f9..ba378688b12b8fe64926cb8388f53f7d70eed0af 100644 --- a/src/runtime/entrypoints.rs +++ b/src/runtime/entrypoints.rs @@ -257,6 +257,33 @@ lazy_static! { vec![UINT64_TYPE.clone()], // (u128) vec![] // returns nothing ); + + pub static ref NEWTIMER: RuntimeEntrypoint = RuntimeEntrypoint::new( + "muentry_new_timer", + vec![], // () + vec![ADDRESS_TYPE.clone()] // returns timerref + ); + pub static ref SETTIMER: RuntimeEntrypoint = RuntimeEntrypoint::new( + "muentry_set_timer", + vec![ADDRESS_TYPE.clone(), UINT64_TYPE.clone(), ADDRESS_TYPE.clone(), ADDRESS_TYPE.clone()], + // (timerref, timeval, ufuncptr, uptr) + vec![] // returns timerref + ); + pub static ref CANCELTIMER: RuntimeEntrypoint = RuntimeEntrypoint::new( + "muentry_cancel_timer", + vec![ADDRESS_TYPE.clone()], // (timerref) + vec![] // returns nothing + ); + pub static ref DELETETIMER: RuntimeEntrypoint = RuntimeEntrypoint::new( + "muentry_delete_timer", + vec![ADDRESS_TYPE.clone()], // (timerref) + vec![] // returns nothing + ); + pub static ref SLEEP: RuntimeEntrypoint = RuntimeEntrypoint::new( + "muentry_sleep_ns", + vec![UINT64_TYPE.clone()], // (u64) + vec![] // returns nothing + ); } // impl/decl: gc/lib.rs @@ -368,6 +395,26 @@ lazy_static! { ); } +// decl: futex +lazy_static! { + pub static ref NEW_FUTEX : RuntimeEntrypoint = RuntimeEntrypoint::new( + "muentry_futex_new", + vec![], + vec![ADDRESS_TYPE.clone()]); + pub static ref DELETE_FUTEX : RuntimeEntrypoint = RuntimeEntrypoint::new( + "muentry_futex_delete", + vec![ADDRESS_TYPE.clone()], + vec![]); + pub static ref LOCK_FUTEX : RuntimeEntrypoint = RuntimeEntrypoint::new( + "muentry_futex_lock", + vec![ADDRESS_TYPE.clone()], + vec![]); + pub static ref UNLOCK_FUTEX : RuntimeEntrypoint = RuntimeEntrypoint::new( + "muentry_futex_unlock", + vec![ADDRESS_TYPE.clone()], + vec![]); +} + // decl: exception.rs lazy_static! { // impl: exception.rs diff --git a/src/runtime/exception.rs b/src/runtime/exception.rs index fd1bdbbd16a99361e6a862affbc2ceee9c29852f..60cce5fbf721e0f3a524de936fcddec07fa8dcde 100644 --- a/src/runtime/exception.rs +++ b/src/runtime/exception.rs @@ -174,7 +174,7 @@ fn print_backtrace( base: Address, compiled_callsite_table: &HashMap ) { - if log::max_log_level() < log::LogLevelFilter::Debug { + if log::max_level() < log::LevelFilter::Debug { return; } diff --git a/src/runtime/futex/futex_rtmu.rs b/src/runtime/futex/futex_rtmu.rs new file mode 100644 index 0000000000000000000000000000000000000000..58948ccd957516aa0bfb1c62277c42a0b5389f9c --- /dev/null +++ b/src/runtime/futex/futex_rtmu.rs @@ -0,0 +1,47 @@ +// Copyright 2019 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +use std::boxed::Box; +use super::*; + +#[cfg(target_os = "linux")] +use super::futex_rtmu_linux::*; + +#[no_mangle] +pub extern "C" fn muentry_futex_new() -> Address { + sys_rtmu_futex::new() +} + +#[no_mangle] +pub extern "C" fn muentry_futex_delete(f: Address) { + sys_rtmu_futex::delete(f); +} + +#[no_mangle] +pub extern "C" fn muentry_futex_lock( + futex_addr: Address, + timeout_ns: u64, +) { + let the_futex: &mut sys_rtmu_futex = unsafe { futex_addr.to_ref_mut() }; + the_futex.lock(timeout_ns); +} + +#[no_mangle] +pub extern "C" fn muentry_futex_unlock( + futex_addr: Address, +) { + let the_futex: &mut sys_rtmu_futex = unsafe { futex_addr.to_ref_mut() }; + the_futex.unlock(); +} \ No newline at end of file diff --git a/src/runtime/futex/futex_rtmu_linux.rs b/src/runtime/futex/futex_rtmu_linux.rs new file mode 100644 index 0000000000000000000000000000000000000000..6fc0ed29520cff8c25f29b26a560f6b0db9e197f --- /dev/null +++ b/src/runtime/futex/futex_rtmu_linux.rs @@ -0,0 +1,152 @@ +// Copyright 2019 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +use std::sync::atomic::{AtomicU32, Ordering}; + +use super::*; +// use super::futex_rtmu::*; + +pub(super) type OsTidT = libc::pid_t; + +#[repr(C)] +#[repr(align(8))] +pub(super) struct sys_rtmu_futex { + pub mem: AtomicU32, +} + +impl sys_rtmu_futex { + pub fn new() -> Address { + let fbox = Box::new( + sys_rtmu_futex { + mem: AtomicU32::new(0) + } + ); + + Address::from_mut_ptr(Box::into_raw(fbox)) + } + + pub fn delete(f: Address) { + unsafe { Box::from_raw(Address::to_ptr_mut(&f) as *mut sys_rtmu_futex) }; + } + + pub fn lock(&mut self, timeout_ns: u64) { + let my_tid = os_gettid(); + match self.mem.compare_exchange( + 0 as u32, + my_tid as u32, + Ordering::SeqCst, + Ordering::SeqCst + ) { + Ok(_) => { + trace!("FUTEX.lock fastpath success"); + } + Err(id) => { + trace!("FUTEX.lock fastpath failed: #{:#?} already locked it", id); + sys_futex_lock_slowpath( + &mut self.mem as *const AtomicU32 as *const u32 as *mut u32, + timeout_ns + ); + } + } + } + + pub fn unlock(&mut self) { + let my_tid = os_gettid(); + match self.mem.compare_exchange( + my_tid as u32, + 0 as u32, + Ordering::SeqCst, + Ordering::SeqCst + ) { + Ok(_) => { + trace!("FUTEX.unlock fastpath success"); + } + Err(id) => { + trace!("FUTEX.unlock fastpath failed: futex content is #{:#?}", id); + sys_futex_unlock_slowpath( + &mut self.mem as *const AtomicU32 as *const u32 as *mut u32 + ); + } + } + } +} + +pub fn os_gettid() -> OsTidT { + unsafe { + libc::syscall(libc::SYS_gettid) as OsTidT + } +} + +fn sys_futex_lock_slowpath(futex_ptr: *mut u32, timeout_ns: u64) { + let null_ts: *mut libc::timespec = std::ptr::null_mut(); + let null_cl: *mut libc::c_long = std::ptr::null_mut(); + + let res = match timeout_ns { + 0 => { + unsafe { + libc::syscall( + libc::SYS_futex, + futex_ptr, + libc::FUTEX_LOCK_PI, + 0, + null_ts, + null_cl, + 0 + ) + } + } + _ => { + unsafe { + libc::syscall( + libc::SYS_futex, + futex_ptr, + libc::FUTEX_LOCK_PI, + 0, + &ns_to_time(timeout_ns) as *const libc::timespec, + null_cl, + 0 + ) + } + } + }; + assert_eq!(res, 0, "FUTEX.lock slowpath failed with error code #{}", res); + trace!("FUTEX.lock slowpath aquired #{:#?}", futex_ptr); +} + +fn sys_futex_unlock_slowpath(futex_ptr: *mut u32) { + let null_ts: *mut libc::timespec = std::ptr::null_mut(); + let null_cl: *mut libc::c_long = std::ptr::null_mut(); + + let res = unsafe { + libc::syscall( + libc::SYS_futex, + futex_ptr, + libc::FUTEX_UNLOCK_PI, + 0, + null_ts, + null_cl, + 0 + ) + }; + assert_eq!(res, 0, "FUTEX.unlock slowpath failed with error code #{}", res); + trace!("FUTEX.unlock slowpath released #{:#?}", futex_ptr); +} + +fn ns_to_time(ns: u64) -> libc::timespec { + libc::timespec { + tv_sec: (ns / 1_000_000_000) as i64, + tv_nsec: (ns % 1_000_000_000) as i64 + } +} \ No newline at end of file diff --git a/src/runtime/futex/mod.rs b/src/runtime/futex/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..c6220d8596d3fb6b74f8f50f2fb680c308fc3742 --- /dev/null +++ b/src/runtime/futex/mod.rs @@ -0,0 +1,35 @@ +// Copyright 2019 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// use ast::ir::*; +// use ast::ptr::*; +// use ast::types::*; +// use compiler::backend::BackendType; +// use compiler::backend::RegGroup; +// use runtime::thread::MuThread; +// use runtime::ValueLocation; +// use utils::math; +// use utils::ByteSize; +// use utils::ObjectReference; +use utils::*; +// use vm::VM; + +#[cfg(feature = "realtime")] +mod futex_rtmu; + +#[cfg(all(feature = "realtime", target_os = "linux"))] +mod futex_rtmu_linux; + +#[cfg(feature = "realtime")] +pub use self::futex_rtmu::*; \ No newline at end of file diff --git a/src/runtime/mm/mm_rtmu_std.rs b/src/runtime/mm/mm_rtmu_std.rs index 591530a3c12495531281070a7702cff3e167e514..1cfbc3d9f7a5528a3e501093e8c1217f84d7ef71 100644 --- a/src/runtime/mm/mm_rtmu_std.rs +++ b/src/runtime/mm/mm_rtmu_std.rs @@ -29,13 +29,13 @@ pub fn sys_delete_raw_mem(backstore: SysMemBackStore, size: usize) { sys_delete_mem(backstore, size) } -pub fn sys_ealloc(size: usize) -> Address { - sys_get_base_addr(sys_allocate_by_size(size)) -} +// pub fn sys_ealloc(size: usize) -> Address { +// sys_get_base_addr(sys_allocate_by_size(size)) +// } -pub fn sys_edelete(backstore: Address, size: usize) { - sys_delete_mem(backstore.to_ptr_mut() as *const u8 as *mut u8, size) -} +// pub fn sys_edelete(backstore: Address, size: usize) { +// sys_delete_mem(backstore.to_ptr_mut() as *const u8 as *mut u8, size) +// } pub fn sys_get_aligned_size(size: usize, align: usize) -> usize { if size % align == 0 { @@ -48,8 +48,8 @@ pub fn sys_get_aligned_size(size: usize, align: usize) -> usize { fn sys_allocate_by_size(size: usize) -> SysMemBackStore { let mem_layout = Box::new(match Layout::from_size_align(size, POINTER_SIZE) { - Ok(LO) => LO, - Err(ERR) => panic!("Allocating region failed with err: {}", ERR) + Ok(lo) => lo, + Err(err) => panic!("Allocating region failed with err: {}", err) }); unsafe { alloc(*mem_layout) } } @@ -58,9 +58,9 @@ fn sys_delete_mem(backstore: SysMemBackStore, size: usize) { let bbbox = unsafe { Box::from_raw(backstore) }; let mem_layout = Box::new(match Layout::from_size_align(size, POINTER_SIZE) { - Ok(LO) => LO, - Err(ERR) => panic!("Allocating region failed with err: {}", ERR) + Ok(lo) => lo, + Err(err) => panic!("Allocating region failed with err: {}", err) }); unsafe { dealloc(backstore, *mem_layout) }; - let backstore = Box::into_raw(bbbox); + let _backstore = Box::into_raw(bbbox); } diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index d32f85fc645ed82b5832c4e2510a57b0dda4dd09..c04d74d63b757bd8fc05f644c3bcf98f90229901 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -46,8 +46,10 @@ pub mod mm; //#[cfg(feature = "realtime")] pub mod thread; pub mod mu_rand; +pub mod futex; + #[cfg(feature = "realtime")] -pub mod time; +pub mod mu_time; lazy_static! { static ref UNKNOWN_FUNCTION_NAME: CName = Arc::new("UNKOWN".to_string()); diff --git a/src/runtime/time/clock.rs b/src/runtime/mu_time/clock.rs similarity index 100% rename from src/runtime/time/clock.rs rename to src/runtime/mu_time/clock.rs diff --git a/src/runtime/time/clock_posix.rs b/src/runtime/mu_time/clock_posix.rs similarity index 100% rename from src/runtime/time/clock_posix.rs rename to src/runtime/mu_time/clock_posix.rs diff --git a/src/runtime/time/clock_std.rs b/src/runtime/mu_time/clock_std.rs similarity index 100% rename from src/runtime/time/clock_std.rs rename to src/runtime/mu_time/clock_std.rs diff --git a/src/runtime/time/mod.rs b/src/runtime/mu_time/mod.rs similarity index 85% rename from src/runtime/time/mod.rs rename to src/runtime/mu_time/mod.rs index 78454725708cd25507ba133d0b285742bd9eff91..8e461bfd52cc5b3e5cebb39e5daa286e0280e4b8 100644 --- a/src/runtime/time/mod.rs +++ b/src/runtime/mu_time/mod.rs @@ -27,5 +27,12 @@ use vm::VM; mod clock_std; mod clock_posix; +// mod timer_timer_crate; +mod timer_posix; -pub mod clock; \ No newline at end of file +pub mod clock; +pub mod timer; + +extern "C" { + fn call_mu_function(func_addr: Address, arg_addr: Address); +} diff --git a/src/runtime/mu_time/timer.rs b/src/runtime/mu_time/timer.rs new file mode 100644 index 0000000000000000000000000000000000000000..f00504fb91f538f5f2791007fc2e560784218942 --- /dev/null +++ b/src/runtime/mu_time/timer.rs @@ -0,0 +1,77 @@ +// Copyright 2019 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//use super::timer_timer_crate::*; +use super::timer_posix::*; +use super::*; + +pub type RTMuTimer = SysTimer; + +#[no_mangle] +pub extern "C" fn muentry_new_timer() -> Address { + Address::from_mut_ptr(SysTimer::new()) +} + +#[no_mangle] +pub extern "C" fn muentry_set_timer( + tmr: Address, + tm: clock::TimeValT, + func: Address, + args: Address, +) { + trace!("muentry_set_timer ({}, {}, {}, {})", tmr, tm, func, args); + let mut _timerref: Box = + unsafe { Box::from_raw(tmr.to_ptr_mut()) }; + _timerref.set(tm, func, args); + let _tmr = Box::into_raw(_timerref); +} + +#[no_mangle] +pub extern "C" fn muentry_cancel_timer(tmr: Address) { + let mut _timerref: Box = + unsafe { Box::from_raw(tmr.to_ptr_mut()) }; + _timerref.cancel(); + let _tmr = Box::into_raw(_timerref); +} + +#[no_mangle] +pub extern "C" fn muentry_delete_timer(tmr: Address) { + let mut _timerref: Box = + unsafe { Box::from_raw(tmr.to_ptr_mut()) }; + _timerref.delete(); +} + +#[no_mangle] +pub extern "C" fn muentry_sleep_ns(dur: usize) { + sys_sleep_ns(dur as u64); +} + +pub(super) fn sys_sleep_ns(dur: u64) { + use std::{thread, time}; + + let now: Option = if cfg!(debug_assertions) { + let now = time::Instant::now(); + trace!("sleeping at #{:#?}", now); + Some(now) + } else { + None + }; + + let duration = time::Duration::from_nanos(dur); + thread::sleep(duration); + + if cfg!(debug_assertions) { + trace!("slept for #{:#?}", now.unwrap().elapsed()); + } +} diff --git a/src/runtime/mu_time/timer_posix.rs b/src/runtime/mu_time/timer_posix.rs new file mode 100644 index 0000000000000000000000000000000000000000..2b8cdeac30a0dd327a6352effec22cfb880d963b --- /dev/null +++ b/src/runtime/mu_time/timer_posix.rs @@ -0,0 +1,104 @@ +// Copyright 2019 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; + +extern crate libc; + +//#[link(name = "runtime_c")] +extern "C" { + pub fn posix_timer_create( + tmr_handler: *mut libc::c_void, + ) -> *mut libc::c_void; + + pub fn posix_timer_settime( + timer_ptr: *mut libc::c_void, + dur: libc::uint64_t, + prd: libc::uint64_t, + ); + + pub fn posix_timer_cancel(timer_ptr: *mut libc::c_void); + pub fn posix_timer_delete(timer_ptr: *mut libc::c_void); +} + +#[repr(C)] +struct TmrHandler { + func_ptr: Address, + arg_ptr: Address, +} + +pub struct SysTimer { + timer_ptr: Address, + handler_ptr: Address, +} + +impl SysTimer { + pub(super) fn new() -> *mut SysTimer { + trace!("SysTimer.NEW"); + let mut stbox = Box::new(SysTimer { + timer_ptr: unsafe { Address::zero() }, + handler_ptr: { + Address::from_mut_ptr(Box::into_raw(Box::new(TmrHandler { + func_ptr: unsafe { Address::zero() }, + arg_ptr: unsafe { Address::zero() }, + }))) + }, + }); + + stbox.timer_ptr = Address::from_mut_ptr(unsafe { + posix_timer_create(stbox.handler_ptr.to_ptr_mut()) + }); + + // Continue from here + // use timer_create to initialize stuff + // then use set-timer and other stuff in `set`, to modify + + let st = Box::into_raw(stbox); + trace!("__st_ptr: {:#?}", st); + + st + } + + pub(super) fn set( + &mut self, + tm: clock::TimeValT, + func: Address, + args: Address, + ) { + trace!("SysTimer.SET ({}, {}, {})", tm, func, args); + + let handler: *mut TmrHandler = self.handler_ptr.to_ptr_mut(); + unsafe { + (*handler).func_ptr = func; + (*handler).arg_ptr = args; + } + + unsafe { + posix_timer_settime(self.timer_ptr.to_ptr_mut(), tm as u64, 0); + }; + } + + pub(super) fn cancel(&mut self) { + unsafe { + posix_timer_cancel(self.timer_ptr.to_ptr_mut()); + }; + } + + pub(super) fn delete(&mut self) { + unsafe { + posix_timer_cancel(self.timer_ptr.to_ptr_mut()); + posix_timer_delete(self.timer_ptr.to_ptr_mut()); + } + } +} diff --git a/src/runtime/mu_time/timer_timer_crate.rs b/src/runtime/mu_time/timer_timer_crate.rs new file mode 100644 index 0000000000000000000000000000000000000000..c33fac1b1d4688996d0c2505840d6243e5b6fb9f --- /dev/null +++ b/src/runtime/mu_time/timer_timer_crate.rs @@ -0,0 +1,80 @@ +// Copyright 2019 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate timer; +extern crate time; + +use super::*; +// use self::timer::Guard; + +type TimerHandler = extern "C" fn(Address) -> (); + +// extern "C" { +// fn call_mu_function(func_addr: Address, arg_addr: Address); +// } + +pub struct SysTimer { + timerref: Box, + guard: timer::Guard, +} + +impl SysTimer { + pub(super) fn new() -> *mut SysTimer { + trace!("SysTimer.NEW"); + let _tmr = Box::new(timer::Timer::new()); + let _tmr_ptr = Box::into_raw(Box::new(SysTimer { + timerref: _tmr, + guard: unsafe { std::mem::zeroed() }, + })); + trace!("_tmr_ptr: {:#?}", _tmr_ptr); + + _tmr_ptr + } + + pub(super) fn set( + &mut self, + tm: clock::TimeValT, + func: Address, + args: Address + ) { + extern crate chrono; + trace!("SysTimer.SET ({}, {}, {})", tm, func, args); + // let func: Arc = unsafe { Arc::from_raw(func.to_ptr_mut()) }; + // let func = func.as_usize() as *const usize as *const fn(Address); + let _delay = time::Duration::nanoseconds(tm); + trace!("delay: {:#?}", _delay); + // let g = self.timerref.schedule_with_delay(_delay, move || { + let tmr = timer::Timer::new(); + let g = tmr.schedule_with_delay( chrono::Duration::nanoseconds(tm), move || { + // let g = tmr.schedule_with_delay(_delay, move || { + // unsafe { (*func)(args); }; + // unsafe { call_mu_function(func, args); }; + trace!("func: {:#?}", func); + trace!("__mu_pp: {:#?}", Address::from_ref(&__mu_pp)); + unsafe { call_mu_function(func, args); }; + // unsafe { call_mu_function(Address::from_ref(&__mu_pp), args); }; + // unsafe { __mu_pp(args); }; + println!("SysTimer.SET..func.args after {:#?}", _delay); + } ); + self.guard = g; + trace!("SysTimer.SET returning"); + } + + pub(super) fn cancel(&mut self) { + let g = self.guard.clone(); + drop(g); + } +} + + diff --git a/src/runtime/runtime_c_x64_sysv.c b/src/runtime/runtime_c_x64_sysv.c index 0a4453eaf733a04c3275a6bd48353608f382518e..f2a8a9359c76593bd23ef1ebcb89cf842f097e93 100644 --- a/src/runtime/runtime_c_x64_sysv.c +++ b/src/runtime/runtime_c_x64_sysv.c @@ -1,11 +1,11 @@ // Copyright 2017 The Australian National University -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,6 +16,7 @@ // RTLD_DEFAULT is not defined in POSIX. Linux gcc does not define it unless // _GNU_SOURCE is also defined. #define _GNU_SOURCE +#define _POSIX_C_SOURCE #endif // __linux__ #include @@ -23,34 +24,192 @@ #include #include #include +#include +#include +#include uint32_t mu_retval; -__thread void* mu_tls; +__thread void *mu_tls; -void muentry_set_retval(uint32_t x) { +void muentry_set_retval(uint32_t x) +{ mu_retval = x; } -int32_t c_check_result() { +int32_t c_check_result() +{ return mu_retval; } -char * alloc_mem(size_t size){ - return (char *) malloc(size); +char *alloc_mem(size_t size) +{ + return (char *)malloc(size); } -void set_thread_local(void* thread) { +void set_thread_local(void *thread) +{ // printf("Thread%p: setting mu_tls to %p\n", (void*) pthread_self(), thread); mu_tls = thread; } -void* muentry_get_thread_local() { -// printf("Thread%p: getting mu_tls as %p\n", (void*) pthread_self(), mu_tls); +void *muentry_get_thread_local() +{ + // printf("Thread%p: getting mu_tls as %p\n", (void*) pthread_self(), mu_tls); return mu_tls; } -void* resolve_symbol(const char* sym) { +void *resolve_symbol(const char *sym) +{ // printf("%s\n", sym); return dlsym(RTLD_DEFAULT, sym); } + +void call_mu_function(int64_t func_addr, int64_t arg_addr) +{ + void (*func)(void *) = func_addr; + (*func)(arg_addr); + // __asm__ volatile ( + // "push %%rdi\n" + // "push %%r10\n" + // "movq %[arg], %%rdi\n" + // "movq %[func], %%r10\n" + // "call *%%r10\n" + // "pop %%r10\n" + // "pop %%rdi\n" + // : // no output + // : [func] "rm" (func_addr), + // [arg] "rm" (arg_addr) + // : "rdi", "r10" + // ); +} + +/** + * C code to handler timer events goes here + */ + +#define errExit(msg) \ + do \ + { \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define TMRSIG SIGRTMIN + +struct _TmrHandler +{ + /* data */ + void *func_ptr; + void *arg_ptr; +}; +typedef struct _TmrHandler TmrHandler; + +typedef void (*MuFunc)(void *); + +static void +handler(int sig, siginfo_t *si, void *uc) +{ + TmrHandler *h = (TmrHandler *)si->si_value + .sival_ptr; + MuFunc func = (MuFunc)h->func_ptr; + func(h->arg_ptr); +} + +/** + * Given a timer handler spec, this function initializes a timer object and + * return a pointer to it. + * + * Note: The timer handler spec is always located at the fixed address pointed + * to be `_tmr_handler`, but the internal content needs to be updated by the + * `timer_settime` function + * + * @param _tmr_handler is a pointer to a previously allocated object which + * includes the necessary memory space to keep track of the timer handler spec. + * @return a pointer to the newly allocated timer object + */ +void *posix_timer_create(void *_tmr_handler) +{ + struct sigevent sev; + sigset_t mask; + struct sigaction sa; + + timer_t *timer_id = (timer_t *)malloc(sizeof(timer_t)); + + /* Establish handler for timer signal */ + + printf("Establishing handler for signal %d\n", TMRSIG); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = handler; + sigemptyset(&sa.sa_mask); + if (sigaction(TMRSIG, &sa, NULL) == -1) + errExit("sigaction"); + + /* Block timer signal temporarily */ + + printf("Blocking signal %d\n", TMRSIG); + sigemptyset(&mask); + sigaddset(&mask, TMRSIG); + if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) + errExit("sigprocmask"); + + /* Create the timer */ + + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = TMRSIG; + sev.sigev_value + .sival_ptr = _tmr_handler; + if (timer_create(CLOCK_REALTIME, &sev, timer_id) == -1) + errExit("timer_create"); + + printf("Unblocking signal %d\n", TMRSIG); + if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) + errExit("sigprocmask"); + + printf("TMR_CREATE timer ID is 0x%lx\n", (long)timer_id); + + return (void *)timer_id; +} + +void posix_timer_settime(void *timer_ptr, uint64_t dur, uint64_t prd) +{ + struct itimerspec its; + + printf("TMR_SETTIME (0x%lx, %lx, %lx)\n", (long)timer_ptr, dur, prd); + + its.it_value + .tv_sec = dur / 1000000000; + its.it_value + .tv_nsec = dur % 1000000000; + its.it_interval + .tv_sec = prd / 1000000000; + its.it_interval + .tv_nsec = prd % 1000000000; + + if (timer_settime(*((timer_t*)timer_ptr), 0, &its, NULL) == -1) + errExit("timer_settime_arm"); +} + +void posix_timer_cancel(void *timer_ptr) +{ + struct itimerspec its; + + its.it_value + .tv_sec = 0; + its.it_value + .tv_nsec = 0; + its.it_interval + .tv_sec = 0; + its.it_interval + .tv_nsec = 0; + + if (timer_settime(*((timer_t*)timer_ptr), 0, &its, NULL) == -1) + errExit("timer_settime_disarm"); +} + +void posix_timer_delete(void *timer_ptr) +{ + timer_t t = *((timer_t *)timer_ptr); + timer_delete(t); + free(timer_ptr); +} \ No newline at end of file diff --git a/src/runtime/swap_stack_x64_sel4_rumprun_sysv.S b/src/runtime/swap_stack_x64_sel4_rumprun_sysv.S new file mode 100644 index 0000000000000000000000000000000000000000..fbba9a6b6ada44316edea4725326fd24e3f68d86 --- /dev/null +++ b/src/runtime/swap_stack_x64_sel4_rumprun_sysv.S @@ -0,0 +1,146 @@ +# Copyright 2017 The Australian National University +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#include "asm_common_x64_sel4_rumprun.S.inc" + +# swap_stack_to(new_sp: Address, entry: Address, old_sp_loc: Address) +# %rdi %rsi %rdx +begin_func swap_to_mu_stack + # -- on old stack -- + # C calling convention + pushq %rbp + movq %rsp, %rbp + + # other callee-saved registers + pushq %rbx + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + # save sp to %rbx + movq %rsp, 0(%rdx) + + # switch to new stack + movq %rdi, %rsp + # save entry function in %rax + movq %rsi, %rax + + # -- on new stack -- + # arguments (reverse order of thread.rs - runtime_load_args) + popq %r9 + popq %r8 + popq %rcx + popq %rdx + popq %rsi + popq %rdi + movsd 0(%rsp), %xmm7 + movsd 8(%rsp), %xmm6 + movsd 16(%rsp), %xmm5 + movsd 24(%rsp), %xmm4 + movsd 32(%rsp), %xmm3 + movsd 40(%rsp), %xmm2 + movsd 48(%rsp), %xmm1 + movsd 56(%rsp), %xmm0 + add $64, %rsp + # at this point new stack is clean (no intermediate values) + + movq %rsp, %rbp + + # push an empty pointer to stack, if entry fucntion tries to return, it causes a segfault + pushq $0 + # push entry function and start it + pushq %rax + ret +end_func swap_to_mu_stack + +# _swap_back_to_native_stack(sp_loc: Address) +# %rdi +begin_func muentry_swap_back_to_native_stack + movq 0(%rdi), %rsp + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbx + + popq %rbp + ret +end_func muentry_swap_back_to_native_stack + +# _get_current_frame_rbp() -> Address +begin_func get_current_frame_rbp + movq %rbp, %rax + ret +end_func get_current_frame_rbp + +# muentry_throw_exception(obj: Address) +# %rdi +begin_func muentry_throw_exception + # save all callee-saved + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %rbp + pushq %rbx + + # %rsp points to %rbx, pass this as 2nd argument + movq %rsp, %rsi + + jmp CNAME(throw_exception_internal@PLT) + # won't return + +# _exception_restore(dest: Address, callee_saved: *const Word, rsp: Address) -> ! +# %rdi %rsi %rdx +# callee_saved: [rbx, rbp, r12, r13, r14, r15] +begin_func exception_restore + movq 0(%rsi), %rbx + movq 8(%rsi), %rbp + movq 16(%rsi),%r12 + movq 24(%rsi),%r13 + movq 32(%rsi),%r14 + movq 40(%rsi),%r15 + + movq %rdx, %rsp + jmpq *%rdi +end_func exception_restore + +# fake_swap_mu_thread(old_sp_loc: Address) +# %rdi +# (we do not actually swap stack, but we make the stack the same +# as if they are native stack that have been swapped out, so that +# when THREADEXIT (swap_back_to_native_stack) is called, we won't panic + +# this function is untested!!! +begin_func fake_swap_mu_thread + # save return address + movq (%rsp), %rax + + pushq %rbp + movq %rsp, %rbp + + pushq %rbx + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + # save old sp to thread field + movq %rsp, 0(%rdi) + + # return to caller, but preserve those pushed values (since THREADEXIT will pick them up) + pushq %rax + ret \ No newline at end of file diff --git a/src/runtime/thread/thread_mu.rs b/src/runtime/thread/thread_mu.rs index cadf35793dec494b4a233209691050b28bf294a9..d983bb88d1e9849aa877b5b79c0f93fa8a02b0f3 100644 --- a/src/runtime/thread/thread_mu.rs +++ b/src/runtime/thread/thread_mu.rs @@ -18,7 +18,7 @@ use super::*; //pub(super) use super::thread_posix::*; pub(super) use super::thread_mu_posix::*; -use core::borrow::BorrowMut; +// use core::borrow::BorrowMut; impl MuThread { /// creates and launches a mu thread, returns a JoinHandle and address to diff --git a/src/utils/src/mem.rs b/src/utils/src/mem.rs index 30ff10aedec8a9440a09d39a283a54bb189678ed..743606dd3b9b1be037cce661b284f42768d02905 100644 --- a/src/utils/src/mem.rs +++ b/src/utils/src/mem.rs @@ -68,7 +68,7 @@ pub fn munmap(addr: Address, size: ByteSize) { /// malloc's and zeroes the memory pub unsafe fn malloc_zero(size: usize) -> *mut u8 { - use self::memsec; + // use self::memsec; match memsec::malloc(size) { Some(ptr) => { memsec::memzero(ptr, size); diff --git a/src/vm/api/api_impl/irnodes.rs b/src/vm/api/api_impl/irnodes.rs index 192af00355bdd3a49ddce04e9c41d506b5b4c914..66ac2ff2777853b3da7444d22f29179b1c9a9b2f 100644 --- a/src/vm/api/api_impl/irnodes.rs +++ b/src/vm/api/api_impl/irnodes.rs @@ -112,6 +112,9 @@ pub enum NodeType { TypeThreadRef { id: MuID }, + TypeFutexRef { + id: MuID + }, TypeRTAttr { id: MuID }, diff --git a/src/vm/handle.rs b/src/vm/handle.rs index 5885076c6a9189c7ee221baf3d9a1468d0b91ea4..482d2c7c647f6f177e29f1493d8eaf1e2f5120d4 100644 --- a/src/vm/handle.rs +++ b/src/vm/handle.rs @@ -89,6 +89,7 @@ pub enum APIHandleValue { RegionRef, TimeVal, TimerRef, + FutexRef, // /// RTMu's clock // TimeStamp, // /// RTMu's timer ID (similar to threadref) @@ -161,6 +162,7 @@ impl fmt::Debug for APIHandleValue { &TagRef64(val) => write!(f, "tagref64 0x{:x}", val), &FuncRef(id) => write!(f, "funcref to #{}", id), &ThreadRef => write!(f, "threadref"), + &FutexRef => write!(f, "futexref"), &RTAttr => write!(f, "rtattr"), &TimeVal => write!(f, "timeval"), &TimerRef => write!(f, "timerref"), diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 0d066c3bf15c87032882cdf6a4c9d0ad01a10548..391662b78655b093685de3372121742b16cdb444 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -36,7 +36,7 @@ use vm::handle::*; use vm::vm_options::MuLogLevel; use vm::vm_options::VMOptions; -use log::LogLevel; +use log::Level; use std; use std::collections::LinkedList; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -300,11 +300,11 @@ impl<'a> VM { use std::env; match level { MuLogLevel::None => {} - MuLogLevel::Error => VM::start_logging_internal(LogLevel::Error), - MuLogLevel::Warn => VM::start_logging_internal(LogLevel::Warn), - MuLogLevel::Info => VM::start_logging_internal(LogLevel::Info), - MuLogLevel::Debug => VM::start_logging_internal(LogLevel::Debug), - MuLogLevel::Trace => VM::start_logging_internal(LogLevel::Trace), + MuLogLevel::Error => VM::start_logging_internal(Level::Error), + MuLogLevel::Warn => VM::start_logging_internal(Level::Warn), + MuLogLevel::Info => VM::start_logging_internal(Level::Info), + MuLogLevel::Debug => VM::start_logging_internal(Level::Debug), + MuLogLevel::Trace => VM::start_logging_internal(Level::Trace), MuLogLevel::Env => { match env::var("MU_LOG_LEVEL") { Ok(s) => VM::start_logging(MuLogLevel::from_string(s)), @@ -316,7 +316,7 @@ impl<'a> VM { /// starts trace-level logging pub fn start_logging_trace() { - VM::start_logging_internal(LogLevel::Trace) + VM::start_logging_internal(Level::Trace) } /// starts logging based on MU_LOG_LEVEL environment variable @@ -324,17 +324,17 @@ impl<'a> VM { VM::start_logging(MuLogLevel::Env) } - /// starts logging based on Rust's LogLevel + /// starts logging based on Rust's Level (previously LogLevel) /// (this function actually initializes logger and deals with error) - fn start_logging_internal(level: LogLevel) { - use stderrlog; + fn start_logging_internal(level: Level) { + // use stderrlog; let verbose = match level { - LogLevel::Error => 0, - LogLevel::Warn => 1, - LogLevel::Info => 2, - LogLevel::Debug => 3, - LogLevel::Trace => 4 + Level::Error => 0, + Level::Warn => 1, + Level::Info => 2, + Level::Debug => 3, + Level::Trace => 4 }; match stderrlog::new().verbosity(verbose).init() { diff --git a/tests/ir_macros.rs b/tests/ir_macros.rs index 663d578653c142d8fc4e0e5c194b7d6297c00a50..a489a17a6e44182df3a819f9ba1f1e722aacbe68 100644 --- a/tests/ir_macros.rs +++ b/tests/ir_macros.rs @@ -123,6 +123,13 @@ macro_rules! typedef { $vm.set_name($name.as_entity()); }; + // futexref + (($vm: expr) $name: ident = mu_futexref) => { + let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), + MuType_::FutexRef); + $vm.set_name($name.as_entity()); + }; + // regionref (($vm: expr) $name: ident = mu_regionref) => { let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))), @@ -836,6 +843,56 @@ macro_rules! inst { ); }; + // NEWFUTEX + (($vm: expr, $fv: ident) $name: ident: $res: ident = NEWFUTEX) + => { + let $name = $fv.new_inst( + Instruction { + hdr: MuEntityHeader::unnamed($vm.next_id()), + value: Some(vec![$res.clone_value()]), + ops: vec![], + v: Instruction_::NewFutex + } + ); + }; + + // DELETEFUTEX + (($vm: expr, $fv: ident) $name: ident: DELETEFUTEX $fref: ident) + => { + let $name = $fv.new_inst( + Instruction { + hdr: MuEntityHeader::unnamed($vm.next_id()), + value: None, + ops: vec![$fref.clone()], + v: Instruction_::DeleteFutex(0) + } + ); + }; + + // LOCKFUTEX + (($vm: expr, $fv: ident) $name: ident: LOCKFUTEX $fref: ident) + => { + let $name = $fv.new_inst( + Instruction { + hdr: MuEntityHeader::unnamed($vm.next_id()), + value: None, + ops: vec![$fref.clone()], + v: Instruction_::LockFutex(0) + } + ); + }; + // UNLOCKFUTEX + (($vm: expr, $fv: ident) $name: ident: UNLOCKFUTEX $fref: ident) + => { + let $name = $fv.new_inst( + Instruction { + hdr: MuEntityHeader::unnamed($vm.next_id()), + value: None, + ops: vec![$fref.clone()], + v: Instruction_::UnlockFutex(0) + } + ); + }; } /// New Real-Time Thread @@ -1047,6 +1104,60 @@ macro_rules! inst_rt { v: Instruction_::PrintTime(0) }); }; + + // newtimer + (($vm: expr, $fv: ident) $name: ident: + $res: ident = NEWTIMER) => { + let $name = $fv.new_inst(Instruction { + hdr: MuEntityHeader::unnamed($vm.next_id()), + value: Some(vec![$res.clone_value()]), + ops: vec![], + v: Instruction_::NewTimer, + }); + }; + + // settimer + (($vm: expr, $fv: ident) $name: ident: + SETTIMER $tmr: ident, $tm: ident, $func: ident, $args: ident) => { + let $name = $fv.new_inst(Instruction { + hdr: MuEntityHeader::unnamed($vm.next_id()), + value: Some(vec![]), + ops: vec![$tmr.clone(), $tm.clone(), $func.clone(), $args.clone()], + v: Instruction_::SetTimer(0, 1, 2, 3), + }); + }; + + // canceltimer + (($vm: expr, $fv: ident) $name: ident: + CANCELTIMER $tmr: ident) => { + let $name = $fv.new_inst(Instruction { + hdr: MuEntityHeader::unnamed($vm.next_id()), + value: Some(vec![]), + ops: vec![$tmr.clone()], + v: Instruction_::CancelTimer(0), + }); + }; + + // deletetimer + (($vm: expr, $fv: ident) $name: ident: + DELETETIMER $tmr: ident) => { + let $name = $fv.new_inst(Instruction { + hdr: MuEntityHeader::unnamed($vm.next_id()), + value: Some(vec![]), + ops: vec![$tmr.clone()], + v: Instruction_::DeleteTimer(0), + }); + }; + + (($vm: expr, $fv: ident) $name: ident: + SLEEP_NS $dur: ident) => { + let $name = $fv.new_inst(Instruction { + hdr: MuEntityHeader::unnamed($vm.next_id()), + value: Some(vec![]), + ops: vec![$dur.clone()], + v: Instruction_::Sleep(0), + }); + }; } //__________-----------________________ @@ -1135,7 +1246,10 @@ macro_rules! emit_timed_test { MuType_::UPtr(_) | MuType_::Ref(_) | MuType_::WeakRef(_) | - MuType_::IRef(_) + MuType_::IRef(_) | + MuType_::FutexRef | + MuType_::ThreadRef | + MuType_::TimerRef => { $vm.declare_const( MuEntityHeader::named($vm.next_id(), Mu(stringify!(expected1))), diff --git a/tests/rtmu_benchmarks/test_rt_quicksort.rs b/tests/rtmu_benchmarks/test_rt_quicksort.rs index 9f42d989d1e3cd51a71e5093300bb6486cbef8b9..95408d0685bb3d894c009c935c00aa0936022992 100644 --- a/tests/rtmu_benchmarks/test_rt_quicksort.rs +++ b/tests/rtmu_benchmarks/test_rt_quicksort.rs @@ -31,11 +31,11 @@ use std::sync::Arc; #[test] fn test_rt_quicksort() { - // build_and_run_test!( - // VM_BUILDER rtmu_quicksort_ealloc(1000000), - // DEP_FUNCS (init_func, cs_func, qs_func, part_func), - // TESTER_NAME qs_ealloc_tester_1, - // ); + build_and_run_test!( + VM_BUILDER rtmu_quicksort_ealloc(1000000), + DEP_FUNCS (init_func, cs_func, qs_func, part_func), + TESTER_NAME qs_ealloc_tester_1, + ); build_and_run_test!( VM_BUILDER rtmu_quicksort_ralloc(1000000), DEP_FUNCS (init_func, cs_func, qs_func, part_func), diff --git a/tests/test_jit/init_env.sh b/tests/test_jit/init_env.sh index f6504495ab686f3714b8cfe74d7a5a80283e8fe1..e17185c085d46a0e64f8c9ccb751914ec3fcdb5c 100755 --- a/tests/test_jit/init_env.sh +++ b/tests/test_jit/init_env.sh @@ -5,7 +5,7 @@ export DYLD_LIBRARY_PATH=$PWD export LD_LIBRARY_PATH=$MU_ZEBU/target/$ZEBU_BUILD/deps:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=./emit:$LD_LIBRARY_PATH export usess=none -#export PYTHONPATH=mu-client-pypy:RPySOM/src +export PYTHONPATH=mu-client-pypy:RPySOM/src export RPYSOM=RPySOM export CC=clang export SPAWN_PROC=1 diff --git a/tests/test_runtime/test_rt/mod.rs b/tests/test_runtime/test_rt/mod.rs index 721bac45db8b4a37061c0c4d329d45293b25c3d9..ae05a5b67a4753b5fa59169382bc110dc37ffc8c 100644 --- a/tests/test_runtime/test_rt/mod.rs +++ b/tests/test_runtime/test_rt/mod.rs @@ -14,4 +14,5 @@ mod test_emm; mod test_rt_thread_attr; -mod test_time_tools; \ No newline at end of file +mod test_time_tools; +mod test_rt_futex; \ No newline at end of file diff --git a/tests/test_runtime/test_rt/test_rt_futex.rs b/tests/test_runtime/test_rt/test_rt_futex.rs new file mode 100644 index 0000000000000000000000000000000000000000..1e5f969f0093b95f14ff9ad214c5dc3df48f2e70 --- /dev/null +++ b/tests/test_runtime/test_rt/test_rt_futex.rs @@ -0,0 +1,94 @@ +// Copyright 2019 The Australian National University +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate libloading; +extern crate log; +extern crate mu; + +use self::mu::ast::inst::*; +use self::mu::ast::ir::*; +use self::mu::ast::op::CmpOp; +use self::mu::ast::types::*; +use self::mu::compiler::*; +use self::mu::utils::LinkedHashMap; +use self::mu::vm::*; + +use self::mu::linkutils; +use self::mu::linkutils::aot; +use std::sync::Arc; + +#[test] +fn test_rt_futex() { + build_and_run_test!(func, futex_tester_1, futex_ops); +} +#[no_mangle] +fn futex_ops() -> VM { + let vm = VM::new_with_opts("--aot-link-static"); + + typedef!((vm) int64 = mu_int(64)); + typedef!((vm) futexref = mu_futexref); + + funcsig!((vm) sig = () -> ()); + funcdecl!((vm) func); + funcdef!((vm) func VERSION func_v1); + + // blk_entry + block!((vm, func_v1) blk_entry); + + ssa!((vm, func_v1) res); + + inst!((vm, func_v1) blk_entry_new_futex: + res = NEWFUTEX + ); + + inst!((vm, func_v1) blk_entry_print_futex: + PRINTHEX res + ); + + inst!((vm, func_v1) blk_entry_lock_futex: + LOCKFUTEX res + ); + + inst!((vm, func_v1) blk_entry_unlock_futex: + UNLOCKFUTEX res + ); + + inst!((vm, func_v1) blk_entry_delete_futex: + DELETEFUTEX res + ); + + inst!((vm, func_v1) blk_entry_ret: + THREADEXIT + ); + + define_block!((vm, func_v1) blk_entry() { + blk_entry_new_futex, + blk_entry_print_futex, + blk_entry_lock_futex, + blk_entry_unlock_futex, + blk_entry_delete_futex, + blk_entry_ret + }); + + define_func_ver!((vm) func_v1 (entry: blk_entry) { + blk_entry + }); + + emit_test!((vm) + TESTER futex_tester_1, + TESTEE func, + ); + + vm +} diff --git a/tests/test_runtime/test_rt/test_time_tools.rs b/tests/test_runtime/test_rt/test_time_tools.rs index 578a4d676981c1736458e61d134cdc41e3295849..71df86d2635fb8c1d43e81eb75622ea87938e5d6 100644 --- a/tests/test_runtime/test_rt/test_time_tools.rs +++ b/tests/test_runtime/test_rt/test_time_tools.rs @@ -19,6 +19,7 @@ extern crate mu; use self::mu::ast::inst::*; use self::mu::ast::ir::*; use self::mu::ast::op::CmpOp; +use self::mu::ast::op::BinOp; use self::mu::ast::types::*; use self::mu::compiler::*; use self::mu::utils::LinkedHashMap; @@ -141,3 +142,166 @@ fn set_time() -> VM { vm } + +#[test] +fn test_rt_set_timer() { + build_and_run_test!( + VM_BUILDER set_timer(), + DEP_FUNCS (func, pp), + TESTER_NAME set_timer_tester, + ); +} +#[no_mangle] +fn set_timer() -> VM { + let vm = VM::new_with_opts("--aot-link-static"); + + typedef! ((vm) int64 = mu_int(64)); + typedef! ((vm) arg_t = mu_struct(int64)); + typedef! ((vm) timerref = mu_timerref); + typedef! ((vm) i64_ptr = mu_uptr(int64)); + typedef! ((vm) arg_ptr = mu_uptr(arg_t)); + + funcsig! ((vm) pp_sig = (arg_ptr) -> ()); + funcdecl! ((vm) pp); // periodic print + funcdef! ((vm) pp VERSION pp_v1); + + typedef! ((vm) ppf_ptr = mu_funcref(pp_sig)); + constdef! ((vm) const_ppf_ptr = Constant::FuncRef(pp)); // pointer to periodic print + constdef! ((vm) const_period = Constant::Int(1_000_000_000)); // 1 second + constdef! ((vm) const_null_ptr = Constant::NullRef); // Null argument + + // blk_entry + block! ((vm, pp_v1) blk_entry); + + ssa! ((vm, pp_v1) last_arg_ptr); + + ssa! ((vm, pp_v1) last_tm_ptr); + ssa! ((vm, pp_v1) last_tm); + ssa! ((vm, pp_v1) tm); + ssa! ((vm, pp_v1) duration); + + /* + BLOCK ENTRY (tmr, period, pp_func, uptr): + new_tm = GETTIME + new_arg = struct(new_tm) + SETTIMER tmr, period, pp_func, uptr + tm = arg.0 + PRINTHEX new_tm - tm // the real period achieved + */ + inst_rt! ((vm, pp_v1) blk_entry_get_time: + tm = GETTIME + ); + + inst! ((vm, pp_v1) blk_entry_get_last_tm_ptr: + last_tm_ptr = GETFIELDIREF last_arg_ptr (is_ptr: true, index: 0) + ); + inst! ((vm, pp_v1) blk_entry_load_last: + last_tm = LOAD last_tm_ptr (is_ptr: true, order: MemoryOrder::NotAtomic) + ); + + inst! ((vm, pp_v1) blk_entry_calc_duration: + duration = BINOP (BinOp::Sub) tm last_tm + ); + inst_rt! ((vm, pp_v1) blk_entry_print_time: + PRINTTIME duration + ); + + inst! ((vm, pp_v1) blk_entry_ret: + RET + ); + + define_block!((vm, pp_v1) blk_entry(last_arg_ptr) { + blk_entry_get_time, + blk_entry_get_last_tm_ptr, + blk_entry_load_last, + blk_entry_calc_duration, + blk_entry_print_time, + blk_entry_ret + }); + + define_func_ver!((vm) pp_v1 (entry: blk_entry) { + blk_entry + }); + + funcsig! ((vm) func_sig = () -> ()); + funcdecl! ((vm) func); // periodic print + funcdef! ((vm) func VERSION func_v1); + + consta! ((vm, func_v1) ppf_ptr_local = const_ppf_ptr); + consta! ((vm, func_v1) period_local = const_period); + + ssa! ((vm, func_v1) tmr); + ssa! ((vm, func_v1) tm); + ssa! ((vm, func_v1) new_arg_ptr); + ssa! ((vm, func_v1) new_tm_ptr); + + // blk_entry + block! ((vm, func_v1) blk_entry); + + inst_rt! ((vm, func_v1) blk_entry_get_time: + tm = GETTIME + ); + + inst_rt! ((vm, func_v1) blk_entry_ealloc_arg: + new_arg_ptr = EALLOC arg_t + ); + inst! ((vm, func_v1) blk_entry_get_new_tm_ptr: + new_tm_ptr = GETFIELDIREF new_arg_ptr (is_ptr: true, index: 0) + ); + inst! ((vm, func_v1) blk_entry_store_new_tm: + STORE new_tm_ptr tm (is_ptr: true, order: MemoryOrder::SeqCst) + ); + + inst_rt! ((vm, func_v1) blk_entry_create_timer: + tmr = NEWTIMER + ); + + inst! ((vm, func_v1) blk_entry_print_func: + PRINTHEX tmr + ); + + inst_rt! ((vm, func_v1) blk_entry_set_next_timer: + SETTIMER tmr, period_local, ppf_ptr_local, new_arg_ptr + ); + + inst_rt! ((vm, func_v1) blk_entry_print_time: + PRINTTIME tm + ); + + inst_rt! ((vm, func_v1) blk_entry_sleep_once: + SLEEP_NS period_local + ); + + inst_rt! ((vm, func_v1) blk_entry_sleep_twice: + SLEEP_NS period_local + ); + + inst! ((vm, func_v1) blk_entry_ret: + RET + ); + + define_block!((vm, func_v1) blk_entry() { + blk_entry_get_time, + blk_entry_ealloc_arg, + blk_entry_get_new_tm_ptr, + blk_entry_store_new_tm, + blk_entry_create_timer, + blk_entry_print_func, + blk_entry_set_next_timer, + blk_entry_print_time, + blk_entry_sleep_once, + blk_entry_sleep_twice, + blk_entry_ret + }); + + define_func_ver!((vm) func_v1 (entry: blk_entry) { + blk_entry + }); + + emit_test!((vm) + TESTER set_timer_tester, + TESTEE func, + ); + + vm +} diff --git a/zebu_c_helpers.c b/zebu_c_helpers.c new file mode 100644 index 0000000000000000000000000000000000000000..c31e3de1fe0d15e4bd113edb49f5b780d5d5d6a8 --- /dev/null +++ b/zebu_c_helpers.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include + +// a pointer to the symbol table I generate +extern void* mu_sym_table; + +//extern int32_t mu_retval; +// +//int32_t muentry_get_retval(){ +// return mu_retval; +//} + +// a function to resolve symbol names to their address, using mu_sym_table\ +// which is valued by the c_resolve_sym function, according to \ +// mu_sym_table_root +// actually this function will search for the symbol in one idX_sym_table +void * resolve_symbol_in_current_context(const unsigned char * input_symbol_name){ + unsigned long i = 0, j=0; + unsigned long num_of_syms = 0; + unsigned long cur_len = 0; + unsigned long input_len = 0; + unsigned char cur_char = 0; + unsigned long cur_add = 0; + unsigned char is_different = 0; + + while(input_symbol_name[input_len] != 0){ + input_len++; + } + + if( (mu_sym_table == NULL) || (input_len == 0)){ + printf("**********\n****ERROR!!!****\nC_RESOLVE_SYMBOL: extern mu sym table is null!\n*********\n"); + assert(0); + } + + // a copy of mu_sym_table, to keep mu_sym_table from changing +// unsigned char * sym_table_current = (unsigned char *) get_sym_table_pointer(); + unsigned char * sym_table_current = (unsigned char *) &mu_sym_table; +// printf("C_RESOLVE_SYMBOL --> Step 1\n"); + +// printf("C_RESOLVE_SYMBOL --> Current mu_sym_table = %p\n", sym_table_current); +// printf("C_RESOLVE_SYMBOL --> Current vm = %p\n", get_vm_pointer()); + + // read the total number of symbols from the first line of sym table + num_of_syms = *((unsigned long*)sym_table_current); +// printf("RESOLVE_SYM --> number of symbols = %d\n", num_of_syms); + // go 8 bytes forward, to skip the current .quad + sym_table_current += 8; + + for(i=0; i