mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Implement the Atomic type
This commit is contained in:
328
stdlib/public/Synchronization/AtomicStorage.swift.gyb
Normal file
328
stdlib/public/Synchronization/AtomicStorage.swift.gyb
Normal file
@@ -0,0 +1,328 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift Atomics open source project
|
||||
//
|
||||
// Copyright (c) 2023 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
% from SwiftAtomics import *
|
||||
|
||||
import Builtin
|
||||
|
||||
% for (type, size, alignment, builtin) in atomicTypes:
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ${size} bit Atomic Storage
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
@_alignment(${alignment})
|
||||
@frozen
|
||||
public struct ${type} {
|
||||
@usableFromInline
|
||||
var storage: ${builtin}
|
||||
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
@inlinable
|
||||
init(_ builtin: ${builtin}) {
|
||||
self.storage = builtin
|
||||
}
|
||||
}
|
||||
|
||||
// ${size} bit atomic loads
|
||||
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
extension Atomic where Value.AtomicRepresentation == ${type} {
|
||||
% for (swift, api, doc, llvm) in loadOrderings:
|
||||
/// Atomically loads and returns the current value, applying the specified
|
||||
/// memory ordering.
|
||||
///
|
||||
/// - Parameter ordering: The memory ordering to apply on this operation.
|
||||
/// - Returns: The current value.
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public func load(ordering: Atomic${api}) -> Value {
|
||||
Value.decodeAtomicRepresentation(
|
||||
${type}(Builtin.atomicload_${llvm}_Int${size}(rawAddress))
|
||||
)
|
||||
}
|
||||
% end
|
||||
}
|
||||
|
||||
// ${size} bit atomic stores
|
||||
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
extension Atomic where Value.AtomicRepresentation == ${type} {
|
||||
% for (swift, api, doc, llvm) in storeOrderings:
|
||||
/// Atomically sets the current value to `desired`, applying the specified
|
||||
/// memory ordering.
|
||||
///
|
||||
/// - Parameter desired: The desired new value.
|
||||
/// - Parameter ordering: The memory ordering to apply on this operation.
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public func store(
|
||||
_ desired: consuming Value,
|
||||
ordering: Atomic${api}
|
||||
) {
|
||||
Builtin.atomicstore_${llvm}_Int${size}(
|
||||
rawAddress,
|
||||
Value.encodeAtomicRepresentation(desired).storage
|
||||
)
|
||||
}
|
||||
% end
|
||||
}
|
||||
|
||||
// ${size} bit atomic exchanges
|
||||
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
extension Atomic where Value.AtomicRepresentation == ${type} {
|
||||
% for (swift, api, _, llvm, _) in updateOrderings:
|
||||
/// Atomically sets the current value to `desired` and returns the original
|
||||
/// value, applying the specified memory ordering.
|
||||
///
|
||||
/// - Parameter desired: The desired new value.
|
||||
/// - Parameter ordering: The memory ordering to apply on this operation.
|
||||
/// - Returns: The original value.
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public func exchange(
|
||||
_ desired: consuming Value,
|
||||
ordering: Atomic${api}
|
||||
) -> Value {
|
||||
let desired = Value.encodeAtomicRepresentation(desired).storage
|
||||
let result = Builtin.atomicrmw_xchg_${llvm}_Int${size}(rawAddress, desired)
|
||||
let atomicStorage = ${type}(result)
|
||||
|
||||
return Value.decodeAtomicRepresentation(atomicStorage)
|
||||
}
|
||||
% end
|
||||
}
|
||||
|
||||
// ${size} bit atomic compare and exchanges
|
||||
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
extension Atomic where Value.AtomicRepresentation == ${type} {
|
||||
% for (_, api, _, llvm, failure) in updateOrderings:
|
||||
/// Perform an atomic compare and exchange operation on the current value,
|
||||
/// applying the specified memory ordering.
|
||||
///
|
||||
/// This operation performs the following algorithm as a single atomic
|
||||
/// transaction:
|
||||
///
|
||||
/// ```
|
||||
/// atomic(self) { currentValue in
|
||||
/// let original = currentValue
|
||||
/// guard original == expected else { return (false, original) }
|
||||
/// currentValue = desired
|
||||
/// return (true, original)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This method implements a "strong" compare and exchange operation
|
||||
/// that does not permit spurious failures.
|
||||
///
|
||||
/// - Parameter expected: The expected current value.
|
||||
/// - Parameter desired: The desired new value.
|
||||
/// - Parameter ordering: The memory ordering to apply on this operation.
|
||||
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
|
||||
/// the exchange was successful, and `original` is the original value.
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public func compareExchange(
|
||||
expected: consuming Value,
|
||||
desired: consuming Value,
|
||||
ordering: Atomic${api}
|
||||
) -> (exchanged: Bool, original: Value) {
|
||||
compareExchange(
|
||||
expected: expected,
|
||||
desired: desired,
|
||||
successOrdering: ordering,
|
||||
failureOrdering: .${llvmToCaseName(failure)}
|
||||
)
|
||||
}
|
||||
% end
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
extension Atomic where Value.AtomicRepresentation == ${type} {
|
||||
% for (_, successApi, _, successLLVM, successFailure) in updateOrderings:
|
||||
% for (_, failureApi, _, failureLLVM) in loadOrderings:
|
||||
/// Perform an atomic compare and exchange operation on the current value,
|
||||
/// applying the specified success/failure memory orderings.
|
||||
///
|
||||
/// This operation performs the following algorithm as a single atomic
|
||||
/// transaction:
|
||||
///
|
||||
/// ```
|
||||
/// atomic(self) { currentValue in
|
||||
/// let original = currentValue
|
||||
/// guard original == expected else { return (false, original) }
|
||||
/// currentValue = desired
|
||||
/// return (true, original)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The `successOrdering` argument specifies the memory ordering to use when
|
||||
/// the operation manages to update the current value, while `failureOrdering`
|
||||
/// will be used when the operation leaves the value intact.
|
||||
///
|
||||
/// This method implements a "strong" compare and exchange operation
|
||||
/// that does not permit spurious failures.
|
||||
///
|
||||
/// - Parameter expected: The expected current value.
|
||||
/// - Parameter desired: The desired new value.
|
||||
/// - Parameter successOrdering: The memory ordering to apply if this
|
||||
/// operation performs the exchange.
|
||||
/// - Parameter failureOrdering: The memory ordering to apply on this
|
||||
/// operation does not perform the exchange.
|
||||
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
|
||||
/// the exchange was successful, and `original` is the original value.
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public func compareExchange(
|
||||
expected: consuming Value,
|
||||
desired: consuming Value,
|
||||
successOrdering: Atomic${successApi},
|
||||
failureOrdering: Atomic${failureApi}
|
||||
) -> (exchanged: Bool, original: Value) {
|
||||
let expected = Value.encodeAtomicRepresentation(expected).storage
|
||||
let desired = Value.encodeAtomicRepresentation(desired).storage
|
||||
let (ov, won) = Builtin.cmpxchg_${actualOrders(successLLVM, failureLLVM)}_Int${size}(
|
||||
rawAddress,
|
||||
expected,
|
||||
desired
|
||||
)
|
||||
|
||||
return (
|
||||
exchanged: Bool(won),
|
||||
original: Value.decodeAtomicRepresentation(${type}(ov))
|
||||
)
|
||||
}
|
||||
% end
|
||||
% end
|
||||
}
|
||||
|
||||
// ${size} bit atomic weak compare and exchanges
|
||||
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
extension Atomic where Value.AtomicRepresentation == ${type} {
|
||||
% for (_, api, _, llvm, failure) in updateOrderings:
|
||||
/// Perform an atomic weak compare and exchange operation on the current
|
||||
/// value, applying the memory ordering. This compare-exchange variant is
|
||||
/// allowed to spuriously fail; it is designed to be called in a loop until
|
||||
/// it indicates a successful exchange has happened.
|
||||
///
|
||||
/// This operation performs the following algorithm as a single atomic
|
||||
/// transaction:
|
||||
///
|
||||
/// ```
|
||||
/// atomic(self) { currentValue in
|
||||
/// let original = currentValue
|
||||
/// guard original == expected else { return (false, original) }
|
||||
/// currentValue = desired
|
||||
/// return (true, original)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// (In this weak form, transient conditions may cause the `original ==
|
||||
/// expected` check to sometimes return false when the two values are in fact
|
||||
/// the same.)
|
||||
///
|
||||
/// - Parameter expected: The expected current value.
|
||||
/// - Parameter desired: The desired new value.
|
||||
/// - Parameter ordering: The memory ordering to apply on this operation.
|
||||
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
|
||||
/// the exchange was successful, and `original` is the original value.
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public func weakCompareExchange(
|
||||
expected: consuming Value,
|
||||
desired: consuming Value,
|
||||
ordering: Atomic${api}
|
||||
) -> (exchanged: Bool, original: Value) {
|
||||
weakCompareExchange(
|
||||
expected: expected,
|
||||
desired: desired,
|
||||
successOrdering: ordering,
|
||||
failureOrdering: .${llvmToCaseName(failure)}
|
||||
)
|
||||
}
|
||||
% end
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
extension Atomic where Value.AtomicRepresentation == ${type} {
|
||||
% for (_, successApi, _, successLLVM, successFailure) in updateOrderings:
|
||||
% for (_, failureApi, _, failureLLVM) in loadOrderings:
|
||||
/// Perform an atomic weak compare and exchange operation on the current
|
||||
/// value, applying the specified success/failure memory orderings. This
|
||||
/// compare-exchange variant is allowed to spuriously fail; it is designed to
|
||||
/// be called in a loop until it indicates a successful exchange has happened.
|
||||
///
|
||||
/// This operation performs the following algorithm as a single atomic
|
||||
/// transaction:
|
||||
///
|
||||
/// ```
|
||||
/// atomic(self) { currentValue in
|
||||
/// let original = currentValue
|
||||
/// guard original == expected else { return (false, original) }
|
||||
/// currentValue = desired
|
||||
/// return (true, original)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// (In this weak form, transient conditions may cause the `original ==
|
||||
/// expected` check to sometimes return false when the two values are in fact
|
||||
/// the same.)
|
||||
///
|
||||
/// The `ordering` argument specifies the memory ordering to use when the
|
||||
/// operation manages to update the current value, while `failureOrdering`
|
||||
/// will be used when the operation leaves the value intact.
|
||||
///
|
||||
/// - Parameter expected: The expected current value.
|
||||
/// - Parameter desired: The desired new value.
|
||||
/// - Parameter successOrdering: The memory ordering to apply if this
|
||||
/// operation performs the exchange.
|
||||
/// - Parameter failureOrdering: The memory ordering to apply on this
|
||||
/// operation does not perform the exchange.
|
||||
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
|
||||
/// the exchange was successful, and `original` is the original value.
|
||||
@available(SwiftStdlib 5.10, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public func weakCompareExchange(
|
||||
expected: consuming Value,
|
||||
desired: consuming Value,
|
||||
successOrdering: Atomic${successApi},
|
||||
failureOrdering: Atomic${failureApi}
|
||||
) -> (exchanged: Bool, original: Value) {
|
||||
let expected = Value.encodeAtomicRepresentation(expected).storage
|
||||
let desired = Value.encodeAtomicRepresentation(desired).storage
|
||||
let (ov, won) = Builtin.cmpxchg_${actualOrders(successLLVM, failureLLVM)}_weak_Int${size}(
|
||||
rawAddress,
|
||||
expected,
|
||||
desired
|
||||
)
|
||||
|
||||
return (
|
||||
exchanged: Bool(won),
|
||||
original: Value.decodeAtomicRepresentation(${type}(ov))
|
||||
)
|
||||
}
|
||||
% end
|
||||
% end
|
||||
}
|
||||
|
||||
% end
|
||||
Reference in New Issue
Block a user