diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 70a79c07189dc..09cd77f89237b 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -66,6 +66,7 @@ pub mod inherent; pub mod error; pub mod instances; pub mod migrations; +pub mod sync; pub mod traits; pub mod weights; diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index c9814e28a7ae4..ec19f9cd284ca 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -48,46 +48,39 @@ pub mod unhashed; pub mod weak_bounded_vec; mod transaction_level_tracker { - use core::sync::atomic::{AtomicU32, Ordering}; + use crate::sync::RuntimeCell; type Layer = u32; - static NUM_LEVELS: AtomicU32 = AtomicU32::new(0); + static NUM_LEVELS: RuntimeCell = RuntimeCell::new(0); const TRANSACTIONAL_LIMIT: Layer = 255; pub fn get_transaction_level() -> Layer { - NUM_LEVELS.load(Ordering::SeqCst) + NUM_LEVELS.get() } /// Increments the transaction level. Returns an error if levels go past the limit. /// /// Returns a guard that when dropped decrements the transaction level automatically. pub fn inc_transaction_level() -> Result { - NUM_LEVELS - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |existing_levels| { - if existing_levels >= TRANSACTIONAL_LIMIT { - return None - } - // Cannot overflow because of check above. - Some(existing_levels + 1) - }) - .map_err(|_| ())?; + let existing_levels = get_transaction_level(); + if existing_levels >= TRANSACTIONAL_LIMIT { + return Err(()) + } + // Cannot overflow because of check above. + NUM_LEVELS.set(existing_levels + 1); Ok(StorageLayerGuard) } fn dec_transaction_level() { - NUM_LEVELS - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |existing_levels| { - if existing_levels == 0 { - log::warn!( - "We are underflowing with calculating transactional levels. Not great, but let's not panic...", - ); - None - } else { - // Cannot underflow because of checks above. - Some(existing_levels - 1) - } - }) - .ok(); + let existing_levels = get_transaction_level(); + if existing_levels == 0 { + log::warn!( + "We are underflowing with calculating transactional levels. Not great, but let's not panic...", + ); + } else { + // Cannot underflow because of checks above. + NUM_LEVELS.set(existing_levels - 1); + } } pub fn is_transactional() -> bool { diff --git a/frame/support/src/sync.rs b/frame/support/src/sync.rs new file mode 100644 index 0000000000000..5fc4d29f8cf18 --- /dev/null +++ b/frame/support/src/sync.rs @@ -0,0 +1,76 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// 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. + +//! Types used to sync access to shared data. All of these types rely on the assumption +//! that no data parallelism exists within the runtime. + +use sp_std::{ + cell::{Cell, RefCell}, + ops::{Deref, DerefMut}, +}; + +/// A [`Sync`] version of [`Cell`]. Safe to use within the runtime. +pub struct RuntimeCell(Cell); + +impl RuntimeCell { + /// See [`Cell::new`] + pub const fn new(value: T) -> Self { + Self(Cell::new(value)) + } +} + +unsafe impl Sync for RuntimeCell {} + +impl Deref for RuntimeCell { + type Target = Cell; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for RuntimeCell { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// A [`Sync`] version of [`RefCell`]. Safe to use within the runtime. +pub struct RuntimeRefCell(RefCell); + +impl RuntimeRefCell { + /// See [`RefCell::new`] + pub const fn new(value: T) -> Self { + Self(RefCell::new(value)) + } +} + +unsafe impl Sync for RuntimeRefCell {} + +impl Deref for RuntimeRefCell { + type Target = RefCell; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for RuntimeRefCell { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +}