diff --git a/Cargo.lock b/Cargo.lock index a197943e..3155994c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,6 +165,7 @@ dependencies = [ "aster-util", "aster-virtio", "atomic", + "atomic-integer-wrapper", "bitflags 1.3.2", "bitvec", "bytemuck", @@ -274,6 +275,15 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "atomic-integer-wrapper" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -333,7 +343,7 @@ checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", ] [[package]] @@ -488,7 +498,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", ] [[package]] @@ -523,7 +533,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", "unicode-xid", ] @@ -617,7 +627,7 @@ checksum = "ba330b70a5341d3bc730b8e205aaee97ddab5d9c448c4f51a7c2d924266fa8f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", ] [[package]] @@ -717,7 +727,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", ] [[package]] @@ -996,7 +1006,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", ] [[package]] @@ -1101,7 +1111,7 @@ dependencies = [ "proc-macro2", "quote", "rand", - "syn 2.0.49", + "syn 2.0.77", ] [[package]] @@ -1182,9 +1192,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1211,9 +1221,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1307,7 +1317,7 @@ checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", ] [[package]] @@ -1394,9 +1404,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.49" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -1445,7 +1455,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", ] [[package]] @@ -1557,7 +1567,7 @@ checksum = "26a7b1c2c808c3db854a54d5215e3f7e7aaf5dcfbce095598cba6af29895695d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", ] [[package]] @@ -1755,5 +1765,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.77", ] diff --git a/Cargo.toml b/Cargo.toml index 0bda9ac7..7e72f858 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ members = [ "kernel/libs/keyable-arc", "kernel/libs/typeflags", "kernel/libs/typeflags-util", + "kernel/libs/atomic-integer-wrapper", ] exclude = [ "kernel/libs/comp-sys/cargo-component", diff --git a/Makefile b/Makefile index bb228530..55e0f388 100644 --- a/Makefile +++ b/Makefile @@ -110,7 +110,8 @@ NON_OSDK_CRATES := \ kernel/libs/aster-rights-proc \ kernel/libs/keyable-arc \ kernel/libs/typeflags \ - kernel/libs/typeflags-util + kernel/libs/typeflags-util \ + kernel/libs/atomic-integer-wrapper # In contrast, OSDK crates depend on OSTD (or being `ostd` itself) # and need to be built or tested with OSDK. diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index d4369885..7733b25c 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -23,6 +23,7 @@ typeflags-util = { path = "libs/typeflags-util" } aster-rights-proc = { path = "libs/aster-rights-proc" } aster-util = { path = "libs/aster-util" } aster-bigtcp = { path = "libs/aster-bigtcp" } +atomic-integer-wrapper = { path = "libs/atomic-integer-wrapper" } id-alloc = { path = "../ostd/libs/id-alloc" } int-to-c-enum = { path = "libs/int-to-c-enum" } cpio-decoder = { path = "libs/cpio-decoder" } diff --git a/kernel/libs/atomic-integer-wrapper/Cargo.toml b/kernel/libs/atomic-integer-wrapper/Cargo.toml new file mode 100644 index 00000000..a91147dc --- /dev/null +++ b/kernel/libs/atomic-integer-wrapper/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "atomic-integer-wrapper" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.86" +quote = "1.0.37" +syn = { version = "2.0.77", features = ["full"] } diff --git a/kernel/libs/atomic-integer-wrapper/src/lib.rs b/kernel/libs/atomic-integer-wrapper/src/lib.rs new file mode 100644 index 00000000..eb6a23cc --- /dev/null +++ b/kernel/libs/atomic-integer-wrapper/src/lib.rs @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! This crate provides a function-like macro for defining atomic version of integer-like type. +//! +//! By integer-like type we mean types that implement `Into` and `From/TryFrom` +//! where `Integer` is a built-in integer type, e.g. u8. +//! +//! Below is a simple example. We define an atomic version `AtomicStatus` for integer-like +//! type `Status`. +//! ```ignore +//! use atomic_integer_wrapper::define_atomic_version_of_integer_like_type; +//! use core::sync::atomic::AtomicU8; +//! +//! #[repr(u8)] +//! pub enum Status { +//! Alive = 1, +//! Dead = 0, +//! } +//! +//! define_atomic_version_of_integer_like_type(Status, { +//! #[derive(Debug)] +//! pub struct AtomicStatus(AtomicU8); +//! }) +//! +//! impl From for Status { +//! // ... +//! } +//! +//! impl From for u8 { +//! // ... +//! } +//! ``` +//! +//! The `define_atomic_version_of_integer_like_type` macro will automatically implement +//! `core::sync::atomic::AtomicU8`'s commonly used methods for `AtomicStatus` like `load` and `store`. +//! +//! The default behavior of the macro when converting a built-in integer to an integer-like type is to use +//! implemented `From` trait for performance. If you'd like to enable some runtime checks that are implemented +//! in `TryFrom` trait, you can specify the `try_from` boolean parameter. In the example above, it's like +//! ```ignore +//! define_atomic_version_of_integer_like_type(Status, try_from = true, { +//! #[derive(Debug)] +//! pub struct AtomicStatus(AtomicU8); +//! }) +//! ``` +//! + +#![feature(let_chains)] +#![feature(proc_macro_diagnostic)] + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::{quote, quote_spanned}; +use syn::{ + braced, + parse::{Parse, ParseStream}, + parse_macro_input, + spanned::Spanned, + Error, Fields, Ident, ItemStruct, LitBool, Result, Token, Type, +}; + +struct Input { + integer_like_type: Type, + try_from: LitBool, + item: ItemStruct, +} + +impl Parse for Input { + fn parse(input: ParseStream) -> Result { + let integer_like_type: Type = input.parse()?; + input.parse::()?; + + let mut try_from = LitBool::new(false, Span::call_site()); + let lookahead = input.lookahead1(); + if lookahead.peek(Ident) { + let key = input.parse::()?; + if key != "try_from" { + return Err(Error::new( + key.span(), + format!(r#"Expected "try_from", found "{}""#, key), + )); + } + input.parse::()?; + try_from = input.parse()?; + input.parse::()?; + } + + let content; + braced!(content in input); + let item: ItemStruct = content.parse()?; + + if !input.is_empty() { + return Err(Error::new(Span::call_site(), "Unexpected token")); + } + + Ok(Input { + integer_like_type, + try_from, + item, + }) + } +} + +#[proc_macro] +pub fn define_atomic_version_of_integer_like_type(input: TokenStream) -> TokenStream { + let Input { + integer_like_type, + try_from, + item, + } = parse_macro_input!(input as Input); + + let atomic_wrapper = item.ident.clone(); + let atomic_integer_type = if let Fields::Unnamed(ref fields_unnamed) = item.fields + && fields_unnamed.unnamed.len() == 1 + { + fields_unnamed.unnamed.first().unwrap().ty.clone() + } else { + item.fields + .span() + .unwrap() + .error("Expected a parenthesized struct like `struct AtomicFoo(AtomicU8)`") + .emit(); + return TokenStream::new(); + }; + let from_integer = if try_from.value { + quote_spanned! {integer_like_type.span()=> + try_into().unwrap() + } + } else { + quote_spanned! {integer_like_type.span()=> + into() + } + }; + + let fn_new = quote! { + pub fn new(value: impl Into<#integer_like_type>) -> Self { + Self(<#atomic_integer_type>::new(value.into().into())) + } + }; + let fn_load = quote! { + pub fn load(&self, order: core::sync::atomic::Ordering) -> #integer_like_type { + self.0.load(order).#from_integer + } + }; + let fn_store = quote! { + pub fn store( + &self, + val: impl Into<#integer_like_type>, + order: core::sync::atomic::Ordering + ) { + self.0.store(val.into().into(), order); + } + }; + let fn_swap = quote! { + #[allow(dead_code)] + pub fn swap( + &self, + val: impl Into<#integer_like_type>, + order: core::sync::atomic::Ordering + ) -> #integer_like_type { + self.0.swap(val.into().into(), order).#from_integer + } + }; + let fn_compare_exchange = quote! { + #[allow(dead_code)] + pub fn compare_exchange( + &self, + current: impl Into<#integer_like_type>, + new: impl Into<#integer_like_type>, + success: core::sync::atomic::Ordering, + failure: core::sync::atomic::Ordering + ) -> core::result::Result<#integer_like_type, #integer_like_type> { + self.0 + .compare_exchange( + current.into().into(), + new.into().into(), + success, + failure + ) + .map(|val| val.#from_integer) + .map_err(|val| val.#from_integer) + } + }; + let fn_fetch_update = quote! { + #[allow(dead_code)] + pub fn fetch_update( + &self, + set_order: core::sync::atomic::Ordering, + fetch_order: core::sync::atomic::Ordering, + mut f: F + ) -> core::result::Result<#integer_like_type, #integer_like_type> + where + F: FnMut(#integer_like_type) -> Option<#integer_like_type>, + { + self.0 + .fetch_update( + set_order, + fetch_order, + |old| f(old.#from_integer).map(<#integer_like_type>::into) + ) + .map(|val| val.#from_integer) + .map_err(|val| val.#from_integer) + } + }; + + let expanded = quote! { + #item + + impl #atomic_wrapper { + #fn_new + + #fn_load + + #fn_store + + #fn_swap + + #fn_compare_exchange + + #fn_fetch_update + } + }; + + TokenStream::from(expanded) +} diff --git a/kernel/src/fs/ext2/impl_for_vfs/inode.rs b/kernel/src/fs/ext2/impl_for_vfs/inode.rs index 206d9847..9a92fbe9 100644 --- a/kernel/src/fs/ext2/impl_for_vfs/inode.rs +++ b/kernel/src/fs/ext2/impl_for_vfs/inode.rs @@ -93,7 +93,7 @@ impl Inode for Ext2Inode { } fn set_owner(&self, uid: Uid) -> Result<()> { - self.set_uid(uid.as_u32()); + self.set_uid(uid.into()); Ok(()) } @@ -102,7 +102,7 @@ impl Inode for Ext2Inode { } fn set_group(&self, gid: Gid) -> Result<()> { - self.set_gid(gid.as_u32()); + self.set_gid(gid.into()); Ok(()) } diff --git a/kernel/src/fs/pipe.rs b/kernel/src/fs/pipe.rs index 0005cdeb..10503f80 100644 --- a/kernel/src/fs/pipe.rs +++ b/kernel/src/fs/pipe.rs @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use core::sync::atomic::AtomicU32; - -use atomic::Ordering; +use core::sync::atomic::{AtomicU32, Ordering}; use super::{ file_handle::FileLike, diff --git a/kernel/src/ipc/semaphore/system_v/sem.rs b/kernel/src/ipc/semaphore/system_v/sem.rs index b1125615..c74f5e26 100644 --- a/kernel/src/ipc/semaphore/system_v/sem.rs +++ b/kernel/src/ipc/semaphore/system_v/sem.rs @@ -6,6 +6,7 @@ use core::{ time::Duration, }; +use atomic_integer_wrapper::define_atomic_version_of_integer_like_type; use ostd::sync::{PreemptDisabled, Waiter, Waker}; use super::sem_set::{SemSetInner, SEMVMX}; @@ -46,22 +47,16 @@ pub enum Status { Removed = 2, } -struct AtomicStatus(AtomicU16); - -impl AtomicStatus { - fn new(status: Status) -> Self { - Self(AtomicU16::new(status as u16)) - } - - fn status(&self) -> Status { - Status::try_from(self.0.load(Ordering::Relaxed)).unwrap() - } - - fn set_status(&self, status: Status) { - self.0.store(status as u16, Ordering::Relaxed); +impl From for u16 { + fn from(value: Status) -> Self { + value as u16 } } +define_atomic_version_of_integer_like_type!(Status, try_from = true, { + struct AtomicStatus(AtomicU16); +}); + /// Pending atomic semop. pub struct PendingOp { sops: Vec, @@ -76,7 +71,7 @@ impl PendingOp { } pub fn set_status(&self, status: Status) { - self.status.set_status(status); + self.status.store(status, Ordering::Relaxed); } pub fn waker(&self) -> &Option> { @@ -92,7 +87,7 @@ impl Debug for PendingOp { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("PendingOp") .field("sops", &self.sops) - .field("status", &(self.status.status())) + .field("status", &(self.status.load(Ordering::Relaxed))) .field("pid", &self.pid) .finish() } @@ -205,7 +200,7 @@ pub fn sem_op( drop(local_sem_sets); waiter.wait(); - match status.status() { + match status.load(Ordering::Relaxed) { Status::Normal => Ok(()), Status::Removed => Err(Error::new(Errno::EIDRM)), Status::Pending => { diff --git a/kernel/src/net/socket/unix/stream/socket.rs b/kernel/src/net/socket/unix/stream/socket.rs index a61e3dd0..f94e1db5 100644 --- a/kernel/src/net/socket/unix/stream/socket.rs +++ b/kernel/src/net/socket/unix/stream/socket.rs @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 -use core::sync::atomic::AtomicBool; +use core::sync::atomic::{AtomicBool, Ordering}; -use atomic::Ordering; use takeable::Takeable; use super::{ diff --git a/kernel/src/net/socket/vsock/stream/socket.rs b/kernel/src/net/socket/vsock/stream/socket.rs index 40b1a348..62b385e9 100644 --- a/kernel/src/net/socket/vsock/stream/socket.rs +++ b/kernel/src/net/socket/vsock/stream/socket.rs @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use core::sync::atomic::AtomicBool; - -use atomic::Ordering; +use core::sync::atomic::{AtomicBool, Ordering}; use super::{connected::Connected, connecting::Connecting, init::Init, listen::Listen}; use crate::{ diff --git a/kernel/src/process/credentials/capabilities.rs b/kernel/src/process/credentials/capabilities.rs index 4abb3b53..6a8e0736 100644 --- a/kernel/src/process/credentials/capabilities.rs +++ b/kernel/src/process/credentials/capabilities.rs @@ -2,6 +2,7 @@ use core::sync::atomic::{AtomicU64, Ordering}; +use atomic_integer_wrapper::define_atomic_version_of_integer_like_type; use bitflags::bitflags; bitflags! { @@ -53,6 +54,8 @@ bitflags! { } impl CapSet { + const MASK: u64 = (1 << (CapSet::most_significant_bit() + 1)) - 1; + /// Converts the capability set to a `u32`. The higher bits are truncated. pub fn as_u32(&self) -> u32 { self.bits() as u32 @@ -64,31 +67,37 @@ impl CapSet { } /// The most significant bit in a 64-bit `CapSet` that may be set to represent a Linux capability. - pub fn most_significant_bit() -> u8 { + pub const fn most_significant_bit() -> u8 { // CHECKPOINT_RESTORE is the Linux capability with the largest numerical value 40 } } -#[derive(Debug)] -pub(super) struct AtomicCapSet(AtomicU64); +impl TryFrom for CapSet { + type Error = &'static str; -impl AtomicCapSet { - pub const fn new(capset: CapSet) -> Self { - Self(AtomicU64::new(capset.bits)) - } - - pub fn set(&self, capset: CapSet) { - self.0.store(capset.bits(), Ordering::Relaxed); - } - - pub fn get(&self) -> CapSet { - CapSet::from_bits_truncate(self.0.load(Ordering::Relaxed)) + fn try_from(value: u64) -> Result { + if value & !CapSet::MASK != 0 { + Err("Invalid CapSet.") + } else { + Ok(CapSet { bits: value }) + } } } +impl From for u64 { + fn from(value: CapSet) -> Self { + value.bits() + } +} + +define_atomic_version_of_integer_like_type!(CapSet, try_from = true, { + #[derive(Debug)] + pub(super) struct AtomicCapSet(AtomicU64); +}); + impl Clone for AtomicCapSet { fn clone(&self) -> Self { - Self::new(self.get()) + Self::new(self.load(Ordering::Relaxed)) } } diff --git a/kernel/src/process/credentials/credentials_.rs b/kernel/src/process/credentials/credentials_.rs index 9e8585e7..daf175c5 100644 --- a/kernel/src/process/credentials/credentials_.rs +++ b/kernel/src/process/credentials/credentials_.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 +use core::sync::atomic::Ordering; + use ostd::sync::{RwLockReadGuard, RwLockWriteGuard}; use super::{group::AtomicGid, user::AtomicUid, Gid, Uid}; @@ -75,28 +77,28 @@ impl Credentials_ { // ******* Uid methods ******* pub(super) fn ruid(&self) -> Uid { - self.ruid.get() + self.ruid.load(Ordering::Relaxed) } pub(super) fn euid(&self) -> Uid { - self.euid.get() + self.euid.load(Ordering::Relaxed) } pub(super) fn suid(&self) -> Uid { - self.suid.get() + self.suid.load(Ordering::Relaxed) } pub(super) fn fsuid(&self) -> Uid { - self.fsuid.get() + self.fsuid.load(Ordering::Relaxed) } pub(super) fn set_uid(&self, uid: Uid) { if self.is_privileged() { - self.ruid.set(uid); - self.euid.set(uid); - self.suid.set(uid); + self.ruid.store(uid, Ordering::Relaxed); + self.euid.store(uid, Ordering::Relaxed); + self.suid.store(uid, Ordering::Relaxed); } else { - self.euid.set(uid); + self.euid.store(uid, Ordering::Relaxed); } } @@ -108,13 +110,13 @@ impl Credentials_ { self.set_resuid_unchecked(ruid, euid, None); if should_set_suid { - self.suid.set(self.euid()); + self.suid.store(self.euid(), Ordering::Release); } // FIXME: should we set fsuid here? The linux document for syscall `setfsuid` is contradictory // with the document of syscall `setreuid`. The `setfsuid` document says the `fsuid` is always // the same as `euid`, but `setreuid` does not mention the `fsuid` should be set. - self.fsuid.set(self.euid()); + self.fsuid.store(self.euid(), Ordering::Release); Ok(()) } @@ -129,7 +131,7 @@ impl Credentials_ { self.set_resuid_unchecked(ruid, euid, suid); - self.fsuid.set(self.euid()); + self.fsuid.store(self.euid(), Ordering::Release); Ok(()) } @@ -142,7 +144,7 @@ impl Credentials_ { }; if self.is_privileged() { - self.fsuid.set(fsuid); + self.fsuid.store(fsuid, Ordering::Release); return Ok(old_fsuid); } @@ -153,17 +155,17 @@ impl Credentials_ { ) } - self.fsuid.set(fsuid); + self.fsuid.store(fsuid, Ordering::Release); Ok(old_fsuid) } pub(super) fn set_euid(&self, euid: Uid) { - self.euid.set(euid); + self.euid.store(euid, Ordering::Release); } pub(super) fn set_suid(&self, suid: Uid) { - self.suid.set(suid); + self.suid.store(suid, Ordering::Release); } // For `setreuid`, ruid can *NOT* be set to old suid, @@ -217,43 +219,43 @@ impl Credentials_ { fn set_resuid_unchecked(&self, ruid: Option, euid: Option, suid: Option) { if let Some(ruid) = ruid { - self.ruid.set(ruid); + self.ruid.store(ruid, Ordering::Relaxed); } if let Some(euid) = euid { - self.euid.set(euid); + self.euid.store(euid, Ordering::Relaxed); } if let Some(suid) = suid { - self.suid.set(suid); + self.suid.store(suid, Ordering::Relaxed); } } // ******* Gid methods ******* pub(super) fn rgid(&self) -> Gid { - self.rgid.get() + self.rgid.load(Ordering::Relaxed) } pub(super) fn egid(&self) -> Gid { - self.egid.get() + self.egid.load(Ordering::Relaxed) } pub(super) fn sgid(&self) -> Gid { - self.sgid.get() + self.sgid.load(Ordering::Relaxed) } pub(super) fn fsgid(&self) -> Gid { - self.fsgid.get() + self.fsgid.load(Ordering::Relaxed) } pub(super) fn set_gid(&self, gid: Gid) { if self.is_privileged() { - self.rgid.set(gid); - self.egid.set(gid); - self.sgid.set(gid); + self.rgid.store(gid, Ordering::Relaxed); + self.egid.store(gid, Ordering::Relaxed); + self.sgid.store(gid, Ordering::Relaxed); } else { - self.egid.set(gid); + self.egid.store(gid, Ordering::Relaxed); } } @@ -265,10 +267,10 @@ impl Credentials_ { self.set_resgid_unchecked(rgid, egid, None); if should_set_sgid { - self.sgid.set(self.egid()); + self.sgid.store(self.egid(), Ordering::Relaxed); } - self.fsgid.set(self.egid()); + self.fsgid.store(self.egid(), Ordering::Relaxed); Ok(()) } @@ -283,7 +285,7 @@ impl Credentials_ { self.set_resgid_unchecked(rgid, egid, sgid); - self.fsgid.set(self.egid()); + self.fsgid.store(self.egid(), Ordering::Relaxed); Ok(()) } @@ -296,7 +298,7 @@ impl Credentials_ { }; if self.is_privileged() { - self.fsgid.set(fsgid); + self.fsgid.store(fsgid, Ordering::Relaxed); return Ok(old_fsgid); } @@ -307,17 +309,17 @@ impl Credentials_ { ) } - self.fsgid.set(fsgid); + self.fsgid.store(fsgid, Ordering::Relaxed); Ok(old_fsgid) } pub(super) fn set_egid(&self, egid: Gid) { - self.egid.set(egid); + self.egid.store(egid, Ordering::Relaxed); } pub(super) fn set_sgid(&self, sgid: Gid) { - self.sgid.set(sgid); + self.sgid.store(sgid, Ordering::Relaxed); } // For `setregid`, rgid can *NOT* be set to old sgid, @@ -371,15 +373,15 @@ impl Credentials_ { fn set_resgid_unchecked(&self, rgid: Option, egid: Option, sgid: Option) { if let Some(rgid) = rgid { - self.rgid.set(rgid); + self.rgid.store(rgid, Ordering::Relaxed); } if let Some(egid) = egid { - self.egid.set(egid); + self.egid.store(egid, Ordering::Relaxed); } if let Some(sgid) = sgid { - self.sgid.set(sgid); + self.sgid.store(sgid, Ordering::Relaxed); } } @@ -396,27 +398,30 @@ impl Credentials_ { // ******* Linux Capability methods ******* pub(super) fn inheritable_capset(&self) -> CapSet { - self.inheritable_capset.get() + self.inheritable_capset.load(Ordering::Relaxed) } pub(super) fn permitted_capset(&self) -> CapSet { - self.permitted_capset.get() + self.permitted_capset.load(Ordering::Relaxed) } pub(super) fn effective_capset(&self) -> CapSet { - self.effective_capset.get() + self.effective_capset.load(Ordering::Relaxed) } pub(super) fn set_inheritable_capset(&self, inheritable_capset: CapSet) { - self.inheritable_capset.set(inheritable_capset); + self.inheritable_capset + .store(inheritable_capset, Ordering::Relaxed); } pub(super) fn set_permitted_capset(&self, permitted_capset: CapSet) { - self.permitted_capset.set(permitted_capset); + self.permitted_capset + .store(permitted_capset, Ordering::Relaxed); } pub(super) fn set_effective_capset(&self, effective_capset: CapSet) { - self.effective_capset.set(effective_capset); + self.effective_capset + .store(effective_capset, Ordering::Relaxed); } } diff --git a/kernel/src/process/credentials/group.rs b/kernel/src/process/credentials/group.rs index 82f639db..a42d4418 100644 --- a/kernel/src/process/credentials/group.rs +++ b/kernel/src/process/credentials/group.rs @@ -2,6 +2,8 @@ use core::sync::atomic::{AtomicU32, Ordering}; +use atomic_integer_wrapper::define_atomic_version_of_integer_like_type; + use crate::prelude::*; #[derive(Debug, Clone, Copy, Pod, Default, PartialEq, Eq, PartialOrd, Ord)] @@ -17,10 +19,6 @@ impl Gid { Self(ROOT_GID) } - pub const fn as_u32(&self) -> u32 { - self.0 - } - pub const fn is_root(&self) -> bool { self.0 == ROOT_GID } @@ -28,25 +26,25 @@ impl Gid { const ROOT_GID: u32 = 0; -#[derive(Debug)] -pub(super) struct AtomicGid(AtomicU32); - -impl AtomicGid { - pub const fn new(gid: Gid) -> Self { - Self(AtomicU32::new(gid.as_u32())) - } - - pub fn set(&self, gid: Gid) { - self.0.store(gid.as_u32(), Ordering::Relaxed) - } - - pub fn get(&self) -> Gid { - Gid(self.0.load(Ordering::Relaxed)) +impl From for Gid { + fn from(value: u32) -> Self { + Self::new(value) } } +impl From for u32 { + fn from(value: Gid) -> Self { + value.0 + } +} + +define_atomic_version_of_integer_like_type!(Gid, { + #[derive(Debug)] + pub(super) struct AtomicGid(AtomicU32); +}); + impl Clone for AtomicGid { fn clone(&self) -> Self { - Self(AtomicU32::new(self.0.load(Ordering::Relaxed))) + Self::new(self.load(Ordering::Relaxed)) } } diff --git a/kernel/src/process/credentials/user.rs b/kernel/src/process/credentials/user.rs index 34f81cda..c8ac36e0 100644 --- a/kernel/src/process/credentials/user.rs +++ b/kernel/src/process/credentials/user.rs @@ -2,6 +2,8 @@ use core::sync::atomic::{AtomicU32, Ordering}; +use atomic_integer_wrapper::define_atomic_version_of_integer_like_type; + use crate::prelude::*; #[derive(Debug, Clone, Copy, PartialEq, Eq, Pod)] @@ -22,35 +24,33 @@ impl Uid { pub const fn is_root(&self) -> bool { self.0 == ROOT_UID } +} - pub const fn as_u32(&self) -> u32 { - self.0 +impl From for Uid { + fn from(value: u32) -> Self { + Self::new(value) } } -#[derive(Debug)] -pub(super) struct AtomicUid(AtomicU32); +impl From for u32 { + fn from(value: Uid) -> Self { + value.0 + } +} + +define_atomic_version_of_integer_like_type!(Uid, { + #[derive(Debug)] + pub(super) struct AtomicUid(AtomicU32); +}); impl AtomicUid { - pub const fn new(uid: Uid) -> Self { - Self(AtomicU32::new(uid.as_u32())) - } - - pub fn set(&self, uid: Uid) { - self.0.store(uid.as_u32(), Ordering::Release) - } - - pub fn get(&self) -> Uid { - Uid(self.0.load(Ordering::Acquire)) - } - pub fn is_root(&self) -> bool { - self.get().is_root() + self.load(Ordering::Acquire).is_root() } } impl Clone for AtomicUid { fn clone(&self) -> Self { - Self(AtomicU32::new(self.0.load(Ordering::Acquire))) + Self::new(self.load(Ordering::Acquire)) } } diff --git a/kernel/src/process/process/mod.rs b/kernel/src/process/process/mod.rs index b8dc35da..b766e901 100644 --- a/kernel/src/process/process/mod.rs +++ b/kernel/src/process/process/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use core::sync::atomic::Ordering; +use core::sync::atomic::{AtomicU32, Ordering}; use self::timer_manager::PosixTimerManager; use super::{ @@ -35,6 +35,7 @@ mod timer_manager; use aster_rights::Full; use atomic::Atomic; +use atomic_integer_wrapper::define_atomic_version_of_integer_like_type; pub use builder::ProcessBuilder; pub use job_control::JobControl; use ostd::{sync::WaitQueue, task::Task}; @@ -44,6 +45,10 @@ pub use terminal::Terminal; /// Process id. pub type Pid = u32; +define_atomic_version_of_integer_like_type!(Pid, { + #[derive(Debug)] + pub struct AtomicPid(AtomicU32); +}); /// Process group id. pub type Pgid = u32; /// Session Id. @@ -107,11 +112,11 @@ pub struct Process { /// /// This type caches the value of the PID so that it can be retrieved cheaply. /// -/// The benefit of using `ParentProcess` over `(Mutex>, Atomic,)` is to +/// The benefit of using `ParentProcess` over `(Mutex>, AtomicPid,)` is to /// enforce the invariant that the cached PID and the weak reference are always kept in sync. pub struct ParentProcess { process: Mutex>, - pid: Atomic, + pid: AtomicPid, } impl ParentProcess { @@ -123,7 +128,7 @@ impl ParentProcess { Self { process: Mutex::new(process), - pid: Atomic::new(pid), + pid: AtomicPid::new(pid), } } diff --git a/kernel/src/process/signal/sig_mask.rs b/kernel/src/process/signal/sig_mask.rs index ca8a1bec..332d0fd4 100644 --- a/kernel/src/process/signal/sig_mask.rs +++ b/kernel/src/process/signal/sig_mask.rs @@ -12,6 +12,8 @@ use core::{ sync::atomic::{AtomicU64, Ordering}, }; +use atomic_integer_wrapper::define_atomic_version_of_integer_like_type; + use super::{constants::MIN_STD_SIG_NUM, sig_num::SigNum}; use crate::prelude::*; @@ -158,68 +160,26 @@ impl LowerHex for SigSet { /// [`Relaxed`]: core::sync::atomic::Ordering::Relaxed pub type AtomicSigMask = AtomicSigSet; -/// An atomic signal set. -pub struct AtomicSigSet(AtomicU64); +define_atomic_version_of_integer_like_type!(SigSet, { + pub struct AtomicSigSet(AtomicU64); +}); impl From for AtomicSigSet { fn from(set: SigSet) -> Self { - AtomicSigSet(AtomicU64::new(set.bits)) + Self::new(set) } } impl AtomicSigSet { pub fn new_empty() -> Self { - AtomicSigSet(AtomicU64::new(0)) + AtomicSigSet::new(0) } pub fn new_full() -> Self { - AtomicSigSet(AtomicU64::new(!0)) - } - - pub fn load(&self, ordering: Ordering) -> SigSet { - SigSet { - bits: self.0.load(ordering), - } - } - - pub fn store(&self, new_mask: impl Into, ordering: Ordering) { - self.0.store(new_mask.into().bits, ordering); - } - - pub fn swap(&self, new_mask: impl Into, ordering: Ordering) -> SigSet { - let bits = self.0.swap(new_mask.into().bits, ordering); - SigSet { bits } + AtomicSigSet::new(!0) } pub fn contains(&self, signals: impl Into, ordering: Ordering) -> bool { - SigSet { - bits: self.0.load(ordering), - } - .contains(signals.into()) - } - - /// Applies an update to the signal set. - /// - /// This is the same as [`AtomicU64::fetch_update`], but the closure `f` - /// operates on a [`SigMask`] instead of a `u64`. - /// - /// It would be a bit slow since it would check if the value is written by - /// another thread while evaluating the closure `f`. If you are confident - /// that there's no such race, don't use this method. - pub fn fetch_update( - &self, - set_order: Ordering, - fetch_order: Ordering, - mut f: F, - ) -> core::result::Result - where - F: FnMut(SigMask) -> Option, - { - self.0 - .fetch_update(set_order, fetch_order, |bits| { - f(SigMask { bits }).map(|set| set.bits) - }) - .map(SigMask::from) - .map_err(SigMask::from) + self.load(ordering).contains(signals.into()) } } diff --git a/kernel/src/process/signal/sig_num.rs b/kernel/src/process/signal/sig_num.rs index 2a5cf2d4..74dbab3f 100644 --- a/kernel/src/process/signal/sig_num.rs +++ b/kernel/src/process/signal/sig_num.rs @@ -2,9 +2,7 @@ #![allow(dead_code)] -use core::sync::atomic::AtomicU8; - -use atomic::Ordering; +use core::sync::atomic::{AtomicU8, Ordering}; use super::constants::*; use crate::prelude::*; diff --git a/kernel/src/syscall/getegid.rs b/kernel/src/syscall/getegid.rs index 656c8725..3ac52e74 100644 --- a/kernel/src/syscall/getegid.rs +++ b/kernel/src/syscall/getegid.rs @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::prelude::*; +use crate::{prelude::*, process::Gid}; pub fn sys_getegid(ctx: &Context) -> Result { let egid = ctx.posix_thread.credentials().egid(); - Ok(SyscallReturn::Return(egid.as_u32() as _)) + Ok(SyscallReturn::Return(>::into(egid) as _)) } diff --git a/kernel/src/syscall/geteuid.rs b/kernel/src/syscall/geteuid.rs index d86c3901..8f628762 100644 --- a/kernel/src/syscall/geteuid.rs +++ b/kernel/src/syscall/geteuid.rs @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::prelude::*; +use crate::{prelude::*, process::Uid}; pub fn sys_geteuid(ctx: &Context) -> Result { let euid = ctx.posix_thread.credentials().euid(); - Ok(SyscallReturn::Return(euid.as_u32() as _)) + Ok(SyscallReturn::Return(>::into(euid) as _)) } diff --git a/kernel/src/syscall/getgid.rs b/kernel/src/syscall/getgid.rs index 03da1410..d5a567fb 100644 --- a/kernel/src/syscall/getgid.rs +++ b/kernel/src/syscall/getgid.rs @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::prelude::*; +use crate::{prelude::*, process::Gid}; pub fn sys_getgid(ctx: &Context) -> Result { let gid = ctx.posix_thread.credentials().rgid(); - Ok(SyscallReturn::Return(gid.as_u32() as _)) + Ok(SyscallReturn::Return(>::into(gid) as _)) } diff --git a/kernel/src/syscall/getuid.rs b/kernel/src/syscall/getuid.rs index fb1b1711..84e2667a 100644 --- a/kernel/src/syscall/getuid.rs +++ b/kernel/src/syscall/getuid.rs @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 use super::SyscallReturn; -use crate::prelude::*; +use crate::{prelude::*, process::Uid}; pub fn sys_getuid(ctx: &Context) -> Result { let uid = ctx.posix_thread.credentials().ruid(); - Ok(SyscallReturn::Return(uid.as_u32() as _)) + Ok(SyscallReturn::Return(>::into(uid) as _)) } diff --git a/kernel/src/syscall/setfsgid.rs b/kernel/src/syscall/setfsgid.rs index b83ae1f4..a4948374 100644 --- a/kernel/src/syscall/setfsgid.rs +++ b/kernel/src/syscall/setfsgid.rs @@ -17,5 +17,7 @@ pub fn sys_setfsgid(gid: i32, ctx: &Context) -> Result { credentials.set_fsgid(fsgid)? }; - Ok(SyscallReturn::Return(old_fsgid.as_u32() as _)) + Ok(SyscallReturn::Return( + >::into(old_fsgid) as _ + )) } diff --git a/kernel/src/syscall/setfsuid.rs b/kernel/src/syscall/setfsuid.rs index b5445905..22067ad7 100644 --- a/kernel/src/syscall/setfsuid.rs +++ b/kernel/src/syscall/setfsuid.rs @@ -17,5 +17,7 @@ pub fn sys_setfsuid(uid: i32, ctx: &Context) -> Result { credentials.set_fsuid(fsuid)? }; - Ok(SyscallReturn::Return(old_fsuid.as_u32() as _)) + Ok(SyscallReturn::Return( + >::into(old_fsuid) as _ + )) } diff --git a/kernel/src/syscall/stat.rs b/kernel/src/syscall/stat.rs index 39239faa..d76b34f3 100644 --- a/kernel/src/syscall/stat.rs +++ b/kernel/src/syscall/stat.rs @@ -121,8 +121,8 @@ impl From for Stat { st_ino: info.ino, st_nlink: info.nlinks, st_mode: info.type_ as u32 | info.mode.bits() as u32, - st_uid: info.uid.as_u32(), - st_gid: info.gid.as_u32(), + st_uid: info.uid.into(), + st_gid: info.gid.into(), __pad0: 0, st_rdev: info.rdev, st_size: info.size as isize, diff --git a/kernel/src/thread/status.rs b/kernel/src/thread/status.rs index f3f56eac..69c542e2 100644 --- a/kernel/src/thread/status.rs +++ b/kernel/src/thread/status.rs @@ -1,43 +1,14 @@ // SPDX-License-Identifier: MPL-2.0 -use core::sync::atomic::{AtomicU8, Ordering}; +use core::sync::atomic::AtomicU8; +use atomic_integer_wrapper::define_atomic_version_of_integer_like_type; use int_to_c_enum::TryFromInt; -/// A `ThreadStatus` which can be safely shared between threads. -#[derive(Debug)] -pub struct AtomicThreadStatus(AtomicU8); - -impl AtomicThreadStatus { - /// Creates a new atomic status. - pub fn new(status: ThreadStatus) -> Self { - Self(AtomicU8::new(status as u8)) - } - - /// Loads a value from the atomic status. - pub fn load(&self, order: Ordering) -> ThreadStatus { - ThreadStatus::try_from(self.0.load(order)).unwrap() - } - - /// Stores a value into the atomic status. - pub fn store(&self, new_status: ThreadStatus, order: Ordering) { - self.0.store(new_status as u8, order); - } - - /// Stores a value into the atomic status if the current value is the same as the `current` value. - pub fn compare_exchange( - &self, - current: ThreadStatus, - new: ThreadStatus, - success: Ordering, - failure: Ordering, - ) -> Result { - self.0 - .compare_exchange(current as u8, new as u8, success, failure) - .map(|val| ThreadStatus::try_from(val).unwrap()) - .map_err(|val| ThreadStatus::try_from(val).unwrap()) - } -} +define_atomic_version_of_integer_like_type!(ThreadStatus, try_from = true, { + #[derive(Debug)] + pub struct AtomicThreadStatus(AtomicU8); +}); #[derive(Clone, Copy, PartialEq, Eq, Debug, TryFromInt)] #[repr(u8)] @@ -61,3 +32,9 @@ impl ThreadStatus { *self == ThreadStatus::Stopped } } + +impl From for u8 { + fn from(value: ThreadStatus) -> Self { + value as u8 + } +}