Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ c2rust-bitfields = { version = "0.3", features = ["no_std"] }
riot-build = { version = "< 0.2.0", optional = true }
riot-rs-core = { version = "< 0.2.0", optional = true }

# atomic support
portable-atomic = {version = "1.0.1", features = ["critical-section"]}
critical-section = {version = "1.1.1", features = ["restore-state-bool"], optional = true}

[build-dependencies]
bindgen = "^0.60.1"
shlex = "^1"
Expand All @@ -36,5 +40,12 @@ regex = "1"
# `extern_types`.
keep-extern-types = []

# This prevents the `undef` of the dummy atomic definitions in
# `riot-c2rust.h` in case `stdatomic.h` is somewhere included.
# Note that these definitions are not realy atomics but placeholders.
# Thus a programm relying on the atomicity of the transpiled Rust structs
# will probably not work as intended.
dummy-atomic-definitions = []

# this needs to be set to build together with RIOT-rs.
riot-rs = [ "riot-build", "riot-rs-core", "keep-extern-types" ]
41 changes: 36 additions & 5 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ fn main() {
let mut consensus_cflag_groups: Option<Vec<Vec<&str>>> = None;
for entry in parsed.iter() {
if let Some(consensus_cc) = consensus_cc.as_ref() {
// Prevent c++ flags from beeing used.
// For example esp32 uses C++ internally.
// Since bindings to C++ are not supported by C2Rust
// we can savely kick it out anyway.
if entry.arguments[0] == "clang++" {
continue;
}

assert!(consensus_cc == &entry.arguments[0])
} else {
consensus_cc = Some(&entry.arguments[0]);
Expand Down Expand Up @@ -367,8 +375,16 @@ fn main() {

let arguments: Vec<_> = core::iter::once("any-cc".to_string())
.chain(cflags.into_iter())
.chain({
if cfg!(feature = "dummy-atomic-definitions") {
vec!["-DDUMMY_ATOMICS=1".to_string()]
} else {
vec![]
}
})
.chain(core::iter::once(c2rust_infile.to_string()))
.collect();

let compile_commands = json!([{
"arguments": arguments,
"directory": out_path,
Expand Down Expand Up @@ -447,11 +463,26 @@ fn main() {
if env::var("CARGO_FEATURE_KEEP_EXTERN_TYPES").is_err() {
// There's only one `pub type` usually, and that breaks use on stable, and src/inline.rs has a
// workaround for that
rustcode = rustcode.replace("\n pub type __locale_t;", "");
rustcode = rustcode.replace("\n pub type _IO_wide_data;", "");
rustcode = rustcode.replace("\n pub type _IO_codecvt;", "");
rustcode = rustcode.replace("\n pub type _IO_marker;", "");
rustcode = rustcode.replace("\n pub type __lock;", "");
let replacements = [
("\n pub type __locale_t;", ""),
("\n pub type _IO_wide_data;", ""),
("\n pub type _IO_codecvt;", ""),
("\n pub type _IO_marker;", ""),
("\n pub type __lock;", ""),
];

let mut old_len = rustcode.len();

for (reg, repl) in replacements {
rustcode = rustcode.replace(reg, repl);

if rustcode.len() != old_len {
eprintln!("Could not remove {reg} from generated rustcode.\
This might lead to duplicate definitions. Consider using cargo feature \"keep-extern-types\" if this causes problems")
}

old_len = rustcode.len();
}
}

// Replace the function declarations with ... usually something pub, but special considerations
Expand Down
14 changes: 10 additions & 4 deletions riot-c2rust.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
#define __builtin_arm_get_fpscr __masked_builtin_arm_get_fpscr
#define __builtin_arm_set_fpscr __masked_builtin_arm_set_fpscr
extern int missing_implementation_for_fpscr_in_c2rust_see_issue_345;
static inline int __masked_builtin_arm_get_fpscr(void) {
static inline int __masked_builtin_arm_get_fpscr(void)
{
return missing_implementation_for_fpscr_in_c2rust_see_issue_345;
}
static inline void __masked_builtin_arm_set_fpscr(int fpscr){
static inline void __masked_builtin_arm_set_fpscr(int fpscr)
{
missing_implementation_for_fpscr_in_c2rust_see_issue_345 = fpscr;
}

Expand All @@ -28,8 +30,8 @@ static inline void __masked_builtin_arm_set_fpscr(int fpscr){
//
// Proper fix: resolve https://github.com/immunant/c2rust/issues/293
#define __CLANG_STDATOMIC_H // for clang
#define _STDATOMIC_H // for GCC
#define _STDATOMIC_H_ // for newlib
#define _STDATOMIC_H // for GCC
#define _STDATOMIC_H_ // for newlib
#define ATOMIC_VAR_INIT(x) x
// FIXME for all: is it really? We don't rely on it, see below on the explicitly included files.
#define atomic_bool bool
Expand Down Expand Up @@ -94,6 +96,9 @@ static inline void __masked_builtin_arm_set_fpscr(int fpscr){
// Exported Clang AST was invalid. Check warnings above for unimplemented features.
// --> /usr/lib/gcc/arm-none-eabi/10.3.1/include/stdatomic.h:69:1
// [-Wclang-ast]
//
// undefs can be disabled by using cargo feature: "dummy-atomic-definitions"
#ifndef DUMMY_ATOMICS
#undef __CLANG_STDATOMIC_H
#undef _STDATOMIC_H_
#undef _STDATOMIC_H
Expand Down Expand Up @@ -135,6 +140,7 @@ static inline void __masked_builtin_arm_set_fpscr(int fpscr){
#undef atomic_ptrdiff_t
#undef atomic_intmax_t
#undef atomic_uintmax_t
#endif

// Allow header files that pull in lots of odd stuff but don't depend on
// inlines -- like nimble's host/ble_gap.h -- to opt out of C2Rust altogether
Expand Down
38 changes: 38 additions & 0 deletions src/critical_section.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! [`critical_section`] implementation for **single core cpu boards**
//! using RIOTs interrupts interface. (Just disables interrupts).
//!
//! This is needed by [`portable_atomic`] to provide atomics to boards without hardware
//! support or rather where rust does not support atomics.

use critical_section::RawRestoreState;

struct RIOTCriticalSection;

critical_section::set_impl!(RIOTCriticalSection);

unsafe impl critical_section::Impl for RIOTCriticalSection {
unsafe fn acquire() -> RawRestoreState {
if crate::irq_is_in() {
return false;
}

let disabled = crate::irq_is_enabled();
// It is possible that between here an interrupt
// interferes and causes another thread/process to continue.
// This should not be a problem because:
// Szenario 1: The other process does not enter a critical section
// or disables interrupts and nothing happens.
// Szenario 2: The other process does disable interrupts, but
// then this thread here can only continue once the interrupts are back on
// and one causes this thread to continue.
// In both cases we should not face a toctu problem.
crate::irq_disable();
disabled
}

unsafe fn release(token: RawRestoreState) {
if token {
crate::irq_enable();
}
}
}
2 changes: 1 addition & 1 deletion src/intrinsics_replacements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! (But then again, they're not needed, as theire RIOT C code can't contain these operations).

#[cfg(target_arch = "riscv32")]
use core::sync::atomic::{AtomicU32, Ordering};
use portable_atomic::{AtomicU32, Ordering};

#[cfg(target_arch = "riscv32")]
pub(crate) fn atomic_and_relaxed(dst: *mut u32, src: u32) -> u32 {
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ pub mod libc;

mod intrinsics_replacements;

mod critical_section;

mod bindgen;
pub mod inline;

Expand Down