From da5a07886e3e47604933daccffa1c7fbfcaa1408 Mon Sep 17 00:00:00 2001 From: xjd Date: Thu, 13 Jun 2024 09:35:04 +0800 Subject: [PATCH] Dummy atomic support (#92) * Dummy atomic implementation make some crates(like bytes, log) work on ckb-vm --- Cargo.toml | 2 + README.md | 2 +- build.rs | 4 + contracts/Cargo.lock | 14 + contracts/ckb-std-tests/Cargo.toml | 4 +- contracts/ckb-std-tests/src/entry.rs | 393 +++++++++++++++++++- src/dummy_atomic.rs | 537 +++++++++++++++++++++++++++ src/lib.rs | 3 + test/Makefile | 3 +- test/simulator/Cargo.toml | 2 + 10 files changed, 959 insertions(+), 5 deletions(-) create mode 100644 src/dummy_atomic.rs diff --git a/Cargo.toml b/Cargo.toml index 292e083..a4254e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ dlopen-c = ["libc"] build-with-clang = [] libc = [] ckb2023 = [] +# work with `target-feature=-a` Cargo flag +dummy-atomic = [] [build-dependencies] cc = "1.0" diff --git a/README.md b/README.md index 739bd3e..0161fbe 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This library contains several modules that help you write CKB contract with Rust * `debug!` macro: a `println!` like macro helps debugging * `entry!` macro: defines contract entry point * `default_alloc!` macro: defines global allocator for no-std rust - +* `dummy_atomic` module: dummy atomic operations ### Memory allocator Default allocator uses a mixed allocation strategy: diff --git a/build.rs b/build.rs index 5c79316..28a8bb4 100644 --- a/build.rs +++ b/build.rs @@ -24,6 +24,10 @@ fn main() { setup_compiler_flags(&mut build); build.compile("libc"); } + if target_arch != "riscv64" && cfg!(feature = "dummy-atomic") { + println!("cargo:warning=This build script intentionally failed: feature `dummy-atomic` can't be used in non risc-v target"); + std::process::exit(1); + } } fn setup_compiler_flags(build: &mut cc::Build) { diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index c074620..48d0f04 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -14,6 +14,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f0d2da64a6a895d5a7e0724882825d50f83c13396b1b9f1878e19a024bab395" +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + [[package]] name = "cc" version = "1.0.83" @@ -64,7 +70,9 @@ name = "ckb-std-tests" version = "0.1.0" dependencies = [ "blake2b-ref", + "bytes", "ckb-std", + "log", ] [[package]] @@ -100,6 +108,12 @@ version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + [[package]] name = "molecule" version = "0.7.5" diff --git a/contracts/ckb-std-tests/Cargo.toml b/contracts/ckb-std-tests/Cargo.toml index 073b376..6765686 100644 --- a/contracts/ckb-std-tests/Cargo.toml +++ b/contracts/ckb-std-tests/Cargo.toml @@ -6,5 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ckb-std = { path = "../../", features = [ "dlopen-c" ] } +ckb-std = { path = "../../", features = [ "dlopen-c", "dummy-atomic" ] } blake2b-ref = { version = "0.3", default-features = false } +bytes = { version = "1.6.0", default-features = false } +log = { version = "0.4.17", default-features = false } diff --git a/contracts/ckb-std-tests/src/entry.rs b/contracts/ckb-std-tests/src/entry.rs index ee74a68..7b3901f 100644 --- a/contracts/ckb-std-tests/src/entry.rs +++ b/contracts/ckb-std-tests/src/entry.rs @@ -10,13 +10,20 @@ use core::mem::size_of; #[cfg(target_arch = "riscv64")] use crate::code_hashes::CODE_HASH_SHARED_LIB; +use crate::error::Error; +#[cfg(target_arch = "riscv64")] +use bytes; +#[cfg(target_arch = "riscv64")] +use ckb_std::dummy_atomic; use ckb_std::since::{EpochNumberWithFraction, Since}; #[cfg(target_arch = "riscv64")] use ckb_std::{dynamic_loading, dynamic_loading_c_impl}; #[cfg(target_arch = "riscv64")] +use core::ffi::c_void; +#[cfg(target_arch = "riscv64")] use core::mem::size_of_val; - -use crate::error::Error; +#[cfg(target_arch = "riscv64")] +use log::{info, warn}; fn new_blake2b() -> Blake2b { const CKB_HASH_PERSONALIZATION: &[u8] = b"ckb-default-hash"; @@ -402,6 +409,383 @@ fn test_since() { ); } +#[cfg(target_arch = "riscv64")] +fn test_atomic() { + // The bytes crate uses atomic operations. + let b = bytes::Bytes::copy_from_slice(&[0, 1, 2, 3]); + + let b2 = b.slice(1..2); + assert_eq!(b2[0], 1); + assert_eq!(b2.len(), 1); + + let v: Vec = b.into(); + assert_eq!(v[1], 1); + assert_eq!(v.len(), 4); + + // The log crate uses atomic operations. + info!("atomic info"); + warn!("atomic warn"); +} + +#[cfg(target_arch = "riscv64")] +fn test_compare_exchange(data: &mut T, expected: &mut T, desired: u64, same: bool) { + let size = size_of_val(data); + let res = match size { + 1 => dummy_atomic::__atomic_compare_exchange_1( + data as *mut T as *mut c_void, + expected as *mut T as *mut c_void, + desired as u8, + false, + 0, + 0, + ), + 2 => dummy_atomic::__atomic_compare_exchange_2( + data as *mut T as *mut c_void, + expected as *mut T as *mut c_void, + desired as u16, + false, + 0, + 0, + ), + 4 => dummy_atomic::__atomic_compare_exchange_4( + data as *mut T as *mut c_void, + expected as *mut T as *mut c_void, + desired as u32, + false, + 0, + 0, + ), + 8 => dummy_atomic::__atomic_compare_exchange_8( + data as *mut T as *mut c_void, + expected as *mut T as *mut c_void, + desired as u64, + false, + 0, + 0, + ), + _ => { + panic!("Unknown size"); + } + }; + assert_eq!(res, same); +} + +#[cfg(target_arch = "riscv64")] +fn test_atomic2() { + let mut data1: u8 = 42; + let old = dummy_atomic::__atomic_exchange_1(&mut data1 as *mut u8 as *mut c_void, 0, 0); + assert_eq!(old, 42); + let mut data2: u16 = 42; + let old = dummy_atomic::__atomic_exchange_2(&mut data2 as *mut u16 as *mut c_void, 0, 0); + assert_eq!(old, 42); + let mut data4: u32 = 42; + let old = dummy_atomic::__atomic_exchange_4(&mut data4 as *mut u32 as *mut c_void, 0, 0); + assert_eq!(old, 42); + let mut data8: u64 = 42; + let old = dummy_atomic::__atomic_exchange_8(&mut data8 as *mut u64 as *mut c_void, 0, 0); + assert_eq!(old, 42); + + let mut data: u8 = 42; + let mut expected: u8 = 42; + test_compare_exchange(&mut data, &mut expected, 0, true); + assert_eq!(data, 0); + test_compare_exchange(&mut data, &mut expected, 0, false); + assert_eq!(expected, 0); + + let mut data: u16 = 42; + let mut expected: u16 = 42; + test_compare_exchange(&mut data, &mut expected, 0, true); + assert_eq!(data, 0); + test_compare_exchange(&mut data, &mut expected, 0, false); + assert_eq!(expected, 0); + + let mut data: u32 = 42; + let mut expected: u32 = 42; + test_compare_exchange(&mut data, &mut expected, 0, true); + assert_eq!(data, 0); + test_compare_exchange(&mut data, &mut expected, 0, false); + assert_eq!(expected, 0); + + let mut data: u64 = 42; + let mut expected: u64 = 42; + test_compare_exchange(&mut data, &mut expected, 0, true); + assert_eq!(data, 0); + test_compare_exchange(&mut data, &mut expected, 0, false); + assert_eq!(expected, 0); + + let data: u8 = 42; + let expected = dummy_atomic::__atomic_load_1(&data as *const u8 as *const c_void, 0); + assert_eq!(expected, data); + + let data: u16 = 42; + let expected = dummy_atomic::__atomic_load_2(&data as *const u16 as *const c_void, 0); + assert_eq!(expected, data); + + let data: u32 = 42; + let expected = dummy_atomic::__atomic_load_4(&data as *const u32 as *const c_void, 0); + assert_eq!(expected, data); + + let data: u64 = 42; + let expected = dummy_atomic::__atomic_load_8(&data as *const u64 as *const c_void, 0); + assert_eq!(expected, data); + + let mut data: u8 = 42; + dummy_atomic::__atomic_store_1(&mut data as *mut u8 as *mut c_void, 0, 0); + assert_eq!(data, 0); + + let mut data: u16 = 42; + dummy_atomic::__atomic_store_2(&mut data as *mut u16 as *mut c_void, 0, 0); + assert_eq!(data, 0); + + let mut data: u32 = 42; + dummy_atomic::__atomic_store_4(&mut data as *mut u32 as *mut c_void, 0, 0); + assert_eq!(data, 0); + + let mut data: u64 = 42; + dummy_atomic::__atomic_store_8(&mut data as *mut u64 as *mut c_void, 0, 0); + assert_eq!(data, 0); + + let mut data: u8 = 42; + let res = dummy_atomic::__atomic_fetch_add_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 43); + + let mut data: u16 = 42; + let res = dummy_atomic::__atomic_fetch_add_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 43); + + let mut data: u32 = 42; + let res = dummy_atomic::__atomic_fetch_add_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 43); + + let mut data: u64 = 42; + let res = dummy_atomic::__atomic_fetch_add_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 43); + + let mut data: u8 = 42; + let res = dummy_atomic::__atomic_fetch_sub_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 41); + + let mut data: u16 = 42; + let res = dummy_atomic::__atomic_fetch_sub_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 41); + + let mut data: u32 = 42; + let res = dummy_atomic::__atomic_fetch_sub_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 41); + + let mut data: u64 = 42; + let res = dummy_atomic::__atomic_fetch_sub_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 41); + + let mut data: u8 = 43; + let res = dummy_atomic::__atomic_fetch_and_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 1); + + let mut data: u16 = 43; + let res = dummy_atomic::__atomic_fetch_and_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 1); + + let mut data: u32 = 43; + let res = dummy_atomic::__atomic_fetch_and_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 1); + + let mut data: u64 = 43; + let res = dummy_atomic::__atomic_fetch_and_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 1); + + let mut data: u8 = 43; + let res = dummy_atomic::__atomic_fetch_xor_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 42); + + let mut data: u16 = 43; + let res = dummy_atomic::__atomic_fetch_xor_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 42); + + let mut data: u32 = 43; + let res = dummy_atomic::__atomic_fetch_xor_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 42); + + let mut data: u64 = 43; + let res = dummy_atomic::__atomic_fetch_xor_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 42); + + let mut data: u8 = 42; + let res = dummy_atomic::__atomic_fetch_or_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 43); + + let mut data: u16 = 42; + let res = dummy_atomic::__atomic_fetch_or_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 43); + + let mut data: u32 = 42; + let res = dummy_atomic::__atomic_fetch_or_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 43); + + let mut data: u64 = 42; + let res = dummy_atomic::__atomic_fetch_or_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 43); + + let mut data: u8 = 1; + let res = dummy_atomic::__atomic_fetch_nand_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 1); + assert_eq!(data, 0xFE); + + let mut data: u16 = 1; + let res = dummy_atomic::__atomic_fetch_nand_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 1); + assert_eq!(data, 0xFFFE); + + let mut data: u32 = 1; + let res = dummy_atomic::__atomic_fetch_nand_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 1); + assert_eq!(data, 0xFFFFFFFE); + + let mut data: u64 = 1; + let res = dummy_atomic::__atomic_fetch_nand_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 1); + assert_eq!(data, 0xFFFFFFFFFFFFFFFE); + + let mut data: u8 = 42; + let res = dummy_atomic::__atomic_add_fetch_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 43); + + let mut data: u16 = 42; + let res = dummy_atomic::__atomic_add_fetch_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 43); + + let mut data: u32 = 42; + let res = dummy_atomic::__atomic_add_fetch_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 43); + + let mut data: u64 = 42; + let res = dummy_atomic::__atomic_add_fetch_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 43); + + let mut data: u8 = 42; + let res = dummy_atomic::__atomic_sub_fetch_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 41); + assert_eq!(data, 41); + + let mut data: u16 = 42; + let res = dummy_atomic::__atomic_sub_fetch_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 41); + assert_eq!(data, 41); + + let mut data: u32 = 42; + let res = dummy_atomic::__atomic_sub_fetch_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 41); + assert_eq!(data, 41); + + let mut data: u64 = 42; + let res = dummy_atomic::__atomic_sub_fetch_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 41); + assert_eq!(data, 41); + + let mut data: u8 = 43; + let res = dummy_atomic::__atomic_and_fetch_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 1); + assert_eq!(data, 1); + + let mut data: u16 = 43; + let res = dummy_atomic::__atomic_and_fetch_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 1); + assert_eq!(data, 1); + + let mut data: u32 = 43; + let res = dummy_atomic::__atomic_and_fetch_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 1); + assert_eq!(data, 1); + + let mut data: u64 = 43; + let res = dummy_atomic::__atomic_and_fetch_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 1); + assert_eq!(data, 1); + + let mut data: u8 = 43; + let res = dummy_atomic::__atomic_xor_fetch_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 42); + + let mut data: u16 = 43; + let res = dummy_atomic::__atomic_xor_fetch_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 42); + + let mut data: u32 = 43; + let res = dummy_atomic::__atomic_xor_fetch_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 42); + + let mut data: u64 = 43; + let res = dummy_atomic::__atomic_xor_fetch_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 42); + assert_eq!(data, 42); + + let mut data: u8 = 42; + let res = dummy_atomic::__atomic_or_fetch_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 43); + + let mut data: u16 = 42; + let res = dummy_atomic::__atomic_or_fetch_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 43); + + let mut data: u32 = 42; + let res = dummy_atomic::__atomic_or_fetch_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 43); + + let mut data: u64 = 42; + let res = dummy_atomic::__atomic_or_fetch_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 43); + assert_eq!(data, 43); + + let mut data: u8 = 1; + let res = dummy_atomic::__atomic_nand_fetch_1(&mut data as *mut u8 as *mut c_void, 1, 0); + assert_eq!(res, 0xFE); + assert_eq!(data, 0xFE); + + let mut data: u16 = 1; + let res = dummy_atomic::__atomic_nand_fetch_2(&mut data as *mut u16 as *mut c_void, 1, 0); + assert_eq!(res, 0xFFFE); + assert_eq!(data, 0xFFFE); + + let mut data: u32 = 1; + let res = dummy_atomic::__atomic_nand_fetch_4(&mut data as *mut u32 as *mut c_void, 1, 0); + assert_eq!(res, 0xFFFFFFFE); + assert_eq!(data, 0xFFFFFFFE); + + let mut data: u64 = 1; + let res = dummy_atomic::__atomic_nand_fetch_8(&mut data as *mut u64 as *mut c_void, 1, 0); + assert_eq!(res, 0xFFFFFFFFFFFFFFFE); + assert_eq!(data, 0xFFFFFFFFFFFFFFFE); +} + pub fn main() -> Result<(), Error> { test_basic(); test_load_data(); @@ -424,5 +808,10 @@ pub fn main() -> Result<(), Error> { test_vm_version(); test_current_cycles(); test_since(); + #[cfg(target_arch = "riscv64")] + { + test_atomic(); + test_atomic2(); + } Ok(()) } diff --git a/src/dummy_atomic.rs b/src/dummy_atomic.rs new file mode 100644 index 0000000..2be4429 --- /dev/null +++ b/src/dummy_atomic.rs @@ -0,0 +1,537 @@ +/// +/// Some Rust code can be compiled into atomic instructions for the RISC-V +/// target. However, these atomic instructions are not supported on ckb-vm. To +/// address this issue, this module has been introduced. +/// +/// This library provides a Rust dummy atomic implementation inspired by +/// [xxuejie/lib-dummy-atomics](https://github.com/xxuejie/lib-dummy-atomics). +/// +/// When the RISC-V atomic extension is disabled by specifying the +/// `target-feature=-a` flag, LLVM will attempt to link the atomic operations to +/// functions prefixed with `__atomic` in this module. For more details, refer +/// to the [LLVM Atomics Documentation](https://llvm.org/docs/Atomics.html). +/// +/// On the CKB-VM, only a single thread is present, making dummy atomic +/// operations sufficient for its purposes. +/// +use core::cmp::PartialEq; +use core::ffi::c_void; +use core::ops::{Add, BitAnd, BitOr, BitXor, Not, Sub}; + +fn atomic_exchange(ptr: *mut c_void, val: T) -> T { + unsafe { + let p = ptr as *mut T; + p.replace(val) + } +} + +fn atomic_compare_exchange( + ptr: *mut c_void, + expected: *mut c_void, + desired: T, +) -> bool { + unsafe { + let dst = ptr as *mut T; + let old = expected as *mut T; + let dst_val: T = dst.read(); + if dst_val == old.read() { + dst.write(desired); + true + } else { + old.write(dst_val); + false + } + } +} + +fn atomic_fetch_add + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + dst.write(old + val); + old + } +} + +fn atomic_fetch_sub + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + dst.write(old - val); + old + } +} + +fn atomic_fetch_xor + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + dst.write(old ^ val); + old + } +} + +fn atomic_fetch_and + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + dst.write(old & val); + old + } +} + +fn atomic_fetch_or + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + dst.write(old | val); + old + } +} + +fn atomic_fetch_nand + Not + Copy>( + ptr: *mut c_void, + val: T, +) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + dst.write(!(old & val)); + old + } +} + +fn atomic_add_fetch + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + let val2 = old + val; + dst.write(val2); + val2 + } +} + +fn atomic_sub_fetch + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + let val2 = old - val; + dst.write(val2); + val2 + } +} + +fn atomic_xor_fetch + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + let val2 = old ^ val; + dst.write(val2); + val2 + } +} + +fn atomic_and_fetch + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + let val2 = old & val; + dst.write(val2); + val2 + } +} + +fn atomic_or_fetch + Copy>(ptr: *mut c_void, val: T) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + let val2 = old | val; + dst.write(val2); + val2 + } +} + +fn atomic_nand_fetch + Not + Copy>( + ptr: *mut c_void, + val: T, +) -> T { + unsafe { + let dst = ptr as *mut T; + let old: T = dst.read(); + let val2 = !(old & val); + dst.write(val2); + val2 + } +} + +#[no_mangle] +pub extern "C" fn __atomic_exchange_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_exchange(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_exchange_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_exchange(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_exchange_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_exchange(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_exchange_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_exchange(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_compare_exchange_1( + ptr: *mut c_void, + expected: *mut c_void, + desired: u8, + _weak: bool, + _success_memorder: isize, + _failure_memorder: isize, +) -> bool { + atomic_compare_exchange(ptr, expected, desired) +} + +#[no_mangle] +pub extern "C" fn __atomic_compare_exchange_2( + ptr: *mut c_void, + expected: *mut c_void, + desired: u16, + _weak: bool, + _success_memorder: isize, + _failure_memorder: isize, +) -> bool { + atomic_compare_exchange(ptr, expected, desired) +} + +#[no_mangle] +pub extern "C" fn __atomic_compare_exchange_4( + ptr: *mut c_void, + expected: *mut c_void, + desired: u32, + _weak: bool, + _success_memorder: isize, + _failure_memorder: isize, +) -> bool { + atomic_compare_exchange(ptr, expected, desired) +} + +#[no_mangle] +pub extern "C" fn __atomic_compare_exchange_8( + ptr: *mut c_void, + expected: *mut c_void, + desired: u64, + _weak: bool, + _success_memorder: isize, + _failure_memorder: isize, +) -> bool { + atomic_compare_exchange(ptr, expected, desired) +} + +#[no_mangle] +pub extern "C" fn __atomic_load_1(ptr: *const c_void, _memorder: isize) -> u8 { + unsafe { + let p = ptr as *mut u8; + p.read() + } +} + +#[no_mangle] +pub extern "C" fn __atomic_load_2(ptr: *const c_void, _memorder: isize) -> u16 { + unsafe { + let p = ptr as *mut u16; + p.read() + } +} + +#[no_mangle] +pub extern "C" fn __atomic_load_4(ptr: *const c_void, _memorder: isize) -> u32 { + unsafe { + let p = ptr as *mut u32; + p.read() + } +} + +#[no_mangle] +pub extern "C" fn __atomic_load_8(ptr: *const c_void, _memorder: isize) -> u64 { + unsafe { + let p = ptr as *mut u64; + p.read() + } +} + +#[no_mangle] +pub extern "C" fn __atomic_store_1(ptr: *mut c_void, val: u8, _memorder: isize) { + unsafe { + let p = ptr as *mut u8; + p.write(val); + } +} + +#[no_mangle] +pub extern "C" fn __atomic_store_2(ptr: *mut c_void, val: u16, _memorder: isize) { + unsafe { + let p = ptr as *mut u16; + p.write(val); + } +} + +#[no_mangle] +pub extern "C" fn __atomic_store_4(ptr: *mut c_void, val: u32, _memorder: isize) { + unsafe { + let p = ptr as *mut u32; + p.write(val); + } +} + +#[no_mangle] +pub extern "C" fn __atomic_store_8(ptr: *mut c_void, val: u64, _memorder: isize) { + unsafe { + let p = ptr as *mut u64; + p.write(val); + } +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_add_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_fetch_add(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_add_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_fetch_add(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_add_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_fetch_add(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_add_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_fetch_add(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_sub_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_fetch_sub(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_sub_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_fetch_sub(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_sub_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_fetch_sub(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_sub_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_fetch_sub(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_and_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_fetch_and(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_and_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_fetch_and(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_and_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_fetch_and(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_and_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_fetch_and(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_xor_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_fetch_xor(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_xor_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_fetch_xor(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_xor_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_fetch_xor(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_xor_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_fetch_xor(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_or_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_fetch_or(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_or_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_fetch_or(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_or_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_fetch_or(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_or_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_fetch_or(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_nand_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_fetch_nand(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_nand_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_fetch_nand(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_nand_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_fetch_nand(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_fetch_nand_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_fetch_nand(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_add_fetch_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_add_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_add_fetch_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_add_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_add_fetch_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_add_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_add_fetch_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_add_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_sub_fetch_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_sub_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_sub_fetch_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_sub_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_sub_fetch_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_sub_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_sub_fetch_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_sub_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_and_fetch_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_and_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_and_fetch_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_and_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_and_fetch_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_and_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_and_fetch_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_and_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_xor_fetch_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_xor_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_xor_fetch_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_xor_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_xor_fetch_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_xor_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_xor_fetch_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_xor_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_or_fetch_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_or_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_or_fetch_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_or_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_or_fetch_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_or_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_or_fetch_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_or_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_nand_fetch_1(ptr: *mut c_void, val: u8, _memorder: isize) -> u8 { + atomic_nand_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_nand_fetch_2(ptr: *mut c_void, val: u16, _memorder: isize) -> u16 { + atomic_nand_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_nand_fetch_4(ptr: *mut c_void, val: u32, _memorder: isize) -> u32 { + atomic_nand_fetch(ptr, val) +} + +#[no_mangle] +pub extern "C" fn __atomic_nand_fetch_8(ptr: *mut c_void, val: u64, _memorder: isize) -> u64 { + atomic_nand_fetch(ptr, val) +} diff --git a/src/lib.rs b/src/lib.rs index 7f99ad3..f3ec82b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ pub mod global_alloc_macro; pub mod high_level; pub mod since; pub mod syscalls; + #[cfg(feature = "ckb-types")] pub use ckb_types; #[cfg(feature = "ckb-types")] @@ -35,3 +36,5 @@ pub mod dynamic_loading; pub mod dynamic_loading_c_impl; #[cfg(feature = "allocator")] pub use buddy_alloc; +#[cfg(feature = "dummy-atomic")] +pub mod dummy_atomic; diff --git a/test/Makefile b/test/Makefile index ad55d82..c082011 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,4 +1,4 @@ -test: clean build +test: build RUST_LOG=debug cargo test -- --nocapture make -C simulator build make -C simulator run @@ -6,6 +6,7 @@ test: clean build build: make -C shared-lib all-via-docker cd .. && capsule build + cd .. && RUSTFLAGS="-C target-feature=-a" capsule build -n ckb-std-tests clean: rm -rf ../build diff --git a/test/simulator/Cargo.toml b/test/simulator/Cargo.toml index 0981945..5a768ab 100644 --- a/test/simulator/Cargo.toml +++ b/test/simulator/Cargo.toml @@ -18,3 +18,5 @@ path = "src/exec_callee.rs" [dependencies] ckb-std = { path = "../..", features = ["ckb-types", "simulator"] } blake2b-ref = { version = "0.3", default-features = false } +bytes = { version = "1.6.0", default-features = false } +log = { version = "0.4.17", default-features = false }