├── .github ├── ISSUE_TEMPLATE │ ├── BUG_REPORT.md │ ├── FEATURE_REQUEST.md │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE │ └── NEW.md └── workflows │ └── pull_request.yml ├── .gitignore ├── .spi.yml ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── Package.swift ├── README.md ├── Sources ├── Atomics │ ├── Atomics.docc │ │ ├── Atomics.md │ │ └── Extensions │ │ │ ├── AtomicInteger.md │ │ │ ├── AtomicIntegerStorage.md │ │ │ ├── AtomicLoadOrdering.md │ │ │ ├── AtomicOptionalReferenceStorage.md │ │ │ ├── AtomicOptionalWrappable.md │ │ │ ├── AtomicRawRepresentableStorage.md │ │ │ ├── AtomicReference.md │ │ │ ├── AtomicReferenceStorage.md │ │ │ ├── AtomicStorage.md │ │ │ ├── AtomicStoreOrdering.md │ │ │ ├── AtomicUpdateOrdering.md │ │ │ ├── AtomicValue.md │ │ │ ├── ManagedAtomic.md │ │ │ ├── ManagedAtomicLazyReference.md │ │ │ ├── UnsafeAtomic.md │ │ │ └── UnsafeAtomicLazyReference.md │ ├── CMakeLists.txt │ ├── Conformances │ │ ├── AtomicBool.swift.gyb │ │ ├── IntegerConformances.swift.gyb │ │ ├── OptionalRawRepresentable.swift │ │ ├── PointerConformances.swift.gyb │ │ ├── RawRepresentable.swift │ │ └── autogenerated │ │ │ ├── AtomicBool.swift │ │ │ ├── IntegerConformances.swift │ │ │ └── PointerConformances.swift │ ├── Primitives │ │ ├── Primitives.native.swift.gyb │ │ └── autogenerated │ │ │ └── Primitives.native.swift │ ├── Protocols │ │ ├── AtomicInteger.swift │ │ ├── AtomicOptionalWrappable.swift │ │ ├── AtomicReference.swift │ │ ├── AtomicStorage.swift │ │ └── AtomicValue.swift │ ├── Types │ │ ├── AtomicMemoryOrderings.swift │ │ ├── DoubleWord.swift │ │ ├── IntegerOperations.swift.gyb │ │ ├── ManagedAtomic.swift │ │ ├── ManagedAtomicLazyReference.swift │ │ ├── UnsafeAtomic.swift │ │ ├── UnsafeAtomicLazyReference.swift │ │ └── autogenerated │ │ │ └── IntegerOperations.swift │ └── Unmanaged extensions.swift ├── CMakeLists.txt └── _AtomicsShims │ ├── CMakeLists.txt │ ├── include │ ├── _AtomicsShims.h │ └── module.modulemap │ └── src │ └── _AtomicsShims.c ├── Tests ├── AtomicsTests │ ├── AtomicLazyReference.swift │ ├── Basics │ │ ├── BasicAtomicBoolTests.swift.gyb │ │ ├── BasicAtomicDoubleWordTests.swift.gyb │ │ ├── BasicAtomicInt16Tests.swift.gyb │ │ ├── BasicAtomicInt32Tests.swift.gyb │ │ ├── BasicAtomicInt64Tests.swift.gyb │ │ ├── BasicAtomicInt8Tests.swift.gyb │ │ ├── BasicAtomicIntTests.swift.gyb │ │ ├── BasicAtomicMutablePointerTests.swift.gyb │ │ ├── BasicAtomicMutableRawPointerTests.swift.gyb │ │ ├── BasicAtomicOptionalMutablePointerTests.swift.gyb │ │ ├── BasicAtomicOptionalMutableRawPointerTests.swift.gyb │ │ ├── BasicAtomicOptionalPointerTests.swift.gyb │ │ ├── BasicAtomicOptionalRawPointerTests.swift.gyb │ │ ├── BasicAtomicOptionalRawRepresentableTests.swift.gyb │ │ ├── BasicAtomicOptionalReferenceTests.swift.gyb │ │ ├── BasicAtomicOptionalUnmanagedTests.swift.gyb │ │ ├── BasicAtomicPointerTests.swift.gyb │ │ ├── BasicAtomicRawPointerTests.swift.gyb │ │ ├── BasicAtomicRawRepresentableTests.swift.gyb │ │ ├── BasicAtomicReferenceTests.swift.gyb │ │ ├── BasicAtomicUInt16Tests.swift.gyb │ │ ├── BasicAtomicUInt32Tests.swift.gyb │ │ ├── BasicAtomicUInt64Tests.swift.gyb │ │ ├── BasicAtomicUInt8Tests.swift.gyb │ │ ├── BasicAtomicUIntTests.swift.gyb │ │ ├── BasicAtomicUnmanagedTests.swift.gyb │ │ ├── BasicTestSupport.swift │ │ ├── BasicTests.gyb-template │ │ └── autogenerated │ │ │ ├── BasicAtomicBoolTests.swift │ │ │ ├── BasicAtomicDoubleWordTests.swift │ │ │ ├── BasicAtomicInt16Tests.swift │ │ │ ├── BasicAtomicInt32Tests.swift │ │ │ ├── BasicAtomicInt64Tests.swift │ │ │ ├── BasicAtomicInt8Tests.swift │ │ │ ├── BasicAtomicIntTests.swift │ │ │ ├── BasicAtomicMutablePointerTests.swift │ │ │ ├── BasicAtomicMutableRawPointerTests.swift │ │ │ ├── BasicAtomicOptionalMutablePointerTests.swift │ │ │ ├── BasicAtomicOptionalMutableRawPointerTests.swift │ │ │ ├── BasicAtomicOptionalPointerTests.swift │ │ │ ├── BasicAtomicOptionalRawPointerTests.swift │ │ │ ├── BasicAtomicOptionalRawRepresentableTests.swift │ │ │ ├── BasicAtomicOptionalReferenceTests.swift │ │ │ ├── BasicAtomicOptionalUnmanagedTests.swift │ │ │ ├── BasicAtomicPointerTests.swift │ │ │ ├── BasicAtomicRawPointerTests.swift │ │ │ ├── BasicAtomicRawRepresentableTests.swift │ │ │ ├── BasicAtomicReferenceTests.swift │ │ │ ├── BasicAtomicUInt16Tests.swift │ │ │ ├── BasicAtomicUInt32Tests.swift │ │ │ ├── BasicAtomicUInt64Tests.swift │ │ │ ├── BasicAtomicUInt8Tests.swift │ │ │ ├── BasicAtomicUIntTests.swift │ │ │ └── BasicAtomicUnmanagedTests.swift │ ├── DoubleWord.swift │ ├── LifetimeTracked.swift │ ├── LockFreeQueue.swift │ ├── LockFreeSingleConsumerStack.swift │ ├── StrongReferenceRace.swift │ ├── StrongReferenceShuffle.swift │ ├── StrongReferenceSubclass.swift │ └── main.swift ├── CMakeLists.txt └── lit │ ├── AtomicsFolding.swift.gyb │ ├── UnsafeAtomicInitializers.swift.gyb │ └── autogenerated │ ├── AtomicsFolding.swift │ └── UnsafeAtomicInitializers.swift ├── Utilities ├── generate-sources.sh ├── gyb ├── gyb.py ├── gyb_utils.py └── run-full-tests.sh ├── Xcode ├── Atomics.xcconfig ├── Atomics.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Atomics.xcscheme ├── Atomics.xctestplan ├── AtomicsTests.xcconfig ├── README.md └── Shared.xcconfig └── cmake └── modules └── SwiftSupport.cmake /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: Something isn't working as expected 4 | labels: bug 5 | --- 6 | 7 | 17 | 18 | Replace this paragraph with a short description of the incorrect behavior. 19 | (If this is a regression, please note the last version of the package that exhibited the correct behavior in addition to your current version.) 20 | 21 | ### Information 22 | 23 | - **Package version:** What tag or branch of swift-atomics are you using? 24 | - **Platform version:** Please tell us the version number of your operating system. 25 | - **Swift version:** Paste the output of `swift --version` here. 26 | 27 | ### Checklist 28 | 29 | - [ ] If possible, I've reproduced the issue using the `main` branch of this package. 30 | - [ ] I've searched for [existing reports](https://github.com/apple/swift-atomics/issues) of the same issue. 31 | 32 | ### Steps to Reproduce 33 | Replace this paragraph with an explanation of how to reproduce the incorrect behavior. 34 | Include a simple code example, if possible. 35 | 36 | ### Expected behavior 37 | Describe what you expect to happen. 38 | 39 | ### Actual behavior 40 | Describe or copy/paste the behavior you observe. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💡 Feature Request 3 | about: A suggestion for a new feature 4 | labels: enhancement 5 | --- 6 | 7 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: ❓ Discussion Forum 4 | url: https://forums.swift.org/c/related-projects/swift-atomics/ 5 | about: Questions about using Swift Atomics? Ask here! 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 9 | 10 | 14 | 15 | 16 | ### Checklist 17 | - [ ] I've read the [Contribution Guidelines](/README.md#contributing-to-swift-atomics) 18 | - [ ] My contributions are licensed under the [Swift license](/LICENSE.txt). 19 | - [ ] I've followed the coding style of the rest of the project. 20 | - [ ] I've added tests covering all new code paths my change adds to the project (if appropriate). 21 | - [ ] I've verified that my change does not break any existing tests. 22 | - [ ] I've updated the documentation if necessary. 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/NEW.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | ### Description 13 | Replace this paragraph with a description of your changes and rationale. 14 | Provide links to an existing issue or external references/discussions, if appropriate. 15 | 16 | ### Detailed Design 17 | Include any additional information about the design here. At minimum, describe a synopsis of any public API additions. 18 | 19 | ```swift 20 | /// The new feature implemented by this pull request. 21 | public struct Example: AtomicValue { 22 | } 23 | ``` 24 | 25 | ### Documentation 26 | How has the new feature been documented? 27 | Have the relevant portions of the guides in the Documentation folder been updated in addition to symbol-level documentation? 28 | 29 | ### Testing 30 | How is the new feature tested? 31 | 32 | ### Performance 33 | How did you verify the new feature performs as expected? 34 | 35 | ### Source Impact 36 | What is the impact of this change on existing users of this package? Does it deprecate or remove any existing API? 37 | 38 | ### Checklist 39 | - [ ] I've read the [Contribution Guidelines](/README.md#contributing-to-swift-atomics) 40 | - [ ] My contributions are licensed under the [Swift license](https://swift.org/LICENSE.txt). 41 | - [ ] I've followed the coding style of the rest of the project. 42 | - [ ] I've added tests covering all new code paths my change adds to the project (to the extent possible). 43 | - [ ] I've verified that my change does not break any existing tests. 44 | - [ ] I've updated the documentation (if appropriate). 45 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Pull request 2 | 3 | on: 4 | pull_request: 5 | types: [opened, reopened, synchronize] 6 | 7 | jobs: 8 | tests: 9 | name: Test 10 | uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main 11 | with: 12 | linux_exclude_swift_versions: '[{"swift_version": "5.8"}, {"swift_version": "5.9"}]' 13 | windows_exclude_swift_versions: '[{"swift_version": "5.9"}]' 14 | 15 | soundness: 16 | name: Soundness 17 | uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main 18 | with: 19 | license_header_check_project_name: "Swift.org" 20 | docs_check_enabled: false 21 | license_header_check_enabled: false 22 | format_check_enabled: false 23 | python_lint_check_enabled: false 24 | shell_check_enabled: false 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.pyc 3 | .DS_Store 4 | .*.sw? 5 | /.build 6 | /.swiftpm 7 | xcuserdata/ 8 | /*.xcodeproj 9 | .docc-build 10 | -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | builder: 3 | configs: 4 | - documentation_targets: [Atomics] 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | This source file is part of the Swift Atomics Open Source Project 3 | 4 | Copyright (c) 2021 - 2025 Apple Inc. and the Swift project authors 5 | Licensed under Apache License v2.0 with Runtime Library Exception 6 | 7 | See https://swift.org/LICENSE.txt for license information 8 | #]] 9 | 10 | cmake_minimum_required(VERSION 3.16) 11 | project(swift-atomics 12 | LANGUAGES C Swift) 13 | 14 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) 15 | 16 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 17 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 18 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 19 | set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) 20 | 21 | if(CMAKE_SYSTEM_NAME STREQUAL Windows OR CMAKE_SYSTEM_NAME STREQUAL Darwin) 22 | option(BUILD_SHARED_LIBS "Build shared libraries by default" YES) 23 | endif() 24 | 25 | include(CTest) 26 | include(SwiftSupport) 27 | 28 | set(ATOMICS_SWIFT_FLAGS) 29 | set(ATOMICS_C_FLAGS) 30 | 31 | if(CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 5.9) 32 | list(APPEND ATOMICS_SWIFT_FLAGS 33 | "-enable-experimental-feature BuiltinModule" 34 | ) 35 | endif() 36 | 37 | add_subdirectory(Sources) 38 | if(BUILD_TESTING) 39 | add_subdirectory(Tests) 40 | endif() 41 | 42 | get_property(SWIFT_ATOMICS_EXPORTS GLOBAL PROPERTY SWIFT_ATOMICS_EXPORTS) 43 | export(TARGETS ${SWIFT_ATOMICS_EXPORTS} 44 | NAMESPACE SwiftAtomics:: 45 | FILE swift-atomics-config.cmake 46 | EXPORT_LINK_INTERFACE_LIBRARIES) 47 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | To be a truly great community, Swift.org needs to welcome developers from all walks of life, 3 | with different backgrounds, and with a wide range of experience. A diverse and friendly 4 | community will have more great ideas, more unique perspectives, and produce more great 5 | code. We will work diligently to make the Swift community welcoming to everyone. 6 | 7 | To give clarity of what is expected of our members, Swift.org has adopted the code of conduct 8 | defined by [contributor-covenant.org](https://www.contributor-covenant.org). This document is used across many open source 9 | communities, and we think it articulates our values well. The full text is copied below: 10 | 11 | ### Contributor Code of Conduct v1.3 12 | As contributors and maintainers of this project, and in the interest of fostering an open and 13 | welcoming community, we pledge to respect all people who contribute through reporting 14 | issues, posting feature requests, updating documentation, submitting pull requests or patches, 15 | and other activities. 16 | 17 | We are committed to making participation in this project a harassment-free experience for 18 | everyone, regardless of level of experience, gender, gender identity and expression, sexual 19 | orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or 20 | nationality. 21 | 22 | Examples of unacceptable behavior by participants include: 23 | - The use of sexualized language or imagery 24 | - Personal attacks 25 | - Trolling or insulting/derogatory comments 26 | - Public or private harassment 27 | - Publishing other’s private information, such as physical or electronic addresses, without explicit permission 28 | - Other unethical or unprofessional conduct 29 | 30 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 31 | commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of 32 | Conduct, or to ban temporarily or permanently any contributor for other behaviors that they 33 | deem inappropriate, threatening, offensive, or harmful. 34 | 35 | By adopting this Code of Conduct, project maintainers commit themselves to fairly and 36 | consistently applying these principles to every aspect of managing this project. Project 37 | maintainers who do not follow or enforce the Code of Conduct may be permanently removed 38 | from the project team. 39 | 40 | This code of conduct applies both within project spaces and in public spaces when an 41 | individual is representing the project or its community. 42 | 43 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 44 | contacting a project maintainer at [conduct@swift.org](mailto:conduct@swift.org). All complaints will be reviewed and 45 | investigated and will result in a response that is deemed necessary and appropriate to the 46 | circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter 47 | of an incident. 48 | 49 | *This policy is adapted from the Contributor Code of Conduct [version 1.3.0](http://contributor-covenant.org/version/1/3/0/).* 50 | 51 | ### Reporting 52 | A working group of community members is committed to promptly addressing any [reported 53 | issues](mailto:conduct@swift.org). Working group members are volunteers appointed by the project lead, with a 54 | preference for individuals with varied backgrounds and perspectives. Membership is expected 55 | to change regularly, and may grow or shrink. 56 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | By submitting a pull request, you represent that you have the right to license 2 | your contribution to Apple and the community, and agree by submitting the patch 3 | that your contributions are licensed under the [Swift 4 | license](https://swift.org/LICENSE.txt). 5 | 6 | --- 7 | 8 | Before submitting the pull request, please make sure you have tested your 9 | changes and that they follow the Swift project [guidelines for contributing 10 | code](https://swift.org/contributing/#contributing-code). 11 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.10 2 | //===----------------------------------------------------------------------===// 3 | // 4 | // This source file is part of the Swift.org open source project 5 | // 6 | // Copyright (c) 2020 - 2025 Apple Inc. and the Swift project authors 7 | // Licensed under Apache License v2.0 with Runtime Library Exception 8 | // 9 | // See https://swift.org/LICENSE.txt for license information 10 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | import PackageDescription 15 | 16 | var _cSettings: [CSetting] = [] 17 | var _swiftSettings: [SwiftSetting] = [] 18 | 19 | // Enable the use of native Swift compiler builtins instead of C atomics. 20 | _cSettings += [ 21 | ] 22 | _swiftSettings += [ 23 | .enableExperimentalFeature("BuiltinModule") 24 | ] 25 | 26 | let package = Package( 27 | name: "swift-atomics", 28 | products: [ 29 | .library( 30 | name: "Atomics", 31 | targets: ["Atomics"]), 32 | ], 33 | targets: [ 34 | .target( 35 | name: "_AtomicsShims", 36 | exclude: [ 37 | "CMakeLists.txt" 38 | ] 39 | ), 40 | .target( 41 | name: "Atomics", 42 | dependencies: ["_AtomicsShims"], 43 | exclude: [ 44 | "CMakeLists.txt", 45 | "Conformances/AtomicBool.swift.gyb", 46 | "Conformances/IntegerConformances.swift.gyb", 47 | "Conformances/PointerConformances.swift.gyb", 48 | "Primitives/Primitives.native.swift.gyb", 49 | "Types/IntegerOperations.swift.gyb", 50 | ], 51 | cSettings: _cSettings, 52 | swiftSettings: _swiftSettings 53 | ), 54 | .testTarget( 55 | name: "AtomicsTests", 56 | dependencies: ["Atomics"], 57 | exclude: [ 58 | "main.swift", 59 | "Basics/BasicTests.gyb-template", 60 | "Basics/BasicAtomicBoolTests.swift.gyb", 61 | "Basics/BasicAtomicDoubleWordTests.swift.gyb", 62 | "Basics/BasicAtomicInt16Tests.swift.gyb", 63 | "Basics/BasicAtomicInt32Tests.swift.gyb", 64 | "Basics/BasicAtomicInt64Tests.swift.gyb", 65 | "Basics/BasicAtomicInt8Tests.swift.gyb", 66 | "Basics/BasicAtomicIntTests.swift.gyb", 67 | "Basics/BasicAtomicMutablePointerTests.swift.gyb", 68 | "Basics/BasicAtomicMutableRawPointerTests.swift.gyb", 69 | "Basics/BasicAtomicOptionalMutablePointerTests.swift.gyb", 70 | "Basics/BasicAtomicOptionalMutableRawPointerTests.swift.gyb", 71 | "Basics/BasicAtomicOptionalPointerTests.swift.gyb", 72 | "Basics/BasicAtomicOptionalRawPointerTests.swift.gyb", 73 | "Basics/BasicAtomicOptionalRawRepresentableTests.swift.gyb", 74 | "Basics/BasicAtomicOptionalReferenceTests.swift.gyb", 75 | "Basics/BasicAtomicOptionalUnmanagedTests.swift.gyb", 76 | "Basics/BasicAtomicPointerTests.swift.gyb", 77 | "Basics/BasicAtomicRawPointerTests.swift.gyb", 78 | "Basics/BasicAtomicRawRepresentableTests.swift.gyb", 79 | "Basics/BasicAtomicReferenceTests.swift.gyb", 80 | "Basics/BasicAtomicUInt16Tests.swift.gyb", 81 | "Basics/BasicAtomicUInt32Tests.swift.gyb", 82 | "Basics/BasicAtomicUInt64Tests.swift.gyb", 83 | "Basics/BasicAtomicUInt8Tests.swift.gyb", 84 | "Basics/BasicAtomicUIntTests.swift.gyb", 85 | "Basics/BasicAtomicUnmanagedTests.swift.gyb", 86 | ], 87 | swiftSettings: _swiftSettings 88 | ), 89 | ] 90 | ) 91 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Atomics.md: -------------------------------------------------------------------------------- 1 | # ``Atomics`` 2 | 3 | An atomics library for Swift. 4 | 5 | ## Overview 6 | 7 | This package implements an atomics library for Swift, providing atomic operations for a variety of Swift types, including integers and pointer values. The goal is to enable intrepid developers to start building synchronization constructs directly in Swift. 8 | 9 | Atomic operations aren't subject to the usual exclusivity rules. The same memory location may be safely read and updated from multiple concurrent threads of execution, as long as all such access is done through atomic operations. For example, here is a trivial atomic counter: 10 | 11 | ``` swift 12 | import Atomics 13 | import Dispatch 14 | 15 | let counter = ManagedAtomic(0) 16 | 17 | DispatchQueue.concurrentPerform(iterations: 10) { _ in 18 | for _ in 0 ..< 1_000_000 { 19 | counter.wrappingIncrement(ordering: .relaxed) 20 | } 21 | } 22 | counter.load(ordering: .relaxed) // ⟹ 10_000_000 23 | ``` 24 | 25 | The only way to access the counter value is to use one of the methods provided by `ManagedAtomic`, each of which implement a particular atomic operation, and each of which require an explicit ordering value. (Swift supports a subset of the C/C++ memory orderings.) 26 | 27 | ## Features 28 | 29 | The package implements atomic operations for the following Swift constructs, all of which conform to the public `AtomicValue` protocol: 30 | 31 | - Standard signed integer types (`Int`, `Int64`, `Int32`, `Int16`, `Int8`) 32 | - Standard unsigned integer types (`UInt`, `UInt64`, `UInt32`, `UInt16`, `UInt8`) 33 | - Booleans (`Bool`) 34 | - Standard pointer types (`UnsafeRawPointer`, `UnsafeMutableRawPointer`, `UnsafePointer`, `UnsafeMutablePointer`), along with their optional-wrapped forms (such as `Optional>`) 35 | - Unmanaged references (`Unmanaged`, `Optional>`) 36 | - A special `DoubleWord` type that consists of two `UInt` values, `low` and `high`, providing double-wide atomic primitives 37 | - Any `RawRepresentable` type whose `RawValue` is in turn an atomic type (such as simple custom enum types) 38 | - Strong references to class instances that opted into atomic use (by conforming to the `AtomicReference` protocol) 39 | 40 | Of particular note is full support for atomic strong references. This provides a convenient memory reclamation solution for concurrent data structures that fits perfectly with Swift's reference counting memory management model. (Atomic strong references are implemented in terms of `DoubleWord` operations.) However, accessing an atomic strong reference is (relatively) expensive, so we also provide a separate set of efficient constructs (`ManagedAtomicLazyReference` and `UnsafeAtomicLazyReference`) for the common case of a lazily initialized (but otherwise constant) atomic strong reference. 41 | 42 | ### Lock-Free vs Wait-Free Operations 43 | 44 | All atomic operations exposed by this package are guaranteed to have lock-free implementations. However, we do not guarantee wait-free operation -- depending on the capabilities of the target platform, some of the exposed operations may be implemented by compare-and-exchange loops. That said, all atomic operations map directly to dedicated CPU instructions where available -- to the extent supported by llvm & Clang. 45 | 46 | ### Memory Management 47 | 48 | Atomic access is implemented in terms of dedicated atomic storage representations that are kept distinct from the corresponding regular (non-atomic) type. (E.g., the actual integer value underlying the counter above isn't directly accessible.) This has several advantages: 49 | 50 | - it helps prevent accidental non-atomic access to atomic variables, 51 | - it enables custom storage representations (such as the one used by atomic strong references), and 52 | - it is a better fit with the standard C atomics library that we use to implement the actual operations (as enabled by [SE-0282]). 53 | 54 | [SE-0282]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0282-atomics.md 55 | 56 | While the underlying pointer-based atomic operations are exposed as static methods on the corresponding `AtomicStorage` types, we strongly recommend the use of higher-level atomic wrappers to manage the details of preparing/disposing atomic storage. This version of the library provides two wrapper types: 57 | 58 | - an easy to use, memory-safe `ManagedAtomic` generic class and 59 | - a less convenient, but more flexible `UnsafeAtomic` generic struct. 60 | 61 | Both constructs provide the following operations on all `AtomicValue` types: 62 | 63 | ```swift 64 | func load(ordering: AtomicLoadOrdering) -> Value 65 | func store(_ desired: Value, ordering: AtomicStoreOrdering) 66 | func exchange(_ desired: Value, ordering: AtomicUpdateOrdering) -> Value 67 | 68 | func compareExchange( 69 | expected: Value, 70 | desired: Value, 71 | ordering: AtomicUpdateOrdering 72 | ) -> (exchanged: Bool, original: Value) 73 | 74 | func compareExchange( 75 | expected: Value, 76 | desired: Value, 77 | successOrdering: AtomicUpdateOrdering, 78 | failureOrdering: AtomicLoadOrdering 79 | ) -> (exchanged: Bool, original: Value) 80 | 81 | func weakCompareExchange( 82 | expected: Value, 83 | desired: Value, 84 | successOrdering: AtomicUpdateOrdering, 85 | failureOrdering: AtomicLoadOrdering 86 | ) -> (exchanged: Bool, original: Value) 87 | ``` 88 | 89 | Integer types come with additional atomic operations for incrementing or decrementing values and bitwise logical operations. `Bool` provides select additional boolean operations along the same vein. 90 | 91 | For an introduction to the APIs provided by this package, for now please see the [first version of SE-0282][SE-0282r0]. 92 | 93 | Note that when/if Swift gains support for non-copiable types, we expect to replace both `ManagedAtomic` and `UnsafeAtomic` with a single move-only atomic struct that combines the performance and versatility of `UnsafeAtomic` with the ease-of-use and memory safety of `ManagedAtomic`. 94 | 95 | The current version of the `Atomics` module does not implement APIs for tagged atomics (see [issue #1](https://github.com/apple/swift-atomics/issues/1)), although it does expose a `DoubleWord` type that can be used to implement them. (Atomic strong references are already implemented in terms of `DoubleWord`, although in their current form they do not expose any user-customizable bits.) 96 | 97 | 98 | ## Topics 99 | 100 | ### Atomic Container Types 101 | 102 | - ``ManagedAtomic`` 103 | - ``UnsafeAtomic`` 104 | - ``ManagedAtomicLazyReference`` 105 | - ``UnsafeAtomicLazyReference`` 106 | 107 | ### Memory Orderings 108 | 109 | - ``AtomicLoadOrdering`` 110 | - ``AtomicStoreOrdering`` 111 | - ``AtomicUpdateOrdering`` 112 | 113 | ### Atomic Value Protocols 114 | 115 | - ``AtomicValue`` 116 | - ``AtomicInteger`` 117 | - ``AtomicReference`` 118 | - ``AtomicOptionalWrappable`` 119 | 120 | ### Atomic Storage Representations 121 | 122 | - ``AtomicStorage`` 123 | - ``AtomicIntegerStorage`` 124 | - ``AtomicRawRepresentableStorage`` 125 | - ``AtomicReferenceStorage`` 126 | - ``AtomicOptionalReferenceStorage`` 127 | 128 | ### Fences 129 | 130 | - ``atomicMemoryFence(ordering:)`` 131 | 132 | ### Value Types 133 | 134 | - ``DoubleWord`` 135 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicInteger.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicInteger`` 2 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicIntegerStorage.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicIntegerStorage`` 2 | 3 | ## Topics 4 | 5 | ### Atomic Integer Operations 6 | 7 | - ``atomicLoadThenWrappingIncrement(by:at:ordering:)`` 8 | - ``atomicLoadThenWrappingDecrement(by:at:ordering:)`` 9 | - ``atomicLoadThenBitwiseOr(with:at:ordering:)`` 10 | - ``atomicLoadThenBitwiseAnd(with:at:ordering:)`` 11 | - ``atomicLoadThenBitwiseXor(with:at:ordering:)`` 12 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicLoadOrdering.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicLoadOrdering`` 2 | 3 | ## Topics 4 | 5 | ### Ordering Values 6 | 7 | - ``relaxed`` 8 | - ``acquiring`` 9 | - ``sequentiallyConsistent`` 10 | 11 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicOptionalReferenceStorage.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicOptionalReferenceStorage`` 2 | 3 | ## Topics 4 | 5 | ### Creating and Disposing Atomic Storage 6 | 7 | - ``init(_:)`` 8 | - ``dispose()`` 9 | 10 | ### Atomic Operations 11 | 12 | - ``atomicLoad(at:ordering:)`` 13 | - ``atomicStore(_:at:ordering:)`` 14 | - ``atomicExchange(_:at:ordering:)`` 15 | - ``atomicCompareExchange(expected:desired:at:ordering:)`` 16 | - ``atomicCompareExchange(expected:desired:at:successOrdering:failureOrdering:)`` 17 | - ``atomicWeakCompareExchange(expected:desired:at:successOrdering:failureOrdering:)`` 18 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicOptionalWrappable.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicOptionalWrappable`` 2 | 3 | ## Topics 4 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicRawRepresentableStorage.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicRawRepresentableStorage`` 2 | 3 | ## Topics 4 | 5 | ### Creating and Disposing Atomic Storage 6 | 7 | - ``init(_:)`` 8 | - ``dispose()`` 9 | 10 | ### Atomic Operations 11 | 12 | - ``atomicLoad(at:ordering:)`` 13 | - ``atomicStore(_:at:ordering:)`` 14 | - ``atomicExchange(_:at:ordering:)`` 15 | - ``atomicCompareExchange(expected:desired:at:ordering:)-1teq9`` 16 | - ``atomicCompareExchange(expected:desired:at:successOrdering:failureOrdering:)`` 17 | - ``atomicWeakCompareExchange(expected:desired:at:successOrdering:failureOrdering:)`` 18 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicReference.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicReferenceStorage`` 2 | 3 | ## Topics 4 | 5 | ### Creating and Disposing Atomic Storage 6 | 7 | - ``init(_:)`` 8 | - ``dispose()`` 9 | 10 | ### Atomic Operations 11 | 12 | - ``atomicLoad(at:ordering:)`` 13 | - ``atomicStore(_:at:ordering:)`` 14 | - ``atomicExchange(_:at:ordering:)`` 15 | - ``atomicCompareExchange(expected:desired:at:ordering:)`` 16 | - ``atomicCompareExchange(expected:desired:at:successOrdering:failureOrdering:)`` 17 | - ``atomicWeakCompareExchange(expected:desired:at:successOrdering:failureOrdering:)`` 18 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicReferenceStorage.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicReference`` 2 | 3 | ## Topics 4 | 5 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicStorage.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicStorage`` 2 | 3 | ## Topics 4 | 5 | ### Associated Types 6 | 7 | - ``Value`` 8 | 9 | ### Creating and Disposing Atomic Storage 10 | 11 | - ``init(_:)`` 12 | - ``dispose()`` 13 | 14 | ### Atomic Operations 15 | 16 | - ``atomicLoad(at:ordering:)`` 17 | - ``atomicStore(_:at:ordering:)`` 18 | - ``atomicExchange(_:at:ordering:)`` 19 | - ``atomicCompareExchange(expected:desired:at:ordering:)`` 20 | - ``atomicCompareExchange(expected:desired:at:successOrdering:failureOrdering:)-9t4wj`` 21 | - ``atomicWeakCompareExchange(expected:desired:at:ordering:)-55229`` 22 | - ``atomicWeakCompareExchange(expected:desired:at:successOrdering:failureOrdering:)`` 23 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicStoreOrdering.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicStoreOrdering`` 2 | 3 | ## Topics 4 | 5 | ### Ordering Values 6 | 7 | - ``relaxed`` 8 | - ``releasing`` 9 | - ``sequentiallyConsistent`` 10 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicUpdateOrdering.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicUpdateOrdering`` 2 | 3 | ## Topics 4 | 5 | ### Ordering Values 6 | 7 | - ``relaxed`` 8 | - ``acquiring`` 9 | - ``releasing`` 10 | - ``acquiringAndReleasing`` 11 | - ``sequentiallyConsistent`` 12 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/AtomicValue.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/AtomicValue`` 2 | 3 | ## Topics 4 | 5 | ### Associated Types 6 | 7 | - ``AtomicRepresentation`` 8 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/ManagedAtomic.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/ManagedAtomic`` 2 | 3 | ## Topics 4 | 5 | ### Initializers 6 | 7 | - ``init(_:)`` 8 | 9 | ### Atomic Operations 10 | 11 | - ``load(ordering:)`` 12 | - ``store(_:ordering:)`` 13 | - ``exchange(_:ordering:)`` 14 | - ``compareExchange(expected:desired:ordering:)`` 15 | - ``compareExchange(expected:desired:successOrdering:failureOrdering:)`` 16 | - ``weakCompareExchange(expected:desired:ordering:)`` 17 | - ``weakCompareExchange(expected:desired:successOrdering:failureOrdering:)`` 18 | 19 | ### Atomic Integer Operations 20 | 21 | - ``wrappingIncrement(by:ordering:)`` 22 | - ``wrappingDecrement(by:ordering:)`` 23 | - ``loadThenWrappingIncrement(by:ordering:)`` 24 | - ``loadThenWrappingDecrement(by:ordering:)`` 25 | - ``loadThenBitwiseOr(with:ordering:)`` 26 | - ``loadThenBitwiseAnd(with:ordering:)`` 27 | - ``loadThenBitwiseXor(with:ordering:)`` 28 | - ``wrappingIncrementThenLoad(by:ordering:)`` 29 | - ``wrappingDecrementThenLoad(by:ordering:)`` 30 | - ``bitwiseOrThenLoad(with:ordering:)`` 31 | - ``bitwiseAndThenLoad(with:ordering:)`` 32 | - ``bitwiseXorThenLoad(with:ordering:)`` 33 | 34 | ### Atomic Boolean Operations 35 | 36 | - ``logicalOrThenLoad(with:ordering:)`` 37 | - ``logicalAndThenLoad(with:ordering:)`` 38 | - ``logicalXorThenLoad(with:ordering:)`` 39 | - ``loadThenLogicalOr(with:ordering:)`` 40 | - ``loadThenLogicalAnd(with:ordering:)`` 41 | - ``loadThenLogicalXor(with:ordering:)`` 42 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/ManagedAtomicLazyReference.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/ManagedAtomicLazyReference`` 2 | 3 | ## Topics 4 | 5 | ### Related Types 6 | 7 | - ``Value`` 8 | 9 | ### Initializers 10 | 11 | - ``init()`` 12 | 13 | ### Atomic Operations 14 | 15 | - ``load()`` 16 | - ``storeIfNilThenLoad(_:)`` 17 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/UnsafeAtomic.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/UnsafeAtomic`` 2 | 3 | ## Topics 4 | 5 | ### Storage Representation 6 | 7 | - ``Storage`` 8 | 9 | ### Initializers 10 | 11 | - ``init(at:)`` 12 | 13 | ### Shorthand Methods for Dynamically Allocating Storage 14 | 15 | - ``create(_:)`` 16 | - ``destroy()`` 17 | 18 | ### Atomic Operations 19 | 20 | - ``load(ordering:)`` 21 | - ``store(_:ordering:)`` 22 | - ``exchange(_:ordering:)`` 23 | - ``compareExchange(expected:desired:ordering:)`` 24 | - ``compareExchange(expected:desired:successOrdering:failureOrdering:)`` 25 | - ``weakCompareExchange(expected:desired:ordering:)`` 26 | - ``weakCompareExchange(expected:desired:successOrdering:failureOrdering:)`` 27 | 28 | ### Atomic Integer Operations 29 | 30 | - ``wrappingIncrement(by:ordering:)`` 31 | - ``wrappingDecrement(by:ordering:)`` 32 | - ``loadThenWrappingIncrement(by:ordering:)`` 33 | - ``loadThenWrappingDecrement(by:ordering:)`` 34 | - ``loadThenBitwiseOr(with:ordering:)`` 35 | - ``loadThenBitwiseAnd(with:ordering:)`` 36 | - ``loadThenBitwiseXor(with:ordering:)`` 37 | - ``wrappingIncrementThenLoad(by:ordering:)`` 38 | - ``wrappingDecrementThenLoad(by:ordering:)`` 39 | - ``bitwiseOrThenLoad(with:ordering:)`` 40 | - ``bitwiseAndThenLoad(with:ordering:)`` 41 | - ``bitwiseXorThenLoad(with:ordering:)`` 42 | 43 | ### Atomic Boolean Operations 44 | 45 | - ``logicalOrThenLoad(with:ordering:)`` 46 | - ``logicalAndThenLoad(with:ordering:)`` 47 | - ``logicalXorThenLoad(with:ordering:)`` 48 | - ``loadThenLogicalOr(with:ordering:)`` 49 | - ``loadThenLogicalAnd(with:ordering:)`` 50 | - ``loadThenLogicalXor(with:ordering:)`` 51 | -------------------------------------------------------------------------------- /Sources/Atomics/Atomics.docc/Extensions/UnsafeAtomicLazyReference.md: -------------------------------------------------------------------------------- 1 | # ``Atomics/UnsafeAtomicLazyReference`` 2 | 3 | ## Topics 4 | 5 | ### Related Types 6 | 7 | - ``Value`` 8 | 9 | ### Initializers 10 | 11 | - ``init(at:)`` 12 | 13 | ### Shorthand Methods for Dynamically Allocating Storage 14 | 15 | - ``create()`` 16 | - ``destroy()`` 17 | 18 | ### Atomic Operations 19 | 20 | - ``load()`` 21 | - ``storeIfNilThenLoad(_:)`` 22 | -------------------------------------------------------------------------------- /Sources/Atomics/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | This source file is part of the Swift Atomics Open Source Project 3 | 4 | Copyright (c) 2021 - 2025 Apple Inc. and the Swift project authors 5 | Licensed under Apache License v2.0 with Runtime Library Exception 6 | 7 | See https://swift.org/LICENSE.txt for license information 8 | #]] 9 | 10 | add_library(Atomics 11 | "Types/UnsafeAtomicLazyReference.swift" 12 | "Types/DoubleWord.swift" 13 | "Types/ManagedAtomic.swift" 14 | "Types/ManagedAtomicLazyReference.swift" 15 | "Types/AtomicMemoryOrderings.swift" 16 | "Types/UnsafeAtomic.swift" 17 | "Types/autogenerated/IntegerOperations.swift" 18 | "Unmanaged extensions.swift" 19 | "Primitives/autogenerated/Primitives.native.swift" 20 | "Conformances/RawRepresentable.swift" 21 | "Conformances/OptionalRawRepresentable.swift" 22 | "Conformances/autogenerated/IntegerConformances.swift" 23 | "Conformances/autogenerated/PointerConformances.swift" 24 | "Conformances/autogenerated/AtomicBool.swift" 25 | "Protocols/AtomicInteger.swift" 26 | "Protocols/AtomicValue.swift" 27 | "Protocols/AtomicReference.swift" 28 | "Protocols/AtomicOptionalWrappable.swift" 29 | "Protocols/AtomicStorage.swift") 30 | 31 | set_target_properties(Atomics PROPERTIES 32 | INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) 33 | target_compile_options(Atomics PUBLIC 34 | "$<$:SHELL:${ATOMICS_SWIFT_FLAGS}>" 35 | "$<$:SHELL:${ATOMICS_C_FLAGS}>") 36 | if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") 37 | target_compile_options(Atomics PUBLIC 38 | "$<$:SHELL:-Xcc -mcx16>") 39 | endif() 40 | target_link_libraries(Atomics PUBLIC 41 | _AtomicsShims) 42 | 43 | _install_target(Atomics) 44 | set_property(GLOBAL APPEND PROPERTY SWIFT_ATOMICS_EXPORTS Atomics) 45 | -------------------------------------------------------------------------------- /Sources/Atomics/Conformances/AtomicBool.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2025 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb_utils import ( 15 | autogenerated_warning, boolOperations, lowerFirst, argLabel) 16 | }% 17 | ${autogenerated_warning()} 18 | 19 | import Builtin 20 | 21 | extension Bool { 22 | @_alwaysEmitIntoClient 23 | @_transparent 24 | internal init(_ builtin: Builtin.Int1) { 25 | self = unsafeBitCast(builtin, to: Bool.self) 26 | } 27 | } 28 | 29 | extension Bool: AtomicValue { 30 | @frozen 31 | public struct AtomicRepresentation { 32 | public typealias Value = Bool 33 | 34 | @usableFromInline 35 | internal typealias _Storage = _AtomicInt8Storage 36 | 37 | @usableFromInline 38 | internal var _storage: _Storage 39 | 40 | @_transparent @_alwaysEmitIntoClient 41 | public init(_ value: Bool) { 42 | _storage = value._atomicRepresentation 43 | } 44 | 45 | @_transparent @_alwaysEmitIntoClient 46 | public func dispose() -> Value { 47 | return _storage._decodeBool 48 | } 49 | } 50 | } 51 | 52 | extension Bool { 53 | @_transparent @_alwaysEmitIntoClient 54 | internal var _atomicRepresentation: _AtomicInt8Storage { 55 | let v: Int8 = (self ? 1 : 0) 56 | return .init(v._value) 57 | } 58 | } 59 | 60 | extension _AtomicInt8Storage { 61 | @_transparent @_alwaysEmitIntoClient 62 | internal var _decodeBool: Bool { 63 | (Int8(self._value) & 1) != 0 64 | } 65 | } 66 | 67 | extension UnsafeMutablePointer 68 | where Pointee == Bool.AtomicRepresentation { 69 | @_transparent @_alwaysEmitIntoClient 70 | @usableFromInline 71 | internal var _extract: UnsafeMutablePointer { 72 | // `Bool.AtomicRepresentation` is layout-compatible with 73 | // its only stored property. 74 | UnsafeMutableRawPointer(self).assumingMemoryBound(to: Pointee._Storage.self) 75 | } 76 | } 77 | 78 | extension Bool.AtomicRepresentation: AtomicStorage { 79 | @_semantics("atomics.requires_constant_orderings") 80 | @_transparent @_alwaysEmitIntoClient 81 | public static func atomicLoad( 82 | at pointer: UnsafeMutablePointer, 83 | ordering: AtomicLoadOrdering 84 | ) -> Bool { 85 | pointer._extract._atomicLoad(ordering: ordering)._decodeBool 86 | } 87 | 88 | @_semantics("atomics.requires_constant_orderings") 89 | @_transparent @_alwaysEmitIntoClient 90 | public static func atomicStore( 91 | _ desired: __owned Bool, 92 | at pointer: UnsafeMutablePointer, 93 | ordering: AtomicStoreOrdering 94 | ) { 95 | pointer._extract._atomicStore( 96 | desired._atomicRepresentation, ordering: ordering) 97 | } 98 | 99 | @_semantics("atomics.requires_constant_orderings") 100 | @_transparent @_alwaysEmitIntoClient 101 | public static func atomicExchange( 102 | _ desired: __owned Bool, 103 | at pointer: UnsafeMutablePointer, 104 | ordering: AtomicUpdateOrdering 105 | ) -> Bool { 106 | pointer._extract._atomicExchange( 107 | desired._atomicRepresentation, ordering: ordering 108 | )._decodeBool 109 | } 110 | 111 | @_semantics("atomics.requires_constant_orderings") 112 | @_transparent @_alwaysEmitIntoClient 113 | public static func atomicCompareExchange( 114 | expected: Bool, 115 | desired: __owned Bool, 116 | at pointer: UnsafeMutablePointer, 117 | ordering: AtomicUpdateOrdering 118 | ) -> (exchanged: Bool, original: Bool) { 119 | let r = pointer._extract._atomicCompareExchange( 120 | expected: expected._atomicRepresentation, 121 | desired: desired._atomicRepresentation, 122 | ordering: ordering) 123 | return (r.exchanged, r.original._decodeBool) 124 | } 125 | 126 | @_semantics("atomics.requires_constant_orderings") 127 | @_transparent @_alwaysEmitIntoClient 128 | public static func atomicCompareExchange( 129 | expected: Bool, 130 | desired: __owned Bool, 131 | at pointer: UnsafeMutablePointer, 132 | successOrdering: AtomicUpdateOrdering, 133 | failureOrdering: AtomicLoadOrdering 134 | ) -> (exchanged: Bool, original: Bool) { 135 | let r = pointer._extract._atomicCompareExchange( 136 | expected: expected._atomicRepresentation, 137 | desired: desired._atomicRepresentation, 138 | successOrdering: successOrdering, 139 | failureOrdering: failureOrdering) 140 | return (r.exchanged, r.original._decodeBool) 141 | } 142 | 143 | @_semantics("atomics.requires_constant_orderings") 144 | @_transparent @_alwaysEmitIntoClient 145 | public static func atomicWeakCompareExchange( 146 | expected: Bool, 147 | desired: __owned Bool, 148 | at pointer: UnsafeMutablePointer, 149 | successOrdering: AtomicUpdateOrdering, 150 | failureOrdering: AtomicLoadOrdering 151 | ) -> (exchanged: Bool, original: Bool) { 152 | let r = pointer._extract._atomicWeakCompareExchange( 153 | expected: expected._atomicRepresentation, 154 | desired: desired._atomicRepresentation, 155 | successOrdering: successOrdering, 156 | failureOrdering: failureOrdering) 157 | return (r.exchanged, r.original._decodeBool) 158 | } 159 | } 160 | 161 | 162 | // MARK: - Additional operations 163 | 164 | extension Bool.AtomicRepresentation { 165 | % for (name, iname, op, label, doc) in boolOperations: 166 | /// Perform an atomic ${doc} operation on the value referenced by 167 | /// `pointer` and return the original value, applying the specified memory 168 | /// ordering. 169 | /// 170 | /// - Parameter operand: A boolean value. 171 | /// - Parameter pointer: A memory location previously initialized with a value 172 | /// returned by `prepareAtomicRepresentation(for:)`. 173 | /// - Parameter ordering: The memory ordering to apply on this operation. 174 | /// - Returns: The original value before the operation. 175 | @_semantics("atomics.requires_constant_orderings") 176 | @_transparent @_alwaysEmitIntoClient 177 | public static func atomicLoadThen${name}( 178 | ${label} operand: Value, 179 | at pointer: UnsafeMutablePointer, 180 | ordering: AtomicUpdateOrdering 181 | ) -> Value { 182 | pointer._extract._atomicLoadThen${iname}( 183 | ${argLabel(label)}operand._atomicRepresentation, ordering: ordering 184 | )._decodeBool 185 | } 186 | % end 187 | } 188 | 189 | % for construct in ["UnsafeAtomic", "ManagedAtomic"]: 190 | extension ${construct} where Value == Bool { 191 | % for (name, iname, op, label, doc) in boolOperations: 192 | /// Perform an atomic ${doc} operation and return the original value, applying 193 | /// the specified memory ordering. 194 | /// 195 | /// - Parameter operand: A boolean value. 196 | /// - Parameter ordering: The memory ordering to apply on this operation. 197 | /// - Returns: The original value before the operation. 198 | @_semantics("atomics.requires_constant_orderings") 199 | @_transparent @_alwaysEmitIntoClient 200 | public func loadThen${name}( 201 | ${label} operand: Value, 202 | ordering: AtomicUpdateOrdering 203 | ) -> Value { 204 | Value.AtomicRepresentation.atomicLoadThen${name}( 205 | ${argLabel(label)}operand, 206 | at: _ptr, 207 | ordering: ordering) 208 | } 209 | % end 210 | } 211 | 212 | extension ${construct} where Value == Bool { 213 | % for (name, iname, op, label, doc) in boolOperations: 214 | /// Perform an atomic ${doc} operation and return the original value, applying 215 | /// the specified memory ordering. 216 | /// 217 | /// - Parameter operand: A boolean value. 218 | /// - Parameter ordering: The memory ordering to apply on this operation. 219 | /// - Returns: The original value before the operation. 220 | @_semantics("atomics.requires_constant_orderings") 221 | @_transparent @_alwaysEmitIntoClient 222 | public func ${lowerFirst(name)}ThenLoad( 223 | ${label} operand: Value, 224 | ordering: AtomicUpdateOrdering 225 | ) -> Value { 226 | let original = Value.AtomicRepresentation.atomicLoadThen${name}( 227 | ${argLabel(label)}operand, 228 | at: _ptr, 229 | ordering: ordering) 230 | return original ${op} operand 231 | } 232 | 233 | % end 234 | } 235 | % end 236 | -------------------------------------------------------------------------------- /Sources/Atomics/Conformances/IntegerConformances.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2025 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | %{ 13 | from gyb_utils import * 14 | 15 | integerTypes = [ 16 | # Swift Storage ShimName 17 | ("Int8", "_AtomicInt8Storage", "Int8"), 18 | ("Int16", "_AtomicInt16Storage", "Int16"), 19 | ("Int32", "_AtomicInt32Storage", "Int32"), 20 | ("Int64", "_AtomicInt64Storage", "Int64"), 21 | ("UInt8", "_AtomicInt8Storage", "Int8"), 22 | ("UInt16", "_AtomicInt16Storage", "Int16"), 23 | ("UInt32", "_AtomicInt32Storage", "Int32"), 24 | ("UInt64", "_AtomicInt64Storage", "Int64"), 25 | ("Int", "_AtomicIntStorage", "Int"), 26 | ("UInt", "_AtomicIntStorage", "Int"), 27 | ("DoubleWord", "_AtomicDoubleWordStorage", "DoubleWord"), 28 | ] 29 | }% 30 | ${autogenerated_warning()} 31 | 32 | % for (swiftType, storageType, shimType) in integerTypes: 33 | 34 | extension ${swiftType}: AtomicValue { 35 | @frozen 36 | public struct AtomicRepresentation { 37 | public typealias Value = ${swiftType} 38 | 39 | @usableFromInline 40 | internal typealias _Storage = ${storageType} 41 | 42 | @usableFromInline 43 | internal var _storage: _Storage 44 | 45 | @_transparent @_alwaysEmitIntoClient 46 | public init(_ value: Value) { 47 | _storage = Self._encode(value) 48 | } 49 | 50 | @_transparent @_alwaysEmitIntoClient 51 | public func dispose() -> Value { 52 | return Self._decode(_storage) 53 | } 54 | } 55 | } 56 | 57 | extension UnsafeMutablePointer 58 | where Pointee == ${swiftType}.AtomicRepresentation { 59 | @_transparent @_alwaysEmitIntoClient 60 | internal var _extract: UnsafeMutablePointer { 61 | // `${swiftType}.AtomicRepresentation` is layout-compatible with 62 | // its only stored property. 63 | UnsafeMutableRawPointer(self).assumingMemoryBound(to: Pointee._Storage.self) 64 | } 65 | } 66 | 67 | extension ${swiftType}.AtomicRepresentation { 68 | @_transparent @_alwaysEmitIntoClient 69 | static func _decode(_ storage: _Storage) -> Value { 70 | return Value(storage._value) 71 | } 72 | 73 | @_transparent @_alwaysEmitIntoClient 74 | static func _encode(_ value: Value) -> _Storage { 75 | return _Storage(value._value) 76 | } 77 | } 78 | 79 | extension ${swiftType}.AtomicRepresentation: AtomicStorage { 80 | @_semantics("atomics.requires_constant_orderings") 81 | @_transparent @_alwaysEmitIntoClient 82 | public static func atomicLoad( 83 | at pointer: UnsafeMutablePointer, 84 | ordering: AtomicLoadOrdering 85 | ) -> ${swiftType} { 86 | let r = pointer._extract._atomicLoad(ordering: ordering) 87 | return Self._decode(r) 88 | } 89 | 90 | @_semantics("atomics.requires_constant_orderings") 91 | @_transparent @_alwaysEmitIntoClient 92 | public static func atomicStore( 93 | _ desired: ${swiftType}, 94 | at pointer: UnsafeMutablePointer, 95 | ordering: AtomicStoreOrdering 96 | ) { 97 | pointer._extract._atomicStore( 98 | Self._encode(desired), 99 | ordering: ordering) 100 | } 101 | 102 | @_semantics("atomics.requires_constant_orderings") 103 | @_transparent @_alwaysEmitIntoClient 104 | public static func atomicExchange( 105 | _ desired: ${swiftType}, 106 | at pointer: UnsafeMutablePointer, 107 | ordering: AtomicUpdateOrdering 108 | ) -> ${swiftType} { 109 | let r = pointer._extract._atomicExchange( 110 | Self._encode(desired), 111 | ordering: ordering) 112 | return Self._decode(r) 113 | } 114 | 115 | @_semantics("atomics.requires_constant_orderings") 116 | @_transparent @_alwaysEmitIntoClient 117 | public static func atomicCompareExchange( 118 | expected: ${swiftType}, 119 | desired: ${swiftType}, 120 | at pointer: UnsafeMutablePointer, 121 | ordering: AtomicUpdateOrdering 122 | ) -> (exchanged: Bool, original: ${swiftType}) { 123 | let r = pointer._extract._atomicCompareExchange( 124 | expected: Self._encode(expected), 125 | desired: Self._encode(desired), 126 | ordering: ordering) 127 | return (r.exchanged, Self._decode(r.original)) 128 | } 129 | 130 | @_semantics("atomics.requires_constant_orderings") 131 | @_transparent @_alwaysEmitIntoClient 132 | public static func atomicCompareExchange( 133 | expected: ${swiftType}, 134 | desired: ${swiftType}, 135 | at pointer: UnsafeMutablePointer, 136 | successOrdering: AtomicUpdateOrdering, 137 | failureOrdering: AtomicLoadOrdering 138 | ) -> (exchanged: Bool, original: ${swiftType}) { 139 | let r = pointer._extract._atomicCompareExchange( 140 | expected: Self._encode(expected), 141 | desired: Self._encode(desired), 142 | successOrdering: successOrdering, 143 | failureOrdering: failureOrdering) 144 | return (r.exchanged, Self._decode(r.original)) 145 | } 146 | 147 | @_semantics("atomics.requires_constant_orderings") 148 | @_transparent @_alwaysEmitIntoClient 149 | public static func atomicWeakCompareExchange( 150 | expected: ${swiftType}, 151 | desired: ${swiftType}, 152 | at pointer: UnsafeMutablePointer, 153 | successOrdering: AtomicUpdateOrdering, 154 | failureOrdering: AtomicLoadOrdering 155 | ) -> (exchanged: Bool, original: ${swiftType}) { 156 | let r = pointer._extract._atomicWeakCompareExchange( 157 | expected: Self._encode(expected), 158 | desired: Self._encode(desired), 159 | successOrdering: successOrdering, 160 | failureOrdering: failureOrdering) 161 | return (r.exchanged, Self._decode(r.original)) 162 | } 163 | } 164 | 165 | % if swiftType != "DoubleWord": 166 | extension ${swiftType}: AtomicInteger {} 167 | 168 | extension ${swiftType}.AtomicRepresentation: AtomicIntegerStorage { 169 | % for (name, cname, op, label, doc) in integerOperations: 170 | % defaultValue = " = 1" if label != "" else "" 171 | @_semantics("atomics.requires_constant_orderings") 172 | @_transparent @_alwaysEmitIntoClient 173 | @discardableResult 174 | public static func atomicLoadThen${name}( 175 | ${label} operand: ${swiftType}${defaultValue}, 176 | at pointer: UnsafeMutablePointer, 177 | ordering: AtomicUpdateOrdering 178 | ) -> ${swiftType} { 179 | let r = pointer._extract._atomicLoadThen${name}( 180 | ${argLabel(label)}Self._encode(operand), ordering: ordering) 181 | return Self._decode(r) 182 | } 183 | 184 | % end 185 | } 186 | 187 | % end 188 | 189 | % end 190 | % end 191 | -------------------------------------------------------------------------------- /Sources/Atomics/Conformances/OptionalRawRepresentable.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2021 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | extension RawRepresentable 14 | where 15 | Self: AtomicOptionalWrappable, 16 | RawValue: AtomicOptionalWrappable, 17 | RawValue.AtomicOptionalRepresentation.Value == RawValue? 18 | { 19 | public typealias AtomicOptionalRepresentation = 20 | AtomicOptionalRawRepresentableStorage 21 | } 22 | 23 | /// A default atomic storage representation for a `RawRepresentable` type 24 | /// whose `RawValue` conforms to `AtomicOptionalWrappable`. 25 | @frozen 26 | public struct AtomicOptionalRawRepresentableStorage: AtomicStorage 27 | where 28 | Wrapped: RawRepresentable, 29 | Wrapped.RawValue: AtomicOptionalWrappable, 30 | Wrapped.RawValue.AtomicOptionalRepresentation.Value == Wrapped.RawValue? 31 | { 32 | 33 | public typealias Value = Optional 34 | 35 | @usableFromInline 36 | internal typealias _Storage = Wrapped.RawValue.AtomicOptionalRepresentation 37 | 38 | @usableFromInline 39 | internal var _storage: _Storage 40 | 41 | @_transparent @_alwaysEmitIntoClient 42 | public init(_ value: __owned Optional) { 43 | self._storage = _Storage(value?.rawValue) 44 | } 45 | 46 | @_transparent @_alwaysEmitIntoClient 47 | __consuming public func dispose() -> Optional { 48 | _storage.dispose().flatMap(Wrapped.init(rawValue:)) 49 | } 50 | 51 | @usableFromInline 52 | @_transparent @_alwaysEmitIntoClient 53 | static func _extract( 54 | _ ptr: UnsafeMutablePointer 55 | ) -> UnsafeMutablePointer<_Storage> { 56 | // `Self` is layout-compatible with its only stored property. 57 | return UnsafeMutableRawPointer(ptr).assumingMemoryBound(to: _Storage.self) 58 | } 59 | 60 | @_semantics("atomics.requires_constant_orderings") 61 | @_transparent @_alwaysEmitIntoClient 62 | public static func atomicLoad( 63 | at pointer: UnsafeMutablePointer, 64 | ordering: AtomicLoadOrdering 65 | ) -> Optional { 66 | let ro = _Storage.atomicLoad( 67 | at: _extract(pointer), ordering: ordering) 68 | return ro.flatMap(Wrapped.init(rawValue:)) 69 | } 70 | 71 | @_semantics("atomics.requires_constant_orderings") 72 | @_transparent @_alwaysEmitIntoClient 73 | public static func atomicStore( 74 | _ desired: __owned Optional, 75 | at pointer: UnsafeMutablePointer, 76 | ordering: AtomicStoreOrdering 77 | ) { 78 | _Storage.atomicStore( 79 | desired?.rawValue, at: _extract(pointer), ordering: ordering) 80 | } 81 | 82 | @_semantics("atomics.requires_constant_orderings") 83 | @_transparent @_alwaysEmitIntoClient 84 | public static func atomicExchange( 85 | _ desired: __owned Optional, 86 | at pointer: UnsafeMutablePointer, 87 | ordering: AtomicUpdateOrdering 88 | ) -> Optional { 89 | let ro = _Storage.atomicExchange( 90 | desired?.rawValue, at: _extract(pointer), ordering: ordering) 91 | return ro.flatMap(Wrapped.init(rawValue:)) 92 | } 93 | 94 | @_semantics("atomics.requires_constant_orderings") 95 | @_transparent @_alwaysEmitIntoClient 96 | public static func atomicCompareExchange( 97 | expected: Optional, 98 | desired: __owned Optional, 99 | at pointer: UnsafeMutablePointer, 100 | ordering: AtomicUpdateOrdering 101 | ) -> (exchanged: Bool, original: Optional) { 102 | let ro = _Storage.atomicCompareExchange( 103 | expected: expected?.rawValue, 104 | desired: desired?.rawValue, 105 | at: _extract(pointer), 106 | ordering: ordering) 107 | return (ro.exchanged, ro.original.flatMap(Wrapped.init(rawValue:))) 108 | } 109 | 110 | @_semantics("atomics.requires_constant_orderings") 111 | @_transparent @_alwaysEmitIntoClient 112 | public static func atomicCompareExchange( 113 | expected: Optional, 114 | desired: __owned Optional, 115 | at pointer: UnsafeMutablePointer, 116 | successOrdering: AtomicUpdateOrdering, 117 | failureOrdering: AtomicLoadOrdering 118 | ) -> (exchanged: Bool, original: Optional) { 119 | let ro = _Storage.atomicCompareExchange( 120 | expected: expected?.rawValue, 121 | desired: desired?.rawValue, 122 | at: _extract(pointer), 123 | successOrdering: successOrdering, 124 | failureOrdering: failureOrdering) 125 | return (ro.exchanged, ro.original.flatMap(Wrapped.init(rawValue:))) 126 | } 127 | 128 | @_semantics("atomics.requires_constant_orderings") 129 | @_transparent @_alwaysEmitIntoClient 130 | public static func atomicWeakCompareExchange( 131 | expected: Optional, 132 | desired: __owned Optional, 133 | at pointer: UnsafeMutablePointer, 134 | successOrdering: AtomicUpdateOrdering, 135 | failureOrdering: AtomicLoadOrdering 136 | ) -> (exchanged: Bool, original: Optional) { 137 | let ro = _Storage.atomicWeakCompareExchange( 138 | expected: expected?.rawValue, 139 | desired: desired?.rawValue, 140 | at: _extract(pointer), 141 | successOrdering: successOrdering, 142 | failureOrdering: failureOrdering) 143 | return (ro.exchanged, ro.original.flatMap(Wrapped.init(rawValue:))) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Sources/Atomics/Conformances/PointerConformances.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2025 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb_utils import autogenerated_warning 15 | 16 | atomicTypes = [ 17 | "UnsafeRawPointer", 18 | "UnsafeMutableRawPointer", 19 | "UnsafePointer", 20 | "UnsafeMutablePointer", 21 | "Unmanaged", 22 | ] 23 | }% 24 | ${autogenerated_warning()} 25 | 26 | % for swiftType in atomicTypes: 27 | extension ${swiftType}: AtomicValue { 28 | @frozen 29 | public struct AtomicRepresentation { 30 | public typealias Value = ${swiftType} 31 | 32 | @usableFromInline 33 | internal typealias _Storage = _AtomicIntStorage 34 | 35 | @usableFromInline 36 | internal let _storage: _Storage 37 | 38 | @_transparent @_alwaysEmitIntoClient 39 | public init(_ value: Value) { 40 | _storage = Self._encode(value) 41 | } 42 | 43 | @_transparent @_alwaysEmitIntoClient 44 | public func dispose() -> Value { 45 | return Self._decode(_storage) 46 | } 47 | } 48 | } 49 | 50 | extension ${swiftType}.AtomicRepresentation { 51 | @_transparent @_alwaysEmitIntoClient 52 | @usableFromInline 53 | internal static func _extract( 54 | _ ptr: UnsafeMutablePointer 55 | ) -> UnsafeMutablePointer<_Storage> { 56 | // `Self` is layout-compatible with its only stored property. 57 | return UnsafeMutableRawPointer(ptr) 58 | .assumingMemoryBound(to: _Storage.self) 59 | } 60 | } 61 | 62 | extension ${swiftType}.AtomicRepresentation { 63 | @_transparent @_alwaysEmitIntoClient 64 | internal static func _decode(_ storage: _Storage) -> Value { 65 | let bits = Int(storage._value) 66 | % if swiftType == "Unmanaged": 67 | return Unmanaged.fromOpaque(UnsafeRawPointer(bitPattern: bits)!) 68 | % else: 69 | return ${swiftType}(bitPattern: bits)! 70 | % end 71 | } 72 | 73 | @_transparent @_alwaysEmitIntoClient 74 | internal static func _encode(_ value: Value) -> _Storage { 75 | % if swiftType == "Unmanaged": 76 | let bits = Int(bitPattern: value.toOpaque()) 77 | % else: 78 | let bits = Int(bitPattern: value) 79 | % end 80 | return _Storage(bits._value) 81 | } 82 | } 83 | 84 | extension ${swiftType}.AtomicRepresentation: AtomicStorage { 85 | @_semantics("atomics.requires_constant_orderings") 86 | @_transparent @_alwaysEmitIntoClient 87 | public static func atomicLoad( 88 | at pointer: UnsafeMutablePointer, 89 | ordering: AtomicLoadOrdering 90 | ) -> Value { 91 | _decode(_extract(pointer)._atomicLoad(ordering: ordering)) 92 | } 93 | 94 | @_semantics("atomics.requires_constant_orderings") 95 | @_transparent @_alwaysEmitIntoClient 96 | public static func atomicStore( 97 | _ desired: Value, 98 | at pointer: UnsafeMutablePointer, 99 | ordering: AtomicStoreOrdering 100 | ) { 101 | _extract(pointer)._atomicStore(_encode(desired), ordering: ordering) 102 | } 103 | 104 | @_semantics("atomics.requires_constant_orderings") 105 | @_transparent @_alwaysEmitIntoClient 106 | public static func atomicExchange( 107 | _ desired: Value, 108 | at pointer: UnsafeMutablePointer, 109 | ordering: AtomicUpdateOrdering 110 | ) -> Value { 111 | let v = _extract(pointer)._atomicExchange( 112 | _encode(desired), ordering: ordering) 113 | return _decode(v) 114 | } 115 | 116 | @_semantics("atomics.requires_constant_orderings") 117 | @_transparent @_alwaysEmitIntoClient 118 | public static func atomicCompareExchange( 119 | expected: Value, 120 | desired: Value, 121 | at pointer: UnsafeMutablePointer, 122 | ordering: AtomicUpdateOrdering 123 | ) -> (exchanged: Bool, original: Value) { 124 | let (exchanged, original) = _extract(pointer)._atomicCompareExchange( 125 | expected: _encode(expected), 126 | desired: _encode(desired), 127 | ordering: ordering) 128 | return (exchanged, _decode(original)) 129 | } 130 | 131 | @_semantics("atomics.requires_constant_orderings") 132 | @_transparent @_alwaysEmitIntoClient 133 | public static func atomicCompareExchange( 134 | expected: Value, 135 | desired: Value, 136 | at pointer: UnsafeMutablePointer, 137 | successOrdering: AtomicUpdateOrdering, 138 | failureOrdering: AtomicLoadOrdering 139 | ) -> (exchanged: Bool, original: Value) { 140 | let (exchanged, original) = _extract(pointer)._atomicCompareExchange( 141 | expected: _encode(expected), 142 | desired: _encode(desired), 143 | successOrdering: successOrdering, 144 | failureOrdering: failureOrdering) 145 | return (exchanged, _decode(original)) 146 | } 147 | 148 | @_semantics("atomics.requires_constant_orderings") 149 | @_transparent @_alwaysEmitIntoClient 150 | public static func atomicWeakCompareExchange( 151 | expected: Value, 152 | desired: Value, 153 | at pointer: UnsafeMutablePointer, 154 | successOrdering: AtomicUpdateOrdering, 155 | failureOrdering: AtomicLoadOrdering 156 | ) -> (exchanged: Bool, original: Value) { 157 | let (exchanged, original) = _extract(pointer)._atomicWeakCompareExchange( 158 | expected: _encode(expected), 159 | desired: _encode(desired), 160 | successOrdering: successOrdering, 161 | failureOrdering: failureOrdering) 162 | return (exchanged, _decode(original)) 163 | } 164 | } 165 | % end 166 | 167 | 168 | % for swiftType in atomicTypes: 169 | extension ${swiftType}: AtomicOptionalWrappable { 170 | @frozen 171 | public struct AtomicOptionalRepresentation { 172 | public typealias Value = ${swiftType}? 173 | 174 | @usableFromInline 175 | internal typealias _Storage = _AtomicIntStorage 176 | 177 | @usableFromInline 178 | internal let _storage: _Storage 179 | 180 | @inline(__always) @_alwaysEmitIntoClient 181 | public init(_ value: Value) { 182 | _storage = Self._encode(value) 183 | } 184 | 185 | @inline(__always) @_alwaysEmitIntoClient 186 | public func dispose() -> Value { 187 | Self._decode(_storage) 188 | } 189 | } 190 | } 191 | 192 | extension ${swiftType}.AtomicOptionalRepresentation { 193 | @_transparent @_alwaysEmitIntoClient 194 | @usableFromInline 195 | internal static func _extract( 196 | _ ptr: UnsafeMutablePointer 197 | ) -> UnsafeMutablePointer<_Storage> { 198 | // `Self` is layout-compatible with its only stored property. 199 | return UnsafeMutableRawPointer(ptr) 200 | .assumingMemoryBound(to: _Storage.self) 201 | } 202 | } 203 | 204 | extension ${swiftType}.AtomicOptionalRepresentation { 205 | @_transparent @_alwaysEmitIntoClient 206 | internal static func _decode(_ storage: _Storage) -> Value { 207 | let bits = Int(storage._value) 208 | % if swiftType == "Unmanaged": 209 | guard let opaque = UnsafeRawPointer(bitPattern: bits) else { 210 | return nil 211 | } 212 | return Unmanaged.fromOpaque(opaque) 213 | % else: 214 | return ${swiftType}(bitPattern: bits) 215 | % end 216 | } 217 | 218 | @_transparent @_alwaysEmitIntoClient 219 | internal static func _encode(_ value: Value) -> _Storage { 220 | % if swiftType == "Unmanaged": 221 | let bits = value.map { Int(bitPattern: $0.toOpaque())} ?? 0 222 | % else: 223 | let bits = value.map { Int(bitPattern: $0) } ?? 0 224 | % end 225 | return _Storage(bits._value) 226 | } 227 | } 228 | 229 | extension ${swiftType}.AtomicOptionalRepresentation: AtomicStorage { 230 | @_semantics("atomics.requires_constant_orderings") 231 | @_transparent @_alwaysEmitIntoClient 232 | public static func atomicLoad( 233 | at pointer: UnsafeMutablePointer, 234 | ordering: AtomicLoadOrdering 235 | ) -> Value { 236 | _decode(_extract(pointer)._atomicLoad(ordering: ordering)) 237 | } 238 | 239 | @_semantics("atomics.requires_constant_orderings") 240 | @_transparent @_alwaysEmitIntoClient 241 | public static func atomicStore( 242 | _ desired: Value, 243 | at pointer: UnsafeMutablePointer, 244 | ordering: AtomicStoreOrdering 245 | ) { 246 | _extract(pointer)._atomicStore(_encode(desired), ordering: ordering) 247 | } 248 | 249 | @_semantics("atomics.requires_constant_orderings") 250 | @_transparent @_alwaysEmitIntoClient 251 | public static func atomicExchange( 252 | _ desired: Value, 253 | at pointer: UnsafeMutablePointer, 254 | ordering: AtomicUpdateOrdering 255 | ) -> Value { 256 | _decode(_extract(pointer)._atomicExchange(_encode(desired), ordering: ordering)) 257 | } 258 | 259 | @_semantics("atomics.requires_constant_orderings") 260 | @_transparent @_alwaysEmitIntoClient 261 | public static func atomicCompareExchange( 262 | expected: Value, 263 | desired: Value, 264 | at pointer: UnsafeMutablePointer, 265 | ordering: AtomicUpdateOrdering 266 | ) -> (exchanged: Bool, original: Value) { 267 | let (exchanged, original) = _extract(pointer)._atomicCompareExchange( 268 | expected: _encode(expected), 269 | desired: _encode(desired), 270 | ordering: ordering) 271 | return (exchanged, _decode(original)) 272 | } 273 | 274 | @_semantics("atomics.requires_constant_orderings") 275 | @_transparent @_alwaysEmitIntoClient 276 | public static func atomicCompareExchange( 277 | expected: Value, 278 | desired: Value, 279 | at pointer: UnsafeMutablePointer, 280 | successOrdering: AtomicUpdateOrdering, 281 | failureOrdering: AtomicLoadOrdering 282 | ) -> (exchanged: Bool, original: Value) { 283 | let (exchanged, original) = _extract(pointer)._atomicCompareExchange( 284 | expected: _encode(expected), 285 | desired: _encode(desired), 286 | successOrdering: successOrdering, 287 | failureOrdering: failureOrdering) 288 | return (exchanged, _decode(original)) 289 | } 290 | 291 | @_semantics("atomics.requires_constant_orderings") 292 | @_transparent @_alwaysEmitIntoClient 293 | public static func atomicWeakCompareExchange( 294 | expected: Value, 295 | desired: Value, 296 | at pointer: UnsafeMutablePointer, 297 | successOrdering: AtomicUpdateOrdering, 298 | failureOrdering: AtomicLoadOrdering 299 | ) -> (exchanged: Bool, original: Value) { 300 | let (exchanged, original) = _extract(pointer)._atomicWeakCompareExchange( 301 | expected: _encode(expected), 302 | desired: _encode(desired), 303 | successOrdering: successOrdering, 304 | failureOrdering: failureOrdering) 305 | return (exchanged, _decode(original)) 306 | } 307 | } 308 | % end 309 | -------------------------------------------------------------------------------- /Sources/Atomics/Conformances/RawRepresentable.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | extension RawRepresentable 14 | where 15 | Self: AtomicValue, 16 | RawValue: AtomicValue, 17 | RawValue.AtomicRepresentation.Value == RawValue 18 | { 19 | public typealias AtomicRepresentation = AtomicRawRepresentableStorage 20 | } 21 | 22 | /// The default atomic storage representation for an atomic `RawRepresentable` 23 | /// type whose `RawValue` conforms to `AtomicValue`. 24 | @frozen 25 | public struct AtomicRawRepresentableStorage: AtomicStorage 26 | where 27 | Value: RawRepresentable, 28 | Value.RawValue: AtomicValue, 29 | Value.RawValue.AtomicRepresentation.Value == Value.RawValue 30 | { 31 | @usableFromInline 32 | internal typealias _Storage = Value.RawValue.AtomicRepresentation 33 | 34 | @usableFromInline 35 | internal var _storage: _Storage 36 | 37 | @_transparent @_alwaysEmitIntoClient 38 | public init(_ value: __owned Value) { 39 | _storage = _Storage(value.rawValue) 40 | } 41 | 42 | @_transparent @_alwaysEmitIntoClient 43 | public func dispose() -> Value { 44 | Value(rawValue: _storage.dispose())! 45 | } 46 | 47 | @_transparent @_alwaysEmitIntoClient 48 | internal static func _extract( 49 | _ ptr: UnsafeMutablePointer 50 | ) -> UnsafeMutablePointer<_Storage> { 51 | // `Self` is layout-compatible with its only stored property. 52 | UnsafeMutableRawPointer(ptr).assumingMemoryBound(to: _Storage.self) 53 | } 54 | 55 | @_semantics("atomics.requires_constant_orderings") 56 | @_transparent @_alwaysEmitIntoClient 57 | public static func atomicLoad( 58 | at pointer: UnsafeMutablePointer, 59 | ordering: AtomicLoadOrdering 60 | ) -> Value { 61 | let raw = _Storage.atomicLoad(at: _extract(pointer), ordering: ordering) 62 | return Value(rawValue: raw)! 63 | } 64 | 65 | @_semantics("atomics.requires_constant_orderings") 66 | @_transparent @_alwaysEmitIntoClient 67 | public static func atomicStore( 68 | _ desired: Value, 69 | at pointer: UnsafeMutablePointer, 70 | ordering: AtomicStoreOrdering 71 | ) { 72 | _Storage.atomicStore( 73 | desired.rawValue, at: _extract(pointer), ordering: ordering) 74 | } 75 | 76 | @_semantics("atomics.requires_constant_orderings") 77 | @_transparent @_alwaysEmitIntoClient 78 | public static func atomicExchange( 79 | _ desired: Value, 80 | at pointer: UnsafeMutablePointer, 81 | ordering: AtomicUpdateOrdering 82 | ) -> Value { 83 | let raw = _Storage.atomicExchange( 84 | desired.rawValue, at: _extract(pointer), ordering: ordering) 85 | return Value(rawValue: raw)! 86 | } 87 | 88 | @_semantics("atomics.requires_constant_orderings") 89 | @_transparent @_alwaysEmitIntoClient 90 | public static func atomicCompareExchange( 91 | expected: Value, 92 | desired: Value, 93 | at pointer: UnsafeMutablePointer, 94 | ordering: AtomicUpdateOrdering 95 | ) -> (exchanged: Bool, original: Value) { 96 | let raw = _Storage.atomicCompareExchange( 97 | expected: expected.rawValue, 98 | desired: desired.rawValue, 99 | at: _extract(pointer), 100 | ordering: ordering) 101 | return (raw.exchanged, Value(rawValue: raw.original)!) 102 | } 103 | 104 | @_semantics("atomics.requires_constant_orderings") 105 | @_transparent @_alwaysEmitIntoClient 106 | public static func atomicCompareExchange( 107 | expected: Value, 108 | desired: Value, 109 | at pointer: UnsafeMutablePointer, 110 | successOrdering: AtomicUpdateOrdering, 111 | failureOrdering: AtomicLoadOrdering 112 | ) -> (exchanged: Bool, original: Value) { 113 | let raw = _Storage.atomicCompareExchange( 114 | expected: expected.rawValue, 115 | desired: desired.rawValue, 116 | at: _extract(pointer), 117 | successOrdering: successOrdering, 118 | failureOrdering: failureOrdering) 119 | return (raw.exchanged, Value(rawValue: raw.original)!) 120 | } 121 | 122 | @_semantics("atomics.requires_constant_orderings") 123 | @_transparent @_alwaysEmitIntoClient 124 | public static func atomicWeakCompareExchange( 125 | expected: Value, 126 | desired: Value, 127 | at pointer: UnsafeMutablePointer, 128 | successOrdering: AtomicUpdateOrdering, 129 | failureOrdering: AtomicLoadOrdering 130 | ) -> (exchanged: Bool, original: Value) { 131 | let raw = _Storage.atomicWeakCompareExchange( 132 | expected: expected.rawValue, 133 | desired: desired.rawValue, 134 | at: _extract(pointer), 135 | successOrdering: successOrdering, 136 | failureOrdering: failureOrdering) 137 | return (raw.exchanged, Value(rawValue: raw.original)!) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /Sources/Atomics/Primitives/Primitives.native.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift.org open source project 4 | // 5 | // Copyright (c) 2023 - 2025 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb_utils import * 15 | }% 16 | ${autogenerated_warning()} 17 | 18 | import Builtin 19 | 20 | @_alwaysEmitIntoClient 21 | @_transparent 22 | internal func _atomicMemoryFence( 23 | ordering: AtomicUpdateOrdering 24 | ) { 25 | switch ordering { 26 | case .relaxed: 27 | break 28 | % for (enumOrder, apiOrder, docOrder, llvmOrder, _) in updateOrderings: 29 | % if enumOrder != "relaxed": 30 | case .${enumOrder}: 31 | Builtin.fence_${llvmOrder}() 32 | % end 33 | % end 34 | default: 35 | fatalError("Unsupported ordering") 36 | } 37 | } 38 | % for (swiftType, builtinType, alignment) in nativePrimitives: 39 | 40 | % if builtinType == "Int128": 41 | #if _pointerBitWidth(_64) 42 | % end 43 | @usableFromInline 44 | @frozen 45 | @_alignment(${alignment}) 46 | internal struct ${swiftType} { 47 | @usableFromInline 48 | internal var _value: Builtin.${builtinType} 49 | 50 | @_alwaysEmitIntoClient @_transparent 51 | internal init(_ value: Builtin.${builtinType}) { 52 | self._value = value 53 | } 54 | } 55 | 56 | extension UnsafeMutablePointer where Pointee == ${swiftType} { 57 | /// Atomically loads a word starting at this address with the specified 58 | /// memory ordering. 59 | @_semantics("atomics.requires_constant_orderings") 60 | @_alwaysEmitIntoClient 61 | @_transparent // Debug performance 62 | internal func _atomicLoad(ordering: AtomicLoadOrdering) -> ${swiftType} { 63 | switch ordering { 64 | % for (enumOrder, apiOrder, _, llvmOrder) in loadOrderings: 65 | case .${enumOrder}: 66 | return ${swiftType}(Builtin.atomicload_${llvmOrder}_${builtinType}(_rawValue)) 67 | % end 68 | default: 69 | fatalError("Unsupported ordering") 70 | } 71 | } 72 | 73 | /// Atomically stores the specified value starting at the memory referenced by 74 | /// this pointer, with the specified memory ordering. 75 | @_semantics("atomics.requires_constant_orderings") 76 | @_alwaysEmitIntoClient 77 | @_transparent // Debug performance 78 | internal func _atomicStore( 79 | _ desired: ${swiftType}, 80 | ordering: AtomicStoreOrdering 81 | ) { 82 | switch ordering { 83 | % for (enumOrder, apiOrder, _, llvmOrder) in storeOrderings: 84 | case .${enumOrder}: 85 | Builtin.atomicstore_${llvmOrder}_${builtinType}(_rawValue, desired._value) 86 | % end 87 | default: 88 | fatalError("Unsupported ordering") 89 | } 90 | } 91 | 92 | /// Atomically stores the specified value starting at the memory referenced by 93 | /// this pointer, with the specified memory ordering. 94 | @_semantics("atomics.requires_constant_orderings") 95 | @_alwaysEmitIntoClient 96 | @_transparent // Debug performance 97 | internal func _atomicExchange( 98 | _ desired: ${swiftType}, 99 | ordering: AtomicUpdateOrdering 100 | ) -> ${swiftType} { 101 | switch ordering { 102 | % for (enumOrder, apiOrder, _, llvmOrder, failureOrder) in updateOrderings: 103 | case .${enumOrder}: 104 | let oldValue = Builtin.atomicrmw_xchg_${llvmOrder}_${builtinType}( 105 | _rawValue, desired._value) 106 | return ${swiftType}(oldValue) 107 | % end 108 | default: 109 | fatalError("Unsupported ordering") 110 | } 111 | } 112 | 113 | /// Perform an atomic compare and exchange operation with the specified memory 114 | /// ordering. 115 | /// 116 | /// This operation is equivalent to the following pseudocode: 117 | /// 118 | /// ``` 119 | /// atomic(self, ordering) { currentValue in 120 | /// let original = currentValue 121 | /// guard original == expected else { return (false, original) } 122 | /// currentValue = desired 123 | /// return (true, original) 124 | /// } 125 | /// ``` 126 | @_semantics("atomics.requires_constant_orderings") 127 | @_alwaysEmitIntoClient 128 | @_transparent // Debug performance 129 | internal func _atomicCompareExchange( 130 | expected: ${swiftType}, 131 | desired: ${swiftType}, 132 | ordering: AtomicUpdateOrdering 133 | ) -> (exchanged: Bool, original: ${swiftType}) { 134 | switch ordering { 135 | % for (enumOrder, apiOrder, _, llvmOrder, failureOrder) in updateOrderings: 136 | case .${enumOrder}: 137 | let (oldValue, won) = Builtin.cmpxchg_${llvmOrder}_${failureOrder}_${builtinType}( 138 | _rawValue, expected._value, desired._value) 139 | return (Bool(won), ${swiftType}(oldValue)) 140 | % end 141 | default: 142 | fatalError("Unsupported ordering") 143 | } 144 | } 145 | 146 | /// Perform an atomic compare and exchange operation with the specified 147 | /// success/failure memory orderings. 148 | /// 149 | /// This operation is equivalent to the following pseudocode: 150 | /// 151 | /// ``` 152 | /// atomic(self, ordering, failureOrdering) { currentValue in 153 | /// let original = currentValue 154 | /// guard original == expected else { return (false, original) } 155 | /// currentValue = desired 156 | /// return (true, original) 157 | /// } 158 | /// ``` 159 | /// 160 | /// The `ordering` argument specifies the memory ordering to use when the 161 | /// operation manages to update the current value, while `failureOrdering` 162 | /// will be used when the operation leaves the value intact. 163 | @_semantics("atomics.requires_constant_orderings") 164 | @_alwaysEmitIntoClient 165 | @_transparent // Debug performance 166 | internal func _atomicCompareExchange( 167 | expected: ${swiftType}, 168 | desired: ${swiftType}, 169 | successOrdering: AtomicUpdateOrdering, 170 | failureOrdering: AtomicLoadOrdering 171 | ) -> (exchanged: Bool, original: ${swiftType}) { 172 | // FIXME: LLVM doesn't support arbitrary ordering combinations 173 | // yet, so upgrade the success ordering when necessary so that it 174 | // is at least as "strong" as the failure case. 175 | switch (successOrdering, failureOrdering) { 176 | % for (swiftSuccess, apiSuccess, _, llvmOrder, _) in updateOrderings: 177 | % for (swiftFailure, apiFailure, _, llvmFailOrder) in loadOrderings: 178 | case (.${swiftSuccess}, .${swiftFailure}): 179 | let (oldValue, won) = Builtin.cmpxchg_${actualOrders(llvmOrder, llvmFailOrder)}_${builtinType}( 180 | _rawValue, expected._value, desired._value) 181 | return (Bool(won), ${swiftType}(oldValue)) 182 | % end 183 | % end 184 | default: 185 | preconditionFailure("Unsupported orderings") 186 | } 187 | } 188 | 189 | /// Perform an atomic compare and exchange operation with the specified 190 | /// success/failure memory orderings. 191 | /// 192 | /// This operation is equivalent to the following pseudocode: 193 | /// 194 | /// ``` 195 | /// atomic(self, ordering, failureOrdering) { currentValue in 196 | /// let original = currentValue 197 | /// guard original == expected else { return (false, original) } 198 | /// currentValue = desired 199 | /// return (true, original) 200 | /// } 201 | /// ``` 202 | /// 203 | /// The `ordering` argument specifies the memory ordering to use when the 204 | /// operation manages to update the current value, while `failureOrdering` 205 | /// will be used when the operation leaves the value intact. 206 | @_semantics("atomics.requires_constant_orderings") 207 | @_alwaysEmitIntoClient 208 | @_transparent // Debug performance 209 | internal func _atomicWeakCompareExchange( 210 | expected: ${swiftType}, 211 | desired: ${swiftType}, 212 | successOrdering: AtomicUpdateOrdering, 213 | failureOrdering: AtomicLoadOrdering 214 | ) -> (exchanged: Bool, original: ${swiftType}) { 215 | // FIXME: LLVM doesn't support arbitrary ordering combinations 216 | // yet, so upgrade the success ordering when necessary so that it 217 | // is at least as "strong" as the failure case. 218 | switch (successOrdering, failureOrdering) { 219 | % for (swiftSuccess, apiSuccess, _, llvmOrder, _) in updateOrderings: 220 | % for (swiftFailure, apiFailure, _, llvmFailOrder) in loadOrderings: 221 | case (.${swiftSuccess}, .${swiftFailure}): 222 | let (oldValue, won) = Builtin.cmpxchg_${actualOrders(llvmOrder, llvmFailOrder)}_weak_${builtinType}( 223 | _rawValue, expected._value, desired._value) 224 | return (Bool(won), ${swiftType}(oldValue)) 225 | % end 226 | % end 227 | default: 228 | preconditionFailure("Unsupported orderings") 229 | } 230 | } 231 | % if builtinType != "Int128": 232 | % for (swiftName, builtinName, operator, label, doc) in integerOperations: 233 | 234 | /// Perform an atomic ${doc} operation and return the new value, 235 | /// with the specified memory ordering. 236 | /// 237 | % if "Wrapping" in swiftName: 238 | /// - Note: This operation silently wraps around on overflow, like the 239 | /// `${operator}` operator does on `UInt` values. 240 | /// 241 | % end 242 | /// - Returns: The original value before the operation. 243 | @_semantics("atomics.requires_constant_orderings") 244 | @_alwaysEmitIntoClient 245 | @_transparent // Debug performance 246 | internal func _atomicLoadThen${swiftName}( 247 | ${label} operand: ${swiftType}, 248 | ordering: AtomicUpdateOrdering 249 | ) -> ${swiftType} { 250 | switch ordering { 251 | % for (enumOrder, apiOrder, _, llvmOrder, failureOrder) in updateOrderings: 252 | case .${enumOrder}: 253 | let value = Builtin.atomicrmw_${builtinName}_${llvmOrder}_${builtinType}( 254 | _rawValue, operand._value) 255 | return ${swiftType}(value) 256 | % end 257 | default: 258 | preconditionFailure("Unsupported ordering") 259 | } 260 | } 261 | % end 262 | % end 263 | } 264 | % if builtinType == "Int128": 265 | #endif 266 | % end 267 | % end 268 | 269 | #if _pointerBitWidth(_64) 270 | @usableFromInline internal typealias _AtomicIntStorage = _AtomicInt64Storage 271 | @usableFromInline internal typealias _AtomicDoubleWordStorage = _AtomicInt128Storage 272 | #elseif _pointerBitWidth(_32) 273 | @usableFromInline internal typealias _AtomicIntStorage = _AtomicInt32Storage 274 | @usableFromInline internal typealias _AtomicDoubleWordStorage = _AtomicInt64Storage 275 | #else 276 | #error("Unexpected pointer bit width") 277 | #endif 278 | -------------------------------------------------------------------------------- /Sources/Atomics/Protocols/AtomicInteger.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// A type that supports atomic integer operations through a separate 14 | /// atomic storage representation. 15 | /// 16 | /// Atomic integer types provide a number of additional atomic 17 | /// operations beyond the ones supported by `AtomicValue`, such as 18 | /// atomic increments/decrements as well as atomic bitwise operations. 19 | /// These may be mapped to dedicated instructions that can be more 20 | /// efficient than implementations based on the general compare and 21 | /// exchange operation; however, this depends on the capabilities of 22 | /// the compiler and the underlying hardware. 23 | public protocol AtomicInteger: AtomicValue, FixedWidthInteger 24 | where 25 | AtomicRepresentation: AtomicIntegerStorage, 26 | AtomicRepresentation.Value == Self 27 | {} 28 | 29 | /// The storage representation for an atomic integer value, providing 30 | /// pointer-based atomic operations. 31 | /// 32 | /// This is a low-level implementation detail of atomic types; instead 33 | /// of directly handling conforming types, it is usually better to use 34 | /// the `UnsafeAtomic` or `ManagedAtomic` generics -- these provide a 35 | /// more reliable interface while ensuring that the storage is 36 | /// correctly constructed and destroyed. 37 | public protocol AtomicIntegerStorage: AtomicStorage { 38 | /// Perform an atomic wrapping increment operation on the value referenced by 39 | /// `pointer` and return the original value, applying the specified memory 40 | /// ordering. 41 | /// 42 | /// Note: This operation silently wraps around on overflow, like the 43 | /// `&+=` operator does on integer values. 44 | /// 45 | /// - Parameter operand: The value to add to the current value. 46 | /// - Parameter pointer: A memory location previously initialized with a value 47 | /// returned by `prepareAtomicRepresentation(for:)`. 48 | /// - Parameter ordering: The memory ordering to apply on this operation. 49 | /// - Returns: The original value before the operation. 50 | @_semantics("atomics.requires_constant_orderings") 51 | static func atomicLoadThenWrappingIncrement( 52 | by operand: Value, 53 | at pointer: UnsafeMutablePointer, 54 | ordering: AtomicUpdateOrdering 55 | ) -> Value 56 | 57 | /// Perform an atomic wrapping decrement operation on the value referenced by 58 | /// `pointer` and return the original value, applying the specified memory 59 | /// ordering. 60 | /// 61 | /// Note: This operation silently wraps around on overflow, like the 62 | /// `&-=` operator does on integer values. 63 | /// 64 | /// - Parameter operand: The value to subtract from the current value. 65 | /// - Parameter pointer: A memory location previously initialized with a value 66 | /// returned by `prepareAtomicRepresentation(for:)`. 67 | /// - Parameter ordering: The memory ordering to apply on this operation. 68 | /// - Returns: The original value before the operation. 69 | @_semantics("atomics.requires_constant_orderings") 70 | static func atomicLoadThenWrappingDecrement( 71 | by operand: Value, 72 | at pointer: UnsafeMutablePointer, 73 | ordering: AtomicUpdateOrdering 74 | ) -> Value 75 | 76 | /// Perform an atomic bitwise AND operation on the value referenced by 77 | /// `pointer` and return the original value, applying the specified memory 78 | /// ordering. 79 | /// 80 | /// - Parameter operand: An integer value. 81 | /// - Parameter pointer: A memory location previously initialized with a value 82 | /// returned by `prepareAtomicRepresentation(for:)`. 83 | /// - Parameter ordering: The memory ordering to apply on this operation. 84 | /// - Returns: The original value before the operation. 85 | @_semantics("atomics.requires_constant_orderings") 86 | static func atomicLoadThenBitwiseAnd( 87 | with operand: Value, 88 | at pointer: UnsafeMutablePointer, 89 | ordering: AtomicUpdateOrdering 90 | ) -> Value 91 | 92 | /// Perform an atomic bitwise OR operation on the value referenced by 93 | /// `pointer` and return the original value, applying the specified memory 94 | /// ordering. 95 | /// 96 | /// - Parameter operand: An integer value. 97 | /// - Parameter pointer: A memory location previously initialized with a value 98 | /// returned by `prepareAtomicRepresentation(for:)`. 99 | /// - Parameter ordering: The memory ordering to apply on this operation. 100 | /// - Returns: The original value before the operation. 101 | @_semantics("atomics.requires_constant_orderings") 102 | static func atomicLoadThenBitwiseOr( 103 | with operand: Value, 104 | at pointer: UnsafeMutablePointer, 105 | ordering: AtomicUpdateOrdering 106 | ) -> Value 107 | 108 | /// Perform an atomic bitwise XOR operation on the value referenced by 109 | /// `pointer` and return the original value, applying the specified memory 110 | /// ordering. 111 | /// 112 | /// - Parameter operand: An integer value. 113 | /// - Parameter pointer: A memory location previously initialized with a value 114 | /// returned by `prepareAtomicRepresentation(for:)`. 115 | /// - Parameter ordering: The memory ordering to apply on this operation. 116 | /// - Returns: The original value before the operation. 117 | @_semantics("atomics.requires_constant_orderings") 118 | static func atomicLoadThenBitwiseXor( 119 | with operand: Value, 120 | at pointer: UnsafeMutablePointer, 121 | ordering: AtomicUpdateOrdering 122 | ) -> Value 123 | } 124 | -------------------------------------------------------------------------------- /Sources/Atomics/Protocols/AtomicOptionalWrappable.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// An atomic value that also supports atomic operations when wrapped 14 | /// in an `Optional`. Atomic optional wrappable types come with a 15 | /// standalone atomic representation for their optional-wrapped 16 | /// variants. 17 | public protocol AtomicOptionalWrappable: AtomicValue { 18 | /// The atomic storage representation for `Optional`. 19 | associatedtype AtomicOptionalRepresentation: AtomicStorage 20 | where AtomicOptionalRepresentation.Value == AtomicRepresentation.Value? 21 | } 22 | 23 | extension Optional: AtomicValue 24 | where 25 | Wrapped: AtomicOptionalWrappable, 26 | Wrapped.AtomicRepresentation.Value == Wrapped 27 | { 28 | public typealias AtomicRepresentation = Wrapped.AtomicOptionalRepresentation 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Atomics/Protocols/AtomicValue.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// A type that supports atomic operations through a separate atomic storage 14 | /// representation. 15 | public protocol AtomicValue { 16 | /// The atomic storage representation for this value. 17 | associatedtype AtomicRepresentation: AtomicStorage 18 | /* where Self is a subtype of AtomicRepresentation.Value */ 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Atomics/Types/DoubleWord.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2025 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import Builtin 14 | 15 | #if _pointerBitWidth(_32) 16 | @frozen 17 | @_alignment(8) 18 | public struct DoubleWord { 19 | @usableFromInline 20 | internal typealias _Builtin = Builtin.Int64 21 | 22 | public var first: UInt 23 | public var second: UInt 24 | 25 | @inlinable @inline(__always) 26 | public init(first: UInt, second: UInt) { 27 | self.first = first 28 | self.second = second 29 | } 30 | } 31 | #elseif _pointerBitWidth(_64) 32 | @frozen 33 | @_alignment(16) 34 | public struct DoubleWord { 35 | @usableFromInline 36 | internal typealias _Builtin = Builtin.Int128 37 | 38 | public var first: UInt 39 | public var second: UInt 40 | 41 | @inlinable @inline(__always) 42 | public init(first: UInt, second: UInt) { 43 | self.first = first 44 | self.second = second 45 | } 46 | } 47 | #else 48 | #error("Unexpected pointer bit width") 49 | #endif 50 | 51 | extension DoubleWord { 52 | @_alwaysEmitIntoClient 53 | @_transparent 54 | internal init(_ builtin: _Builtin) { 55 | self = unsafeBitCast(builtin, to: DoubleWord.self) 56 | } 57 | 58 | @_alwaysEmitIntoClient 59 | @_transparent 60 | internal var _value: _Builtin { 61 | unsafeBitCast(self, to: _Builtin.self) 62 | } 63 | } 64 | 65 | extension DoubleWord { 66 | /// Initialize a new `DoubleWord` value given its high- and 67 | /// low-order words. 68 | @available(*, deprecated, renamed: "init(first:second:)") 69 | @inlinable @inline(__always) 70 | public init(high: UInt, low: UInt) { 71 | self.init(first: low, second: high) 72 | } 73 | 74 | /// The most significant word in `self`, considering it as a single, 75 | /// wide integer value. 76 | @available(*, deprecated, renamed: "second") 77 | @inlinable @inline(__always) 78 | public var high: UInt { 79 | get { second } 80 | set { second = newValue } 81 | } 82 | 83 | /// The least significant word in `self`, considering it as a 84 | /// single, wide integer value. This may correspond to either 85 | /// `first` or `second`, depending on the endianness of the 86 | /// underlying architecture. 87 | @available(*, deprecated, renamed: "first") 88 | @inlinable @inline(__always) 89 | public var low: UInt { 90 | get { first } 91 | set { first = newValue } 92 | } 93 | } 94 | 95 | extension DoubleWord: Equatable { 96 | @inlinable 97 | public static func ==(left: Self, right: Self) -> Bool { 98 | left.first == right.first && left.second == right.second 99 | } 100 | } 101 | 102 | extension DoubleWord: Hashable { 103 | @inlinable 104 | public func hash(into hasher: inout Hasher) { 105 | hasher.combine(self.first) 106 | hasher.combine(self.second) 107 | } 108 | } 109 | 110 | extension DoubleWord: CustomStringConvertible { 111 | public var description: String { 112 | "DoubleWord(first: \(first), second: \(second))" 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Sources/Atomics/Types/IntegerOperations.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | %{ 13 | from gyb_utils import ( 14 | autogenerated_warning, integerOperations, lowerFirst, argLabel) 15 | }% 16 | ${autogenerated_warning()} 17 | 18 | % for construct in ["UnsafeAtomic", "ManagedAtomic"]: 19 | extension ${construct} where Value: AtomicInteger { 20 | % for (name, _, op, label, doc) in integerOperations: 21 | /// Perform an atomic ${doc} operation and return the original value, applying 22 | /// the specified memory ordering. 23 | /// 24 | % if "Wrapping" in name: 25 | /// Note: This operation silently wraps around on overflow, like the 26 | /// `${op}` operator does on `Int` values. 27 | /// 28 | % end 29 | /// - Parameter operand: An integer value. 30 | /// - Parameter ordering: The memory ordering to apply on this operation. 31 | /// - Returns: The original value before the operation. 32 | @_semantics("atomics.requires_constant_orderings") 33 | @_transparent @_alwaysEmitIntoClient 34 | public func loadThen${name}( 35 | ${label} operand: Value${" = 1" if "crement" in name else ""}, 36 | ordering: AtomicUpdateOrdering 37 | ) -> Value { 38 | _Storage.atomicLoadThen${name}( 39 | ${argLabel(label)}operand, 40 | at: _ptr, 41 | ordering: ordering) 42 | } 43 | 44 | % end 45 | % for (name, _, op, label, doc) in integerOperations: 46 | /// Perform an atomic ${doc} operation and return the new value, applying 47 | /// the specified memory ordering. 48 | /// 49 | % if "Wrapping" in name: 50 | /// Note: This operation silently wraps around on overflow, like the 51 | /// `${op}` operator does on `Int` values. 52 | /// 53 | % end 54 | /// - Parameter operand: An integer value. 55 | /// - Parameter ordering: The memory ordering to apply on this operation. 56 | /// - Returns: The new value after the operation. 57 | @_semantics("atomics.requires_constant_orderings") 58 | @_transparent @_alwaysEmitIntoClient 59 | public func ${lowerFirst(name)}ThenLoad( 60 | ${label} operand: Value${" = 1" if "crement" in name else ""}, 61 | ordering: AtomicUpdateOrdering 62 | ) -> Value { 63 | let original = _Storage.atomicLoadThen${name}( 64 | ${argLabel(label)}operand, 65 | at: _ptr, 66 | ordering: ordering) 67 | return original ${op} operand 68 | } 69 | 70 | % end 71 | 72 | /// Perform an atomic wrapping increment operation applying the 73 | /// specified memory ordering. 74 | /// 75 | /// Note: This operation silently wraps around on overflow, like the 76 | /// `&+=` operator does on `Int` values. 77 | /// 78 | /// - Parameter operand: The value to add to the current value. 79 | /// - Parameter ordering: The memory ordering to apply on this operation. 80 | @_semantics("atomics.requires_constant_orderings") 81 | @_transparent @_alwaysEmitIntoClient 82 | public func wrappingIncrement( 83 | by operand: Value = 1, 84 | ordering: AtomicUpdateOrdering 85 | ) { 86 | _ = _Storage.atomicLoadThenWrappingIncrement( 87 | by: operand, 88 | at: _ptr, 89 | ordering: ordering) 90 | } 91 | 92 | /// Perform an atomic wrapping decrement operation applying the 93 | /// specified memory ordering. 94 | /// 95 | /// Note: This operation silently wraps around on overflow, like the 96 | /// `&-=` operator does on `Int` values. 97 | /// 98 | /// - Parameter operand: The value to subtract from the current value. 99 | /// - Parameter ordering: The memory ordering to apply on this operation. 100 | @_semantics("atomics.requires_constant_orderings") 101 | @_transparent @_alwaysEmitIntoClient 102 | public func wrappingDecrement( 103 | by operand: Value = 1, 104 | ordering: AtomicUpdateOrdering 105 | ) { 106 | _ = _Storage.atomicLoadThenWrappingDecrement( 107 | by: operand, 108 | at: _ptr, 109 | ordering: ordering) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Sources/Atomics/Types/ManagedAtomicLazyReference.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// A reference type holding a lazily initializable atomic 14 | /// strong reference, with automatic memory management. 15 | /// 16 | /// These values can be set (initialized) exactly once, but read many 17 | /// times. 18 | @_fixed_layout 19 | public class ManagedAtomicLazyReference { 20 | /// The value logically stored in an atomic lazy reference value. 21 | public typealias Value = Instance? 22 | 23 | @usableFromInline 24 | internal typealias _Rep = Optional>.AtomicRepresentation 25 | 26 | /// The atomic representation of the value stored inside. 27 | /// 28 | /// Warning: This ivar must only ever be accessed via `_ptr` after 29 | /// its initialization. 30 | @usableFromInline 31 | internal let _storage: _Rep 32 | 33 | /// Initializes a new managed atomic lazy reference with a nil value. 34 | @inlinable 35 | public init() { 36 | _storage = _Rep(nil) 37 | } 38 | 39 | deinit { 40 | if let unmanaged = _ptr.pointee.dispose() { 41 | unmanaged.release() 42 | } 43 | } 44 | 45 | @_alwaysEmitIntoClient @inline(__always) 46 | internal var _ptr: UnsafeMutablePointer<_Rep> { 47 | _getUnsafePointerToStoredProperties(self).assumingMemoryBound(to: _Rep.self) 48 | } 49 | } 50 | 51 | extension ManagedAtomicLazyReference: @unchecked Sendable 52 | where Instance: Sendable {} 53 | 54 | extension ManagedAtomicLazyReference { 55 | /// Atomically initializes this reference if its current value is nil, then 56 | /// returns the initialized value. If this reference is already initialized, 57 | /// then `storeIfNilThenLoad(_:)` discards its supplied argument and returns 58 | /// the current value without updating it. 59 | /// 60 | /// The following example demonstrates how this can be used to implement a 61 | /// thread-safe lazily initialized reference: 62 | /// 63 | /// ``` 64 | /// class Image { 65 | /// var _histogram: UnsafeAtomicLazyReference = .init() 66 | /// 67 | /// // This is safe to call concurrently from multiple threads. 68 | /// var atomicLazyHistogram: Histogram { 69 | /// if let histogram = _histogram.load() { return histogram } 70 | /// // Note that code here may run concurrently on 71 | /// // multiple threads, but only one of them will get to 72 | /// // succeed setting the reference. 73 | /// let histogram = ... 74 | /// return _histogram.storeIfNilThenLoad(histogram) 75 | /// } 76 | /// ``` 77 | /// 78 | /// This operation uses acquiring-and-releasing memory ordering. 79 | public func storeIfNilThenLoad(_ desired: __owned Instance) -> Instance { 80 | let desiredUnmanaged = Unmanaged.passRetained(desired) 81 | let (exchanged, current) = _Rep.atomicCompareExchange( 82 | expected: nil, 83 | desired: desiredUnmanaged, 84 | at: _ptr, 85 | ordering: .acquiringAndReleasing) 86 | if !exchanged { 87 | // The reference has already been initialized. Balance the retain that 88 | // we performed on `desired`. 89 | desiredUnmanaged.release() 90 | return current!.takeUnretainedValue() 91 | } 92 | return desiredUnmanaged.takeUnretainedValue() 93 | } 94 | 95 | /// Atomically loads and returns the current value of this reference. 96 | /// 97 | /// The load operation is performed with the memory ordering 98 | /// `AtomicLoadOrdering.acquiring`. 99 | public func load() -> Instance? { 100 | let value = _Rep.atomicLoad(at: _ptr, ordering: .acquiring) 101 | return value?.takeUnretainedValue() 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Sources/Atomics/Types/UnsafeAtomicLazyReference.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// An unsafe reference type holding a lazily initializable atomic 14 | /// strong reference, requiring manual memory management of the 15 | /// underlying storage representation. 16 | /// 17 | /// These values can be set (initialized) exactly once, but read many 18 | /// times. 19 | @frozen 20 | public struct UnsafeAtomicLazyReference { 21 | /// The value logically stored in an atomic lazy reference value. 22 | public typealias Value = Instance? 23 | 24 | @usableFromInline 25 | internal typealias _Rep = Optional>.AtomicRepresentation 26 | 27 | @usableFromInline 28 | internal let _ptr: UnsafeMutablePointer<_Rep> 29 | 30 | /// Initialize an unsafe atomic lazy reference that uses the supplied memory 31 | /// location for storage. The storage location must already be initialized to 32 | /// represent a valid atomic value. 33 | /// 34 | /// At the end of the lifetime of the atomic value, you must manually ensure 35 | /// that the storage location is correctly `dispose()`d, deinitalized and 36 | /// deallocated. 37 | /// 38 | /// Note: This is not an atomic operation. 39 | @_transparent // Debug performance 40 | public init(@_nonEphemeral at pointer: UnsafeMutablePointer) { 41 | // `Storage` is layout-compatible with its only stored property. 42 | _ptr = UnsafeMutableRawPointer(pointer).assumingMemoryBound(to: _Rep.self) 43 | } 44 | } 45 | 46 | extension UnsafeAtomicLazyReference: @unchecked Sendable 47 | where Instance: Sendable {} 48 | 49 | extension UnsafeAtomicLazyReference { 50 | /// The storage representation for an atomic lazy reference value. 51 | @frozen 52 | public struct Storage { 53 | @usableFromInline 54 | internal var _storage: _Rep 55 | 56 | /// Initialize a new atomic lazy reference storage value holding `nil`. 57 | /// 58 | /// Note: This is not an atomic operation. This call may have side effects 59 | /// (such as unpaired retains of strong references) that will need to be 60 | /// undone by calling `dispose()` before the storage value is 61 | /// deinitialized. 62 | @inlinable @inline(__always) 63 | public init() { 64 | _storage = _Rep(nil) 65 | } 66 | 67 | /// Prepare this atomic storage value for deinitialization, extracting the 68 | /// logical value it represents. This invalidates this atomic storage; you 69 | /// must not perform any operations on it after this call (except for 70 | /// deinitialization). 71 | /// 72 | /// This call prevents resource leaks when destroying the storage 73 | /// representation of certain `AtomicValue` types. (In particular, ones 74 | /// that model strong references.) 75 | /// 76 | /// Note: This is not an atomic operation. Logically, it implements a 77 | /// custom destructor for the underlying non-copiable value. 78 | @inlinable @inline(__always) 79 | @discardableResult 80 | public mutating func dispose() -> Value { 81 | defer { _storage = _Rep(nil) } 82 | return _storage.dispose()?.takeRetainedValue() 83 | } 84 | } 85 | } 86 | 87 | extension UnsafeAtomicLazyReference { 88 | /// Create a new `UnsafeAtomicLazyReference` value by dynamically allocating 89 | /// storage for it. 90 | /// 91 | /// This call is usually paired with `destroy` to get rid of the allocated 92 | /// storage at the end of its lifetime. 93 | /// 94 | /// Note: This is not an atomic operation. 95 | @inlinable 96 | public static func create() -> Self { 97 | let ptr = UnsafeMutablePointer.allocate(capacity: 1) 98 | ptr.initialize(to: Storage()) 99 | return Self(at: ptr) 100 | } 101 | 102 | /// Disposes of the current value of the storage location corresponding to 103 | /// this unsafe atomic lazy reference, then deinitializes and deallocates the 104 | /// storage. 105 | /// 106 | /// Note: This is not an atomic operation. 107 | /// 108 | /// - Returns: The last value stored in the storage representation before it 109 | /// was destroyed. 110 | @discardableResult 111 | @inlinable 112 | public func destroy() -> Value { 113 | // `Storage` is layout-compatible with its only stored property. 114 | let address = UnsafeMutableRawPointer(_ptr) 115 | .assumingMemoryBound(to: Storage.self) 116 | defer { address.deallocate() } 117 | return address.pointee.dispose() 118 | } 119 | } 120 | 121 | extension UnsafeAtomicLazyReference { 122 | /// Atomically initializes this reference if its current value is nil, then 123 | /// returns the initialized value. If this reference is already initialized, 124 | /// then `storeIfNilThenLoad(_:)` discards its supplied argument and returns 125 | /// the current value without updating it. 126 | /// 127 | /// The following example demonstrates how this can be used to implement a 128 | /// thread-safe lazily initialized reference: 129 | /// 130 | /// ``` 131 | /// class Image { 132 | /// var _histogram: UnsafeAtomicLazyReference = .init() 133 | /// 134 | /// // This is safe to call concurrently from multiple threads. 135 | /// var atomicLazyHistogram: Histogram { 136 | /// if let histogram = _histogram.load() { return histogram } 137 | /// // Note that code here may run concurrently on 138 | /// // multiple threads, but only one of them will get to 139 | /// // succeed setting the reference. 140 | /// let histogram = ... 141 | /// return _histogram.storeIfNilThenLoad(histogram) 142 | /// } 143 | /// ``` 144 | /// 145 | /// This operation uses acquiring-and-releasing memory ordering. 146 | public func storeIfNilThenLoad(_ desired: __owned Instance) -> Instance { 147 | let desiredUnmanaged = Unmanaged.passRetained(desired) 148 | let (exchanged, current) = _Rep.atomicCompareExchange( 149 | expected: nil, 150 | desired: desiredUnmanaged, 151 | at: _ptr, 152 | ordering: .acquiringAndReleasing) 153 | if !exchanged { 154 | // The reference has already been initialized. Balance the retain that 155 | // we performed on `desired`. 156 | desiredUnmanaged.release() 157 | return current!.takeUnretainedValue() 158 | } 159 | return desiredUnmanaged.takeUnretainedValue() 160 | } 161 | 162 | /// Atomically loads and returns the current value of this reference. 163 | /// 164 | /// The load operation is performed with the memory ordering 165 | /// `AtomicLoadOrdering.acquiring`. 166 | public func load() -> Instance? { 167 | let value = _Rep.atomicLoad(at: _ptr, ordering: .acquiring) 168 | return value?.takeUnretainedValue() 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /Sources/Atomics/Unmanaged extensions.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2025 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #if ATOMICS_SINGLE_MODULE 14 | @_silgen_name("_sa_retain_n") 15 | internal func _sa_retain_n(_ object: UnsafeMutableRawPointer, _ delta: UInt32) 16 | 17 | @_silgen_name("_sa_release_n") 18 | internal func _sa_release_n(_ object: UnsafeMutableRawPointer, _ delta: UInt32) 19 | #else 20 | // Note: This file contains the last remaining import of the shims 21 | // module, and we only need it to get the declarations for 22 | // _sa_retain_n/_sa_release_n. The import is unfortunately still 23 | // problematic; these functions need to be moved into the stdlib or 24 | // (preferably) we need a compiler-level fix for 25 | // https://github.com/apple/swift/issues/56105 to get rid of it. 26 | // 27 | // Hiding the import using @_implementationOnly is not possible unless 28 | // Swift's library evolution dialect is enabled. (Which we cannot easily test 29 | // here.) Perhaps `internal import` will help work around this at some point. 30 | import _AtomicsShims 31 | #endif 32 | 33 | extension Unmanaged { 34 | internal func retain(by delta: Int) { 35 | _sa_retain_n(toOpaque(), UInt32(delta)) 36 | } 37 | 38 | internal func release(by delta: Int) { 39 | _sa_release_n(toOpaque(), UInt32(delta)) 40 | } 41 | } 42 | 43 | extension Unmanaged { 44 | @inline(__always) 45 | internal static func passRetained(_ instance: __owned Instance?) -> Self? { 46 | guard let instance = instance else { return nil } 47 | return .passRetained(instance) 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /Sources/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | This source file is part of the Swift Atomics Open Source Project 3 | 4 | Copyright (c) 2021 - 2023 Apple Inc. and the Swift project authors 5 | Licensed under Apache License v2.0 with Runtime Library Exception 6 | 7 | See https://swift.org/LICENSE.txt for license information 8 | #]] 9 | 10 | add_subdirectory(_AtomicsShims) 11 | add_subdirectory(Atomics) 12 | -------------------------------------------------------------------------------- /Sources/_AtomicsShims/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | This source file is part of the Swift Atomics Open Source Project 3 | 4 | Copyright (c) 2021 - 2023 Apple Inc. and the Swift project authors 5 | Licensed under Apache License v2.0 with Runtime Library Exception 6 | 7 | See https://swift.org/LICENSE.txt for license information 8 | #]] 9 | 10 | add_library(_AtomicsShims STATIC 11 | src/_AtomicsShims.c) 12 | target_include_directories(_AtomicsShims PUBLIC 13 | include) 14 | target_compile_options(_AtomicsShims PUBLIC 15 | "$<$:SHELL:${ATOMICS_SWIFT_FLAGS}>" 16 | "$<$:SHELL:${ATOMICS_C_FLAGS}>") 17 | if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") 18 | target_compile_options(_AtomicsShims PUBLIC 19 | "$<$:SHELL:-Xcc -mcx16>") 20 | endif() 21 | 22 | set_property(GLOBAL APPEND PROPERTY SWIFT_ATOMICS_EXPORTS _AtomicsShims) 23 | -------------------------------------------------------------------------------- /Sources/_AtomicsShims/include/_AtomicsShims.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2025 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #ifndef SWIFTATOMIC_HEADER_INCLUDED 14 | #define SWIFTATOMIC_HEADER_INCLUDED 1 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #define SWIFTATOMIC_INLINE static inline __attribute__((__always_inline__)) 21 | #define SWIFTATOMIC_SWIFT_NAME(name) __attribute__((swift_name(#name))) 22 | #define SWIFTATOMIC_ALIGNED(alignment) __attribute__((aligned(alignment))) 23 | 24 | #if __has_attribute(swiftcall) 25 | # define SWIFTATOMIC_SWIFTCC __attribute__((swiftcall)) 26 | #else 27 | # define SWIFTATOMIC_SWIFTCC 28 | #endif 29 | 30 | #if ATOMICS_SINGLE_MODULE 31 | # if __has_attribute(visibility) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_WIN32) 32 | # define SWIFTATOMIC_SHIMS_EXPORT __attribute__((visibility("hidden"))) 33 | # else 34 | # define SWIFTATOMIC_SHIMS_EXPORT 35 | # endif 36 | #else 37 | # ifdef __cplusplus 38 | # define SWIFTATOMIC_SHIMS_EXPORT extern "C" 39 | # else 40 | # define SWIFTATOMIC_SHIMS_EXPORT extern 41 | # endif 42 | #endif 43 | 44 | #if SWIFTATOMIC_SINGLE_MODULE 45 | // In the single-module configuration, declare _sa_retain_n/_sa_release_n with 46 | // the Swift calling convention, so that they can be easily picked up with 47 | // @_silgen_name'd declarations. 48 | // FIXME: Use @_cdecl("name") once we can switch to a compiler that has it. 49 | SWIFTATOMIC_SWIFTCC SWIFTATOMIC_SHIMS_EXPORT void _sa_retain_n(void *object, uint32_t n); 50 | SWIFTATOMIC_SWIFTCC SWIFTATOMIC_SHIMS_EXPORT void _sa_release_n(void *object, uint32_t n); 51 | #else 52 | SWIFTATOMIC_SHIMS_EXPORT void _sa_retain_n(void *object, uint32_t n); 53 | SWIFTATOMIC_SHIMS_EXPORT void _sa_release_n(void *object, uint32_t n); 54 | #endif 55 | 56 | #endif //SWIFTATOMIC_HEADER_INCLUDED 57 | -------------------------------------------------------------------------------- /Sources/_AtomicsShims/include/module.modulemap: -------------------------------------------------------------------------------- 1 | module _AtomicsShims { 2 | header "_AtomicsShims.h" 3 | } 4 | -------------------------------------------------------------------------------- /Sources/_AtomicsShims/src/_AtomicsShims.c: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "_AtomicsShims.h" 14 | 15 | // FIXME: These should be static inline header-only shims, but Swift 5.3 doesn't 16 | // like calls to swift_retain_n/swift_release_n appearing in Swift code, not 17 | // even when imported through C. (See https://bugs.swift.org/browse/SR-13708) 18 | 19 | #if defined(__APPLE__) && defined(__MACH__) 20 | // Ensure we link with libswiftCore.dylib even when the build system decides 21 | // to build this module as a standalone library. 22 | // (See https://github.com/apple/swift-atomics/issues/55) 23 | __asm__(".linker_option \"-lswiftCore\"\n"); 24 | #endif 25 | 26 | void _sa_retain_n(void *object, uint32_t n) 27 | { 28 | extern void *swift_retain_n(void *object, uint32_t n); 29 | swift_retain_n(object, n); 30 | } 31 | 32 | void _sa_release_n(void *object, uint32_t n) 33 | { 34 | extern void swift_release_n(void *object, uint32_t n); 35 | swift_release_n(object, n); 36 | } 37 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/AtomicLazyReference.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import XCTest 14 | import Atomics 15 | 16 | class AtomicLazyReferenceTests: XCTestCase { 17 | func test_unsafe_create_destroy() { 18 | XCTAssertEqual(LifetimeTracked.instances, 0) 19 | let v = UnsafeAtomicLazyReference.create() 20 | defer { 21 | v.destroy() 22 | XCTAssertEqual(LifetimeTracked.instances, 0) 23 | } 24 | XCTAssertNil(v.load()) 25 | } 26 | 27 | func test_unsafe_storeIfNilThenLoad() { 28 | XCTAssertEqual(LifetimeTracked.instances, 0) 29 | do { 30 | let v = UnsafeAtomicLazyReference.create() 31 | XCTAssertNil(v.load()) 32 | 33 | let ref = LifetimeTracked(42) 34 | XCTAssertTrue(v.storeIfNilThenLoad(ref) === ref) 35 | XCTAssertTrue(v.load() === ref) 36 | 37 | let ref2 = LifetimeTracked(23) 38 | XCTAssertTrue(v.storeIfNilThenLoad(ref2) === ref) 39 | XCTAssertTrue(v.load() === ref) 40 | 41 | v.destroy() 42 | } 43 | XCTAssertEqual(LifetimeTracked.instances, 0) 44 | } 45 | 46 | func test_managed_storeIfNilThenLoad() { 47 | XCTAssertEqual(LifetimeTracked.instances, 0) 48 | do { 49 | let v = ManagedAtomicLazyReference() 50 | XCTAssertNil(v.load()) 51 | 52 | let ref = LifetimeTracked(42) 53 | XCTAssertTrue(v.storeIfNilThenLoad(ref) === ref) 54 | XCTAssertTrue(v.load() === ref) 55 | 56 | let ref2 = LifetimeTracked(23) 57 | XCTAssertTrue(v.storeIfNilThenLoad(ref2) === ref) 58 | XCTAssertTrue(v.load() === ref) 59 | } 60 | XCTAssertEqual(LifetimeTracked.instances, 0) 61 | } 62 | 63 | #if MANUAL_TEST_DISCOVERY 64 | public static var allTests = [ 65 | ("test_unsafe_create_destroy", test_unsafe_create_destroy), 66 | ("test_unsafe_storeIfNilThenLoad", test_unsafe_storeIfNilThenLoad), 67 | ("test_managed_storeIfNilThenLoad", test_managed_storeIfNilThenLoad), 68 | ] 69 | #endif 70 | } 71 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicBoolTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("Bool", "Bool", "true", "false"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicDoubleWordTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("DoubleWord", "DoubleWord", "DoubleWord(first: 100, second: 64)", "DoubleWord(first: 50, second: 32)"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicInt16Tests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("Int16", "Int16", "12", "23"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicInt32Tests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("Int32", "Int32", "12", "23"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicInt64Tests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("Int64", "Int64", "12", "23"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicInt8Tests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("Int8", "Int8", "12", "23"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicIntTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("Int", "Int", "12", "23"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicMutablePointerTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("MutablePointer", "UnsafeMutablePointer", "_mfoo1", "_mfoo2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicMutableRawPointerTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("MutableRawPointer", "UnsafeMutableRawPointer", "_mraw1", "_mraw2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicOptionalMutablePointerTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("OptionalMutablePointer", "UnsafeMutablePointer?", "nil", "_mfoo2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicOptionalMutableRawPointerTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("OptionalMutableRawPointer", "UnsafeMutableRawPointer?", "nil", "_mraw2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicOptionalPointerTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("OptionalPointer", "UnsafePointer?", "nil", "_foo2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicOptionalRawPointerTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("OptionalRawPointer", "UnsafeRawPointer?", "nil", "_raw2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicOptionalRawRepresentableTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("OptionalRawRepresentable", "Hyacinth?", "Hyacinth.bucket", "nil"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicOptionalReferenceTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("OptionalReference", "Baz?", "nil", "_baz2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicOptionalUnmanagedTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("OptionalUnmanaged", "Unmanaged?", "nil", "_bar2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicPointerTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("Pointer", "UnsafePointer", "_foo1", "_foo2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicRawPointerTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("RawPointer", "UnsafeRawPointer", "_raw1", "_raw2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicRawRepresentableTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("RawRepresentable", "Fred", "Fred.one", "Fred.two"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicReferenceTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("Reference", "Baz", "_baz1", "_baz2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicUInt16Tests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("UInt16", "UInt16", "12", "23"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicUInt32Tests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | 15 | from gyb import expand 16 | 17 | types = [ 18 | # Label Type a b 19 | ("UInt32", "UInt32", "12", "23"), 20 | ] 21 | }% 22 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 23 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicUInt64Tests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("UInt64", "UInt64", "12", "23"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicUInt8Tests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("UInt8", "UInt8", "12", "23"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicUIntTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("UInt", "UInt", "12", "23"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicAtomicUnmanagedTests.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | %{ 14 | from gyb import expand 15 | 16 | types = [ 17 | # Label Type a b 18 | ("Unmanaged", "Unmanaged", "_bar1", "_bar2"), 19 | ] 20 | }% 21 | ${expand("BasicTests.gyb-template", line_directive='', types=types)} 22 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/Basics/BasicTestSupport.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2025 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import Atomics 14 | 15 | #if compiler(>=6.0) 16 | extension Unmanaged: @retroactive Equatable { // FIXME: This is terrible 17 | public static func ==(left: Self, right: Self) -> Bool { 18 | left.toOpaque() == right.toOpaque() 19 | } 20 | } 21 | #else 22 | extension Unmanaged: Equatable { // FIXME: This is terrible 23 | public static func ==(left: Self, right: Self) -> Bool { 24 | left.toOpaque() == right.toOpaque() 25 | } 26 | } 27 | #endif 28 | 29 | struct Foo: Equatable, CustomStringConvertible { 30 | var value: Int 31 | init(_ value: Int) { self.value = value } 32 | var description: String { "Foo(\(value))" } 33 | } 34 | 35 | class Bar: Equatable, CustomStringConvertible { 36 | var value: Int 37 | init(_ value: Int) { self.value = value } 38 | var description: String { "Bar(\(value))" } 39 | static func ==(left: Bar, right: Bar) -> Bool { 40 | left === right 41 | } 42 | } 43 | 44 | final class Baz: Equatable, CustomStringConvertible, AtomicReference { 45 | var value: Int 46 | init(_ value: Int) { self.value = value } 47 | var description: String { "Bar(\(value))" } 48 | static func ==(left: Baz, right: Baz) -> Bool { 49 | left === right 50 | } 51 | } 52 | 53 | enum Fred: Int, AtomicValue { 54 | case one 55 | case two 56 | } 57 | 58 | struct Hyacinth: RawRepresentable, Equatable, AtomicOptionalWrappable { 59 | var rawValue: UnsafeRawPointer 60 | 61 | init(rawValue: UnsafeRawPointer) { 62 | self.rawValue = rawValue 63 | } 64 | 65 | static let bucket: Hyacinth = Hyacinth( 66 | rawValue: UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 8)) 67 | } 68 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/DoubleWord.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import XCTest 14 | import Atomics 15 | 16 | class DoubleWordTests: XCTestCase { 17 | func testMemoryLayout() { 18 | XCTAssertEqual(MemoryLayout.size, 2 * MemoryLayout.size) 19 | XCTAssertEqual(MemoryLayout.stride, MemoryLayout.size) 20 | XCTAssertEqual(MemoryLayout.alignment, 2 * MemoryLayout.alignment) 21 | } 22 | 23 | struct UIntPair: Equatable { 24 | var first: UInt 25 | var second: UInt 26 | 27 | init(_ first: UInt, _ second: UInt) { 28 | self.first = first 29 | self.second = second 30 | } 31 | } 32 | 33 | func componentsInMemoryOrder(of dword: DoubleWord) -> UIntPair { 34 | let p = UnsafeMutableRawPointer.allocate( 35 | byteCount: MemoryLayout.size, 36 | alignment: MemoryLayout.alignment) 37 | p.storeBytes(of: dword, as: DoubleWord.self) 38 | let first = p.load(as: UInt.self) 39 | let second = p.load(fromByteOffset: MemoryLayout.stride, as: UInt.self) 40 | return UIntPair(first, second) 41 | } 42 | 43 | func testFirstSecondInitializer() { 44 | let value = DoubleWord(first: 1, second: 2) 45 | XCTAssertEqual(componentsInMemoryOrder(of: value), UIntPair(1, 2)) 46 | } 47 | 48 | @available(*, deprecated) 49 | func testHighLowInitializer() { 50 | let value = DoubleWord(high: 1, low: 2) 51 | XCTAssertEqual(componentsInMemoryOrder(of: value), UIntPair(2, 1)) 52 | } 53 | 54 | func testPropertyGetters() { 55 | let value = DoubleWord(first: UInt.max, second: 0) 56 | XCTAssertEqual(value.first, UInt.max) 57 | XCTAssertEqual(value.second, 0) 58 | } 59 | 60 | @available(*, deprecated) 61 | func testPropertyGetters_deprecated() { 62 | let value = DoubleWord(first: UInt.max, second: 0) 63 | XCTAssertEqual(value.first, UInt.max) 64 | XCTAssertEqual(value.second, 0) 65 | XCTAssertEqual(value.high, 0) 66 | XCTAssertEqual(value.low, UInt.max) 67 | } 68 | 69 | func testPropertySetters() { 70 | var value = DoubleWord(first: 1, second: 2) 71 | value.first = 3 72 | XCTAssertEqual(componentsInMemoryOrder(of: value), UIntPair(3, 2)) 73 | value.second = 4 74 | XCTAssertEqual(componentsInMemoryOrder(of: value), UIntPair(3, 4)) 75 | } 76 | 77 | @available(*, deprecated) 78 | func testPropertySetters_deprecated() { 79 | var value = DoubleWord(first: 3, second: 4) 80 | value.low = 5 81 | XCTAssertEqual(componentsInMemoryOrder(of: value), UIntPair(5, 4)) 82 | value.high = 6 83 | XCTAssertEqual(componentsInMemoryOrder(of: value), UIntPair(5, 6)) 84 | } 85 | 86 | #if MANUAL_TEST_DISCOVERY 87 | public static var allTests = [ 88 | ("testMemoryLayout", testMemoryLayout), 89 | ("testFirstSecondInitializer", testFirstSecondInitializer), 90 | ("testHighLowInitializer", testHighLowInitializer), 91 | ("testPropertyGetters", testPropertyGetters), 92 | ("testPropertySetters", testPropertySetters), 93 | ] 94 | #endif 95 | } 96 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/LifetimeTracked.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | /// A type that tracks the number of live instances. 14 | /// 15 | /// To be useful in more contexts, `LifetimeTracked` conforms to various 16 | /// protocols in trivial ways. 17 | /// 18 | /// `LifetimeTracked` is useful to check for leaks in algorithms and data 19 | /// structures. `StdlibUnittest` harness automatically checks that after each 20 | /// test has done executing, no `LifetimeTracked` instances exist. 21 | public final class LifetimeTracked { 22 | public init(_ value: Int, identity: Int = 0) { 23 | LifetimeTracked.instances += 1 24 | LifetimeTracked._nextSerialNumber += 1 25 | serialNumber = LifetimeTracked._nextSerialNumber 26 | self.value = value 27 | self.identity = identity 28 | } 29 | 30 | deinit { 31 | assert(serialNumber > 0, "double destruction!") 32 | LifetimeTracked.instances -= 1 33 | serialNumber = -serialNumber 34 | } 35 | 36 | public static var instances: Int = 0 37 | internal static var _nextSerialNumber = 0 38 | 39 | public let value: Int 40 | public var identity: Int 41 | public var serialNumber: Int = 0 42 | } 43 | 44 | extension LifetimeTracked : Equatable { 45 | public static func == (x: LifetimeTracked, y: LifetimeTracked) -> Bool { 46 | return x.value == y.value 47 | } 48 | } 49 | 50 | extension LifetimeTracked : Hashable { 51 | public var hashValue: Int { 52 | return value 53 | } 54 | public func hash(into hasher: inout Hasher) { 55 | hasher.combine(value) 56 | } 57 | } 58 | 59 | extension LifetimeTracked : Strideable { 60 | public func distance(to other: LifetimeTracked) -> Int { 61 | return self.value.distance(to: other.value) 62 | } 63 | 64 | public func advanced(by n: Int) -> LifetimeTracked { 65 | return LifetimeTracked(self.value.advanced(by: n)) 66 | } 67 | } 68 | 69 | extension LifetimeTracked : CustomStringConvertible { 70 | public var description: String { 71 | assert(serialNumber > 0, "dead Tracked!") 72 | return value.description 73 | } 74 | } 75 | 76 | public func < (x: LifetimeTracked, y: LifetimeTracked) -> Bool { 77 | return x.value < y.value 78 | } 79 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/LockFreeQueue.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | // A lock-free concurrent queue implementation adapted from 14 | // M. Michael and M. Scott's 1996 paper [Michael 1996]. 15 | // 16 | // [Michael 1996]: https://doi.org/10.1145/248052.248106 17 | // 18 | // While this is a nice illustration of the use of atomic strong references, 19 | // this is a somewhat sloppy implementation of an old algorithm. If you need a 20 | // lock-free queue for actual production use, it would probably be a good idea 21 | // to look at some more recent algorithms before deciding on this one. 22 | // 23 | // Note: because this implementation uses reference counting, we don't need 24 | // to implement a free list to resolve the original algorithm's use-after-free 25 | // problem. 26 | 27 | import XCTest 28 | import Dispatch 29 | import Atomics 30 | 31 | private var iterations: Int { 32 | #if SWIFT_ATOMICS_LONG_TESTS 33 | return 1_000_000 34 | #else 35 | return 50_000 36 | #endif 37 | } 38 | 39 | private let nodeCount = ManagedAtomic(0) 40 | 41 | class LockFreeQueue { 42 | final class Node: AtomicReference { 43 | let next: ManagedAtomic 44 | var value: Element? 45 | 46 | init(value: Element?, next: Node?) { 47 | self.value = value 48 | self.next = ManagedAtomic(next) 49 | nodeCount.wrappingIncrement(ordering: .relaxed) 50 | } 51 | 52 | deinit { 53 | var values = 0 54 | // Prevent stack overflow when reclaiming a long queue 55 | var node = self.next.exchange(nil, ordering: .relaxed) 56 | while node != nil && isKnownUniquelyReferenced(&node) { 57 | let next = node!.next.exchange(nil, ordering: .relaxed) 58 | withExtendedLifetime(node) { 59 | values += 1 60 | } 61 | node = next 62 | } 63 | if values > 0 { 64 | print(values) 65 | } 66 | nodeCount.wrappingDecrement(ordering: .relaxed) 67 | } 68 | } 69 | 70 | let head: ManagedAtomic 71 | let tail: ManagedAtomic 72 | 73 | // Used to distinguish removed nodes from active nodes with a nil `next`. 74 | let marker = Node(value: nil, next: nil) 75 | 76 | init() { 77 | let dummy = Node(value: nil, next: nil) 78 | self.head = ManagedAtomic(dummy) 79 | self.tail = ManagedAtomic(dummy) 80 | } 81 | 82 | func enqueue(_ newValue: Element) { 83 | let new = Node(value: newValue, next: nil) 84 | 85 | var tail = self.tail.load(ordering: .acquiring) 86 | while true { 87 | let next = tail.next.load(ordering: .acquiring) 88 | if tail === marker || next === marker { 89 | // The node we loaded has been unlinked by a dequeue on another thread. 90 | // Try again. 91 | tail = self.tail.load(ordering: .acquiring) 92 | continue 93 | } 94 | if let next = next { 95 | // Assist competing threads by nudging `self.tail` forward a step. 96 | let (exchanged, original) = self.tail.compareExchange( 97 | expected: tail, 98 | desired: next, 99 | ordering: .acquiringAndReleasing) 100 | tail = (exchanged ? next : original) 101 | continue 102 | } 103 | let (exchanged, current) = tail.next.compareExchange( 104 | expected: nil, 105 | desired: new, 106 | ordering: .acquiringAndReleasing 107 | ) 108 | if exchanged { 109 | _ = self.tail.compareExchange(expected: tail, desired: new, ordering: .releasing) 110 | return 111 | } 112 | tail = current! 113 | } 114 | } 115 | 116 | func dequeue() -> Element? { 117 | while true { 118 | let head = self.head.load(ordering: .acquiring) 119 | let next = head.next.load(ordering: .acquiring) 120 | if next === marker { continue } 121 | guard let n = next else { return nil } 122 | let tail = self.tail.load(ordering: .acquiring) 123 | if head === tail { 124 | // Nudge `tail` forward a step to make sure it doesn't fall off the 125 | // list when we unlink this node. 126 | _ = self.tail.compareExchange(expected: tail, desired: n, ordering: .acquiringAndReleasing) 127 | } 128 | if self.head.compareExchange(expected: head, desired: n, ordering: .releasing).exchanged { 129 | let result = n.value! 130 | n.value = nil 131 | // To prevent threads that are suspended in `enqueue`/`dequeue` from 132 | // holding onto arbitrarily long chains of removed nodes, we unlink 133 | // removed nodes by replacing their `next` value with the special 134 | // `marker`. 135 | head.next.store(marker, ordering: .releasing) 136 | return result 137 | } 138 | } 139 | } 140 | } 141 | 142 | class QueueTests: XCTestCase { 143 | override func tearDown() { 144 | XCTAssertEqual(nodeCount.load(ordering: .relaxed), 0) 145 | } 146 | 147 | func check(readers: Int, writers: Int, count: Int) { 148 | let queue = LockFreeQueue<(writer: Int, value: Int)>() 149 | let num = ManagedAtomic(0) 150 | DispatchQueue.concurrentPerform(iterations: writers + readers) { id in 151 | if id < writers { 152 | // Writer 153 | for i in 0 ..< count { 154 | queue.enqueue((id, i)) 155 | } 156 | } else { 157 | // Reader 158 | var values = (0 ..< writers).map { _ in -1 } 159 | while num.load(ordering: .relaxed) < writers * count { 160 | // Spin until we get a value 161 | guard let (writer, value) = queue.dequeue() else { continue } 162 | precondition(writer >= 0 && writer < writers) 163 | precondition(readers == 1 ? value == values[writer] + 1 : value > values[writer]) 164 | values[writer] = value 165 | num.wrappingIncrement(ordering: .relaxed) 166 | } 167 | } 168 | } 169 | } 170 | 171 | func test01_10() { 172 | check(readers: 1, writers: 10, count: iterations) 173 | } 174 | 175 | func test02_10() { 176 | check(readers: 2, writers: 10, count: iterations) 177 | } 178 | 179 | func test04_10() { 180 | check(readers: 2, writers: 10, count: iterations) 181 | } 182 | 183 | func test16_16() { 184 | check(readers: 16, writers: 16, count: iterations) 185 | } 186 | 187 | #if MANUAL_TEST_DISCOVERY 188 | public static var allTests = [ 189 | ("test01_10", test01_10), 190 | ("test02_10", test02_10), 191 | ("test04_10", test04_10), 192 | ("test16_16", test16_16), 193 | ] 194 | #endif 195 | } 196 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/LockFreeSingleConsumerStack.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import XCTest 14 | import Atomics 15 | import Dispatch 16 | 17 | class LockFreeSingleConsumerStack { 18 | struct Node { 19 | let value: Element 20 | var next: UnsafeMutablePointer? 21 | } 22 | typealias NodePtr = UnsafeMutablePointer 23 | 24 | private var _last = UnsafeAtomic.create(nil) 25 | private var _consumerCount = UnsafeAtomic.create(0) 26 | private var foo = 0 27 | 28 | deinit { 29 | // Discard remaining nodes 30 | while let _ = pop() {} 31 | _last.destroy() 32 | _consumerCount.destroy() 33 | } 34 | 35 | // Push the given element to the top of the stack. 36 | // It is okay to concurrently call this in an arbitrary number of threads. 37 | func push(_ value: Element) { 38 | let new = NodePtr.allocate(capacity: 1) 39 | new.initialize(to: Node(value: value, next: nil)) 40 | 41 | var done = false 42 | var current = _last.load(ordering: .relaxed) 43 | while !done { 44 | new.pointee.next = current 45 | (done, current) = _last.compareExchange( 46 | expected: current, 47 | desired: new, 48 | ordering: .releasing) 49 | } 50 | } 51 | 52 | // Pop and return the topmost element from the stack. 53 | // This method does not support multiple overlapping concurrent calls. 54 | func pop() -> Element? { 55 | precondition( 56 | _consumerCount.loadThenWrappingIncrement(ordering: .acquiring) == 0, 57 | "Multiple consumers detected") 58 | defer { _consumerCount.wrappingDecrement(ordering: .releasing) } 59 | var done = false 60 | var current = _last.load(ordering: .acquiring) 61 | while let c = current { 62 | (done, current) = _last.compareExchange( 63 | expected: c, 64 | desired: c.pointee.next, 65 | ordering: .acquiring) 66 | if done { 67 | let result = c.move() 68 | c.deallocate() 69 | return result.value 70 | } 71 | } 72 | return nil 73 | } 74 | } 75 | 76 | class LockFreeSingleConsumerStackTests: XCTestCase { 77 | func test_Basics() { 78 | let stack = LockFreeSingleConsumerStack() 79 | XCTAssertNil(stack.pop()) 80 | stack.push(0) 81 | XCTAssertEqual(0, stack.pop()) 82 | 83 | stack.push(1) 84 | stack.push(2) 85 | stack.push(3) 86 | stack.push(4) 87 | XCTAssertEqual(4, stack.pop()) 88 | XCTAssertEqual(3, stack.pop()) 89 | XCTAssertEqual(2, stack.pop()) 90 | XCTAssertEqual(1, stack.pop()) 91 | XCTAssertNil(stack.pop()) 92 | } 93 | 94 | func test_ConcurrentPushes() { 95 | let stack = LockFreeSingleConsumerStack<(thread: Int, value: Int)>() 96 | 97 | let numThreads = 100 98 | let numValues = 10_000 99 | DispatchQueue.concurrentPerform(iterations: numThreads) { thread in 100 | for value in 1 ... numValues { 101 | stack.push((thread: thread, value: value)) 102 | } 103 | } 104 | 105 | var expected: [Int] = Array(repeating: numValues, count: numThreads) 106 | while let (thread, value) = stack.pop() { 107 | XCTAssertEqual(expected[thread], value) 108 | expected[thread] -= 1 109 | } 110 | XCTAssertEqual(Array(repeating: 0, count: numThreads), expected) 111 | } 112 | 113 | func test_ConcurrentPushesAndPops() { 114 | let stack = LockFreeSingleConsumerStack<(thread: Int, value: Int)>() 115 | 116 | let numThreads = 100 117 | let numValues = 10_000 118 | 119 | var perThreadSums: [Int] = Array(repeating: 0, count: numThreads) 120 | let consumerQueue = DispatchQueue(label: "org.swift.background") 121 | consumerQueue.async { 122 | var count = 0 123 | while count < numThreads * numValues { 124 | // Note: busy wait 125 | if let (thread, value) = stack.pop() { 126 | perThreadSums[thread] += value 127 | count += 1 128 | } 129 | } 130 | } 131 | 132 | DispatchQueue.concurrentPerform(iterations: numThreads + 1) { thread in 133 | if thread < numThreads { 134 | // Producers 135 | for value in 0 ..< numValues { 136 | stack.push((thread: thread, value: value)) 137 | } 138 | } 139 | } 140 | 141 | consumerQueue.sync { 142 | XCTAssertEqual(Array(repeating: numValues * (numValues - 1) / 2, count: numThreads), perThreadSums) 143 | } 144 | } 145 | 146 | #if MANUAL_TEST_DISCOVERY 147 | public static var allTests = [ 148 | ("test_Basics", test_Basics), 149 | ("test_ConcurrentPushes", test_ConcurrentPushes), 150 | ("test_ConcurrentPushesAndPops", test_ConcurrentPushesAndPops), 151 | ] 152 | #endif 153 | } 154 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/StrongReferenceShuffle.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | // A lock-free linked list concurrency test. `n` threads are each 14 | // racing on a linked list containing `n` values; in each iteration, 15 | // each thread unlinks its corresponding value then reinserts it at 16 | // the end of the list. 17 | 18 | import XCTest 19 | import Atomics 20 | import Dispatch 21 | 22 | private var iterations: Int { 23 | #if SWIFT_ATOMICS_LONG_TESTS 24 | return 1_000_000 25 | #else 26 | return 50_000 27 | #endif 28 | } 29 | 30 | private let nodeCount = ManagedAtomic(0) 31 | 32 | private class List { 33 | final class Node: AtomicReference { 34 | private let _next: UnsafeAtomic 35 | private let _value: UnsafeAtomic?> 36 | 37 | init(pointer: UnsafeMutablePointer?, next: Node? = nil) { 38 | self._next = .create(next) 39 | self._value = .create(pointer) 40 | nodeCount.wrappingIncrement(ordering: .relaxed) 41 | } 42 | 43 | convenience init(_ value: Value?, next: Node? = nil) { 44 | if let value = value { 45 | let p = UnsafeMutablePointer.allocate(capacity: 1) 46 | p.initialize(to: value) 47 | self.init(pointer: p, next: next) 48 | } else { 49 | self.init(pointer: nil, next: next) 50 | } 51 | } 52 | 53 | deinit { 54 | // Prevent stack overflow when deinitializing a long chain 55 | var node = self._next.destroy() 56 | while node != nil && isKnownUniquelyReferenced(&node) { 57 | let next = node!._next.exchange(nil, ordering: .relaxed) 58 | withExtendedLifetime(node) {} 59 | node = next 60 | } 61 | 62 | if let p = self._value.destroy() { 63 | p.deinitialize(count: 1) 64 | p.deallocate() 65 | } 66 | nodeCount.wrappingDecrement(ordering: .relaxed) 67 | } 68 | 69 | var value: Value? { _value.load(ordering: .sequentiallyConsistent)?.pointee } 70 | 71 | func clearValue() -> UnsafeMutablePointer? { 72 | withExtendedLifetime(self) { 73 | _value.exchange(nil, ordering: .sequentiallyConsistent) 74 | } 75 | } 76 | 77 | var next: Node? { _next.load(ordering: .sequentiallyConsistent) } 78 | 79 | func clearNext() -> Node? { 80 | withExtendedLifetime(self) { 81 | _next.exchange(nil, ordering: .sequentiallyConsistent) 82 | } 83 | } 84 | 85 | func compareExchangeNext(expected: Node?, desired: Node?) -> (exchanged: Bool, original: Node?) { 86 | withExtendedLifetime(self) { 87 | _next.compareExchange(expected: expected, desired: desired, ordering: .sequentiallyConsistent) 88 | } 89 | } 90 | } 91 | 92 | let head: Node 93 | 94 | init(from elements: Elements) 95 | where Elements.Element == Value { 96 | var n: Node? = nil 97 | for value in elements.reversed() { 98 | n = Node(value, next: n) 99 | } 100 | self.head = Node(nil, next: n) 101 | } 102 | 103 | deinit { 104 | // Prevent a stack overflow while recursively releasing list nodes. 105 | var node = head.clearNext() 106 | while let n = node { 107 | let next = n.clearNext() 108 | node = next 109 | } 110 | } 111 | } 112 | 113 | extension List { 114 | /// Move the given value to the end of this list. It is safe to call 115 | /// this concurrently on multiple threads as long as all invocations 116 | /// are using distinct values. 117 | func sink(_ value: Value) { 118 | var current = self.head 119 | var next = self.head.next 120 | var anchor = current 121 | var anchorNext = next 122 | var found = false 123 | 124 | var new: Node? 125 | while true { 126 | if let n = next { 127 | var v = n.value 128 | if !found, v == value { 129 | // Mark this node as deleted. 130 | found = true 131 | new = Node(pointer: n.clearValue(), next: nil) 132 | precondition(new?.value == value, "Concurrent sink invocations with the same value") 133 | v = nil 134 | } 135 | current = n 136 | next = n.next 137 | if v != nil { 138 | if current !== anchor { 139 | // Opportunistically unlink the chain of deleted nodes between `anchor` and `n`. 140 | _ = anchor.compareExchangeNext(expected: anchorNext, desired: n) 141 | } 142 | anchor = current 143 | anchorNext = next 144 | } 145 | } else { 146 | // `next` is nil. Append `new` to the end of the list. 147 | precondition(found, "Lost value \(value) in \(read())") 148 | let (exchanged, original) = current.compareExchangeNext(expected: nil, desired: new) 149 | if exchanged { 150 | if current !== anchor { 151 | // Opportunistically unlink the chain of deleted nodes between `anchor` and `new`. 152 | _ = anchor.compareExchangeNext(expected: anchorNext, desired: new) 153 | } 154 | return 155 | } 156 | next = original 157 | } 158 | } 159 | } 160 | 161 | /// Read out and return the contents of this list in an array. Note 162 | /// that this may return duplicate or missing elements if it is 163 | /// called concurrently with `sink`. (This is still safe -- the 164 | /// results may be useless, but the returned values are still 165 | /// valid.) 166 | @inline(never) 167 | func read() -> [Value?] { 168 | var result: [Value?] = [] 169 | var node = head 170 | while let next = node.next { 171 | result.append(next.value) 172 | node = next 173 | } 174 | withExtendedLifetime(node) {} 175 | return result 176 | } 177 | } 178 | 179 | extension List where Value: Hashable { 180 | @inline(never) 181 | func readUnique(expectedCount: Int = 0) -> Set { 182 | var result: Set = [] 183 | result.reserveCapacity(expectedCount) 184 | var node = head 185 | while let next = node.next { 186 | if let value = next.value { 187 | result.insert(value) 188 | } 189 | node = next 190 | } 191 | withExtendedLifetime(node) {} 192 | return result 193 | } 194 | } 195 | 196 | 197 | class StrongReferenceShuffleTests: XCTestCase { 198 | override func tearDown() { 199 | XCTAssertEqual(nodeCount.load(ordering: .relaxed), 0) 200 | } 201 | 202 | func checkSink( 203 | writers: Int, 204 | readers: Int, 205 | iterations: Int, 206 | file: StaticString = #file, 207 | line: UInt = #line 208 | ) { 209 | let list = List(from: 0 ..< writers) 210 | 211 | XCTAssertEqual(list.read(), Array(0 ..< writers), 212 | "Unexpected list contents at start", 213 | file: file, line: line) 214 | 215 | DispatchQueue.concurrentPerform(iterations: readers + writers) { id in 216 | if id < writers { 217 | for _ in 0 ..< iterations { 218 | list.sink(id) 219 | } 220 | } else { 221 | for _ in 0 ..< iterations { 222 | let elements = list.readUnique(expectedCount: writers) 223 | precondition(elements.count <= writers) 224 | } 225 | } 226 | } 227 | 228 | let contents = list.read() 229 | print( 230 | contents 231 | .map { value -> String in 232 | if let value = value { return "\(value)" } 233 | return "nil" 234 | } 235 | .joined(separator: ", ")) 236 | let values = Set(contents.compactMap { $0 }) 237 | XCTAssertEqual(values, Set(0 ..< writers), 238 | "Unexpected list contents at end", 239 | file: file, line: line) 240 | } 241 | 242 | func test_sink_01_00() { checkSink(writers: 1, readers: 0, iterations: iterations) } 243 | func test_sink_02_00() { checkSink(writers: 2, readers: 0, iterations: iterations) } 244 | func test_sink_04_00() { checkSink(writers: 4, readers: 0, iterations: iterations) } 245 | func test_sink_08_00() { checkSink(writers: 8, readers: 0, iterations: iterations) } 246 | 247 | func test_sink_01_01() { checkSink(writers: 1, readers: 1, iterations: iterations) } 248 | func test_sink_02_01() { checkSink(writers: 2, readers: 1, iterations: iterations) } 249 | func test_sink_04_01() { checkSink(writers: 4, readers: 1, iterations: iterations) } 250 | func test_sink_08_01() { checkSink(writers: 8, readers: 1, iterations: iterations) } 251 | 252 | func test_sink_01_02() { checkSink(writers: 1, readers: 2, iterations: iterations) } 253 | func test_sink_02_02() { checkSink(writers: 2, readers: 2, iterations: iterations) } 254 | func test_sink_04_02() { checkSink(writers: 4, readers: 2, iterations: iterations) } 255 | func test_sink_08_02() { checkSink(writers: 8, readers: 2, iterations: iterations) } 256 | 257 | func test_sink_01_04() { checkSink(writers: 1, readers: 4, iterations: iterations) } 258 | func test_sink_02_04() { checkSink(writers: 2, readers: 4, iterations: iterations) } 259 | func test_sink_04_04() { checkSink(writers: 4, readers: 4, iterations: iterations) } 260 | func test_sink_08_04() { checkSink(writers: 8, readers: 4, iterations: iterations) } 261 | 262 | func test_sink_01_08() { checkSink(writers: 1, readers: 8, iterations: iterations) } 263 | func test_sink_02_08() { checkSink(writers: 2, readers: 8, iterations: iterations) } 264 | func test_sink_04_08() { checkSink(writers: 4, readers: 8, iterations: iterations) } 265 | func test_sink_08_08() { checkSink(writers: 8, readers: 8, iterations: iterations) } 266 | 267 | #if MANUAL_TEST_DISCOVERY 268 | public static var allTests = [ 269 | ("test_sink_01_00", test_sink_01_00), 270 | ("test_sink_02_00", test_sink_02_00), 271 | ("test_sink_04_00", test_sink_04_00), 272 | ("test_sink_08_00", test_sink_08_00), 273 | ("test_sink_01_01", test_sink_01_01), 274 | ("test_sink_02_01", test_sink_02_01), 275 | ("test_sink_04_01", test_sink_04_01), 276 | ("test_sink_08_01", test_sink_08_01), 277 | ("test_sink_01_02", test_sink_01_02), 278 | ("test_sink_02_02", test_sink_02_02), 279 | ("test_sink_04_02", test_sink_04_02), 280 | ("test_sink_08_02", test_sink_08_02), 281 | ("test_sink_01_04", test_sink_01_04), 282 | ("test_sink_02_04", test_sink_02_04), 283 | ("test_sink_04_04", test_sink_04_04), 284 | ("test_sink_08_04", test_sink_08_04), 285 | ("test_sink_01_08", test_sink_01_08), 286 | ("test_sink_02_08", test_sink_02_08), 287 | ("test_sink_04_08", test_sink_04_08), 288 | ("test_sink_08_08", test_sink_08_08), 289 | ] 290 | #endif 291 | } 292 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/StrongReferenceSubclass.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | import Atomics 14 | import XCTest 15 | 16 | private class Base: AtomicReference { 17 | let value: Int 18 | 19 | init(_ value: Int) { 20 | self.value = value 21 | } 22 | } 23 | 24 | private class Child: Base {} 25 | private class Grandchild: Child {} 26 | 27 | class StrongReferenceSubclass: XCTestCase { 28 | func test_base_unsafe() { 29 | let object = Child(42) 30 | let v = UnsafeAtomic.create(object) 31 | 32 | XCTAssertTrue(v.load(ordering: .relaxed) === object) 33 | 34 | let object2 = Grandchild(23) 35 | let o = v.exchange(object2, ordering: .relaxed) 36 | XCTAssertTrue(o === object) 37 | 38 | XCTAssertTrue(v.load(ordering: .relaxed) === object2) 39 | 40 | let r = v.destroy() 41 | XCTAssertTrue(r === object2) 42 | } 43 | 44 | func test_base_managed() { 45 | let object = Child(42) 46 | let v = ManagedAtomic(object) 47 | 48 | XCTAssertTrue(v.load(ordering: .relaxed) === object) 49 | 50 | let object2 = Grandchild(23) 51 | let o = v.exchange(object2, ordering: .relaxed) 52 | XCTAssertTrue(o === object) 53 | 54 | XCTAssertTrue(v.load(ordering: .relaxed) === object2) 55 | } 56 | 57 | func test_optional_base_unsafe() { 58 | let v = UnsafeAtomic.create(nil) 59 | 60 | XCTAssertTrue(v.load(ordering: .relaxed) == nil) 61 | 62 | let object = Grandchild(23) 63 | let o = v.exchange(object, ordering: .relaxed) 64 | XCTAssertTrue(o == nil) 65 | 66 | XCTAssertTrue(v.load(ordering: .relaxed) === object) 67 | 68 | let r = v.destroy() 69 | XCTAssertTrue(r === object) 70 | } 71 | 72 | func test_optional_base_managed() { 73 | let v = ManagedAtomic(nil) 74 | 75 | XCTAssertTrue(v.load(ordering: .relaxed) == nil) 76 | 77 | let object = Grandchild(23) 78 | let o = v.exchange(object, ordering: .relaxed) 79 | XCTAssertTrue(o == nil) 80 | 81 | XCTAssertTrue(v.load(ordering: .relaxed) === object) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Tests/AtomicsTests/main.swift: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2021 - 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #if MANUAL_TEST_DISCOVERY 14 | import XCTest 15 | 16 | var testCases = [ 17 | // Basics 18 | testCase(BasicAtomicBoolTests.allTests), 19 | testCase(BasicAtomicDoubleWordTests.allTests), 20 | testCase(BasicAtomicInt16Tests.allTests), 21 | testCase(BasicAtomicInt32Tests.allTests), 22 | testCase(BasicAtomicInt64Tests.allTests), 23 | testCase(BasicAtomicInt8Tests.allTests), 24 | testCase(BasicAtomicIntTests.allTests), 25 | testCase(BasicAtomicMutablePointerTests.allTests), 26 | testCase(BasicAtomicMutableRawPointerTests.allTests), 27 | testCase(BasicAtomicOptionalMutablePointerTests.allTests), 28 | testCase(BasicAtomicOptionalMutableRawPointerTests.allTests), 29 | testCase(BasicAtomicOptionalPointerTests.allTests), 30 | testCase(BasicAtomicOptionalRawPointerTests.allTests), 31 | testCase(BasicAtomicOptionalReferenceTests.allTests), 32 | testCase(BasicAtomicOptionalUnmanagedTests.allTests), 33 | testCase(BasicAtomicPointerTests.allTests), 34 | testCase(BasicAtomicRawPointerTests.allTests), 35 | testCase(BasicAtomicRawRepresentableTests.allTests), 36 | testCase(BasicAtomicReferenceTests.allTests), 37 | testCase(BasicAtomicUInt16Tests.allTests), 38 | testCase(BasicAtomicUInt32Tests.allTests), 39 | testCase(BasicAtomicUInt64Tests.allTests), 40 | testCase(BasicAtomicUInt8Tests.allTests), 41 | testCase(BasicAtomicUIntTests.allTests), 42 | testCase(BasicAtomicUnmanagedTests.allTests), 43 | 44 | testCase(LockFreeSingleConsumerStackTests.allTests), 45 | testCase(DoubleWordTests.allTests), 46 | testCase(AtomicLazyReferenceTests.allTests), 47 | testCase(QueueTests.allTests), 48 | testCase(StrongReferenceRace.allTests), 49 | testCase(StrongReferenceShuffleTests.allTests), 50 | ] 51 | 52 | XCTMain(testCases) 53 | #endif 54 | -------------------------------------------------------------------------------- /Tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | This source file is part of the Swift Atomics Open Source Project 3 | 4 | Copyright (c) 2021 - 2023 Apple Inc. and the Swift project authors 5 | Licensed under Apache License v2.0 with Runtime Library Exception 6 | 7 | See https://swift.org/LICENSE.txt for license information 8 | #]] 9 | 10 | if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) # FIXME Hook this up on Darwin 11 | find_package(dispatch CONFIG) 12 | find_package(Foundation CONFIG) 13 | find_package(XCTest CONFIG) 14 | 15 | add_executable(AtomicsTestBundle 16 | AtomicsTests/main.swift 17 | AtomicsTests/AtomicLazyReference.swift 18 | AtomicsTests/Basics/BasicTestSupport.swift 19 | AtomicsTests/Basics/autogenerated/BasicAtomicBoolTests.swift 20 | AtomicsTests/Basics/autogenerated/BasicAtomicDoubleWordTests.swift 21 | AtomicsTests/Basics/autogenerated/BasicAtomicInt16Tests.swift 22 | AtomicsTests/Basics/autogenerated/BasicAtomicInt32Tests.swift 23 | AtomicsTests/Basics/autogenerated/BasicAtomicInt64Tests.swift 24 | AtomicsTests/Basics/autogenerated/BasicAtomicInt8Tests.swift 25 | AtomicsTests/Basics/autogenerated/BasicAtomicIntTests.swift 26 | AtomicsTests/Basics/autogenerated/BasicAtomicMutablePointerTests.swift 27 | AtomicsTests/Basics/autogenerated/BasicAtomicMutableRawPointerTests.swift 28 | AtomicsTests/Basics/autogenerated/BasicAtomicOptionalMutablePointerTests.swift 29 | AtomicsTests/Basics/autogenerated/BasicAtomicOptionalMutableRawPointerTests.swift 30 | AtomicsTests/Basics/autogenerated/BasicAtomicOptionalPointerTests.swift 31 | AtomicsTests/Basics/autogenerated/BasicAtomicOptionalRawPointerTests.swift 32 | AtomicsTests/Basics/autogenerated/BasicAtomicOptionalRawRepresentableTests.swift 33 | AtomicsTests/Basics/autogenerated/BasicAtomicOptionalReferenceTests.swift 34 | AtomicsTests/Basics/autogenerated/BasicAtomicOptionalUnmanagedTests.swift 35 | AtomicsTests/Basics/autogenerated/BasicAtomicPointerTests.swift 36 | AtomicsTests/Basics/autogenerated/BasicAtomicRawPointerTests.swift 37 | AtomicsTests/Basics/autogenerated/BasicAtomicRawRepresentableTests.swift 38 | AtomicsTests/Basics/autogenerated/BasicAtomicReferenceTests.swift 39 | AtomicsTests/Basics/autogenerated/BasicAtomicUInt16Tests.swift 40 | AtomicsTests/Basics/autogenerated/BasicAtomicUInt32Tests.swift 41 | AtomicsTests/Basics/autogenerated/BasicAtomicUInt64Tests.swift 42 | AtomicsTests/Basics/autogenerated/BasicAtomicUInt8Tests.swift 43 | AtomicsTests/Basics/autogenerated/BasicAtomicUIntTests.swift 44 | AtomicsTests/Basics/autogenerated/BasicAtomicUnmanagedTests.swift 45 | AtomicsTests/DoubleWord.swift 46 | AtomicsTests/LifetimeTracked.swift 47 | AtomicsTests/LockFreeQueue.swift 48 | AtomicsTests/LockFreeSingleConsumerStack.swift 49 | AtomicsTests/StrongReferenceRace.swift 50 | AtomicsTests/StrongReferenceShuffle.swift 51 | AtomicsTests/StrongReferenceSubclass.swift) 52 | 53 | target_compile_options(AtomicsTestBundle PRIVATE "-DMANUAL_TEST_DISCOVERY") 54 | 55 | target_link_libraries(AtomicsTestBundle PRIVATE 56 | Atomics 57 | XCTest 58 | dispatch 59 | Foundation) 60 | 61 | add_test(NAME SwiftAtomics 62 | COMMAND AtomicsTestBundle) 63 | endif() 64 | -------------------------------------------------------------------------------- /Tests/lit/UnsafeAtomicInitializers.swift.gyb: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2020 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | // 11 | //===----------------------------------------------------------------------===// 12 | // RUN: %empty-directory(%t) 13 | // RUN: %gyb %s -o %t/UnsafeAtomicInitializers.swift 14 | // RUN: %line-directive %t/UnsafeAtomicInitializers.swift -- %target-swift-frontend -typecheck -verify %t/UnsafeAtomicInitializers.swift 15 | 16 | %{ 17 | from gyb_utils import autogenerated_warning 18 | 19 | types = [ 20 | # id type initial 21 | ("Int", "Int", "0"), 22 | ("Int64", "Int64", "0"), 23 | ("Int32", "Int32", "0"), 24 | ("Int16", "Int16", "0"), 25 | ("Int8", "Int8", "0"), 26 | ("UInt", "UInt", "0"), 27 | ("UInt64", "UInt64", "0"), 28 | ("UInt32", "UInt32", "0"), 29 | ("UInt16", "UInt16", "0"), 30 | ("UInt8", "UInt8", "0"), 31 | 32 | # id type initial 33 | ("URP", "UnsafeRawPointer", "UnsafeRawPointer(UnsafeMutableRawPointer.allocate(byteCount: 8, alignment: 8))"), 34 | ("UP", "UnsafePointer", "UnsafePointer(UnsafeMutablePointer.allocate(capacity: 1))"), 35 | ("UMRP", "UnsafeMutableRawPointer", ".allocate(byteCount: 8, alignment: 8)"), 36 | ("UMP", "UnsafeMutablePointer", ".allocate(capacity: 1)"), 37 | ("Unmanaged", "Unmanaged", "Unmanaged.passRetained(Foo())"), 38 | 39 | # id type initial 40 | ("URPOpt", "UnsafeRawPointer?", "nil"), 41 | ("UPOpt", "UnsafePointer?", "nil"), 42 | ("UMRPOpt", "UnsafeMutableRawPointer?", "nil"), 43 | ("UMPOpt", "UnsafeMutablePointer?", "nil"), 44 | ("UnmanagedOpt", "Unmanaged?", "nil"), 45 | ] 46 | }% 47 | ${autogenerated_warning()} 48 | 49 | import Atomics 50 | 51 | class Foo { 52 | var value = 0 53 | } 54 | struct Bar { 55 | var value = 0 56 | } 57 | 58 | % for (id, type, initial) in types: 59 | func test_${id}() -> UnsafeAtomic<${type}> { 60 | var storage = UnsafeAtomic<${type}>.Storage(${initial}) 61 | let atomic = UnsafeAtomic<${type}>(at: &storage) // expected-warning {{inout expression creates a temporary pointer, but argument 'at' should be a pointer that outlives the call to 'init(at:)'}} 62 | // expected-note@-1 {{implicit argument conversion from 'UnsafeAtomic<${type}>.Storage' to 'UnsafeMutablePointer.Storage>' produces a pointer valid only for the duration of the call to 'init(at:)'}} 63 | // expected-note@-2 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}} 64 | return atomic 65 | } 66 | % end 67 | 68 | func test_UnsafeAtomicLazyReference() -> UnsafeAtomicLazyReference { 69 | var value = UnsafeAtomicLazyReference.Storage() 70 | let atomic = UnsafeAtomicLazyReference(at: &value) // expected-warning {{inout expression creates a temporary pointer, but argument 'at' should be a pointer that outlives the call to 'init(at:)'}} 71 | // expected-note@-1 {{implicit argument conversion from 'UnsafeAtomicLazyReference.Storage' to 'UnsafeMutablePointer.Storage>' produces a pointer valid only for the duration of the call to 'init(at:)'}} 72 | // expected-note@-2 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}} 73 | return atomic 74 | } 75 | 76 | class BrokenAtomicCounter { // THIS IS BROKEN; DO NOT USE 77 | private var _storage = UnsafeAtomic.Storage(0) 78 | private var _value: UnsafeAtomic? 79 | 80 | init() { 81 | // This escapes the ephemeral pointer generated by the inout expression, 82 | // so it leads to undefined behavior when the pointer gets dereferenced 83 | // in the atomic operations below. DO NOT DO THIS. 84 | _value = UnsafeAtomic(at: &_storage) // expected-warning {{inout expression creates a temporary pointer, but argument 'at' should be a pointer that outlives the call to 'init(at:)'}} 85 | // expected-note@-1 {{implicit argument conversion from 'UnsafeAtomic.Storage' to 'UnsafeMutablePointer.Storage>' produces a pointer valid only for the duration of the call to 'init(at:)'}} 86 | // expected-note@-2 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}} 87 | } 88 | 89 | func increment() { 90 | _value!.wrappingIncrement(by: 1, ordering: .relaxed) 91 | } 92 | 93 | func get() -> Int { 94 | _value!.load(ordering: .relaxed) 95 | } 96 | } 97 | 98 | struct AtomicCounter { 99 | typealias Value = Int 100 | typealias Header = UnsafeAtomic.Storage 101 | 102 | class Buffer: ManagedBuffer { 103 | deinit { 104 | withUnsafeMutablePointerToHeader { header in 105 | _ = header.pointee.dispose() 106 | } 107 | } 108 | } 109 | 110 | let buffer: Buffer 111 | 112 | init() { 113 | buffer = Buffer.create(minimumCapacity: 0) { _ in 114 | Header(0) 115 | } as! Buffer 116 | } 117 | 118 | private func _withAtomicPointer( 119 | _ body: (UnsafeAtomic) throws -> R 120 | ) rethrows -> R { 121 | try buffer.withUnsafeMutablePointerToHeader { header in 122 | try body(UnsafeAtomic(at: header)) 123 | } 124 | } 125 | 126 | func increment() { 127 | _withAtomicPointer { $0.wrappingIncrement(ordering: .relaxed) } 128 | } 129 | 130 | func load() -> Int { 131 | _withAtomicPointer { $0.load(ordering: .relaxed) } 132 | } 133 | } 134 | 135 | struct AtomicUnmanagedRef { 136 | typealias Value = Unmanaged? 137 | typealias Header = UnsafeAtomic.Storage 138 | 139 | class Buffer: ManagedBuffer { 140 | deinit { 141 | withUnsafeMutablePointerToHeader { header in 142 | _ = header.pointee.dispose() 143 | } 144 | } 145 | } 146 | 147 | let buffer: Buffer 148 | 149 | init() { 150 | buffer = Buffer.create(minimumCapacity: 0) { _ in 151 | Header(nil) 152 | } as! Buffer 153 | } 154 | 155 | private func _withAtomicPointer( 156 | _ body: (UnsafeAtomic) throws -> R 157 | ) rethrows -> R { 158 | try buffer.withUnsafeMutablePointerToHeader { header in 159 | try body(UnsafeAtomic(at: header)) 160 | } 161 | } 162 | 163 | func store(_ desired: Value) { 164 | _withAtomicPointer { $0.store(desired, ordering: .sequentiallyConsistent) } 165 | } 166 | 167 | func load() -> Value { 168 | _withAtomicPointer { $0.load(ordering: .sequentiallyConsistent) } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /Utilities/generate-sources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #===----------------------------------------------------------------------===// 3 | # 4 | # This source file is part of the Swift.org open source project 5 | # 6 | # Copyright (c) 2020 - 2023 Apple Inc. and the Swift project authors 7 | # Licensed under Apache License v2.0 with Runtime Library Exception 8 | # 9 | # See https://swift.org/LICENSE.txt for license information 10 | # See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 11 | # 12 | #===----------------------------------------------------------------------===// 13 | 14 | set -eu 15 | 16 | srcroot="$(dirname "$0")/.." 17 | cd "$srcroot" 18 | 19 | gyb="./Utilities/gyb" 20 | 21 | # Disable line directives in gyb output. We commit generated sources 22 | # into the package repository, so we do not want absolute file names 23 | # in them. 24 | lineDirective='' 25 | 26 | # Uncomment the following line to enable #sourceLocation directives. 27 | # This is useful for local development. 28 | #lineDirective='#sourceLocation(file: "%(file)s", line: %(line)d)' 29 | 30 | 31 | # Create a temporary directory; remove it on exit. 32 | tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/$(basename "$0").XXXXXXXX")" 33 | trap "rm -rf \"$tmpdir\"" EXIT 34 | 35 | # Run gyb on each gyb file in the source tree and put results in 36 | # subdirectories named 'autogenerated'. 37 | find ./Sources ./Tests -name "*.gyb" | while read input; do 38 | basename="$(basename "$input")" 39 | targetdir="$(dirname "$input")/autogenerated" 40 | output="$targetdir/"${basename%.gyb} 41 | tmpfile="$tmpdir/${basename%.gyb}" 42 | 43 | # Make sure the output directory exists. 44 | mkdir -p "$targetdir" 45 | 46 | # Run gyb, making sure to only update files when they change. 47 | "$gyb" --line-directive "$lineDirective" -o "$tmpfile" "$input" 48 | if [ -e "$output" ] && cmp -s "$tmpfile" "$output"; then 49 | : Ignore unchanged file 50 | else 51 | echo "Updated $output" 52 | cp "$tmpfile" "$output" 53 | fi 54 | echo "$output" >> "$tmpdir/generated-files.txt" 55 | done 56 | 57 | # Remove autogenerated files without a corresponding gyb. 58 | find . -path '*/autogenerated/*.swift' >> "$tmpdir/generated-files.txt" 59 | sort "$tmpdir/generated-files.txt" | uniq -u | while read obsolete; do 60 | echo "Removing $obsolete" 61 | rm "$obsolete" 62 | done 63 | -------------------------------------------------------------------------------- /Utilities/gyb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import gyb 3 | gyb.main() 4 | -------------------------------------------------------------------------------- /Utilities/gyb_utils.py: -------------------------------------------------------------------------------- 1 | #===-----------------------------------------------------------------------===// 2 | # 3 | # This source file is part of the Swift.org open source project 4 | # 5 | # Copyright (c) 2020 - 2025 Apple Inc. and the Swift project authors 6 | # Licensed under Apache License v2.0 with Runtime Library Exception 7 | # 8 | # See https://swift.org/LICENSE.txt for license information 9 | # See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 10 | # 11 | #===-----------------------------------------------------------------------===// 12 | 13 | def autogenerated_warning(): 14 | return """ 15 | // ############################################################################# 16 | // # # 17 | // # DO NOT EDIT THIS FILE; IT IS AUTOGENERATED. # 18 | // # # 19 | // ############################################################################# 20 | """ 21 | 22 | cPrimitives = [ 23 | #Storage Value 24 | ("_AtomicInt8Storage", "Int8"), 25 | ("_AtomicInt16Storage", "Int16"), 26 | ("_AtomicInt32Storage", "Int32"), 27 | ("_AtomicInt64Storage", "Int64"), 28 | ("_AtomicIntStorage", "Int"), 29 | ("_AtomicDoubleWordStorage", "DoubleWord"), 30 | ] 31 | 32 | nativePrimitives = [ 33 | #Storage Builtin Alignment 34 | ("_AtomicInt8Storage", "Int8", "1"), 35 | ("_AtomicInt16Storage", "Int16", "2"), 36 | ("_AtomicInt32Storage", "Int32", "4"), 37 | ("_AtomicInt64Storage", "Int64", "8"), 38 | ("_AtomicInt128Storage", "Int128", "16"), 39 | ] 40 | 41 | loadOrderings = [ 42 | # Swift enum case, API name, doc name, llvm name 43 | ('relaxed', 'Relaxed', 'relaxed', 'monotonic'), 44 | ('acquiring', 'Acquiring', 'acquiring', 'acquire'), 45 | ('sequentiallyConsistent', 'SequentiallyConsistent', 'sequentially consistent', 'seqcst'), 46 | ] 47 | 48 | storeOrderings = [ 49 | # Swift enum case, API name, doc name, llvm name 50 | ('relaxed', 'Relaxed', 'relaxed', 'monotonic'), 51 | ('releasing', 'Releasing', 'releasing', 'release'), 52 | ('sequentiallyConsistent', 'SequentiallyConsistent', 'sequentially consistent', 'seqcst'), 53 | ] 54 | 55 | updateOrderings = [ 56 | # Swift enum case, API name, documentation name, llvm name, failure name 57 | ('relaxed', 'Relaxed', 'relaxed', 'monotonic', 'monotonic'), 58 | ('acquiring', 'Acquiring', 'acquiring', 'acquire', 'acquire'), 59 | ('releasing', 'Releasing', 'releasing', 'release', 'monotonic'), 60 | ('acquiringAndReleasing', 'AcquiringAndReleasing', 'acquiring-and-releasing', 'acqrel', 'acquire'), 61 | ('sequentiallyConsistent', 'SequentiallyConsistent', 'sequentially consistent', 'seqcst', 'seqcst'), 62 | ] 63 | 64 | def shim_name(llvmOrdering): 65 | if llvmOrdering == 'monotonic': 66 | return "relaxed" 67 | if llvmOrdering == 'acquire': 68 | return "acquire" 69 | if llvmOrdering == 'release': 70 | return "release" 71 | if llvmOrdering == 'acqrel': 72 | return "acq_rel" 73 | if llvmOrdering == 'seqcst': 74 | return "seq_cst" 75 | raise ValueError("Unknown ordering " + llvmOrdering) 76 | 77 | def isStrongerThan(rmw, load): # See llvm/Support/AtomicOrdering.h 78 | if rmw == "sequentiallyConsistent": 79 | return load == "relaxed" or load == "acquiring" 80 | if rmw == "acquiringAndReleasing": 81 | return load == "relaxed" 82 | if rmw == "releasing": 83 | return False 84 | if rmw == "acquiring": 85 | return load == "relaxed" 86 | if rmw == "relaxed": 87 | return False 88 | 89 | def failureOrderingOf(update): 90 | if update == "release": 91 | return "monotonic" 92 | if update == "acqrel": 93 | return "acquire" 94 | return update 95 | 96 | # LLVM doesn't support arbitrary ordering combinations yet, so for the 97 | # two-ordering cmpxchg variants we need to upgrade the success 98 | # ordering when necessary so that it is at least as "strong" as the 99 | # failure case. This function implements that mapping. 100 | # 101 | # See llvm/Support/AtomicOrdering.h 102 | def actualOrders(success, failure): 103 | def max(success, failure): 104 | if failure == "acquire": 105 | if success == "monotonic": 106 | return "acquire" 107 | if success == "release": 108 | return "acqrel" 109 | if failure == "seqcst": 110 | return "seqcst" 111 | return success 112 | actualSuccess = max(success, failure) 113 | return actualSuccess + "_" + failure 114 | 115 | def actualShimOrders(success, failure): 116 | r=actualOrders(success, failure).split("_") 117 | return shim_name(r[0]) + "_" + shim_name(r[1]) 118 | 119 | integerOperations = [ 120 | # Swift name, llvm name, operator, label, doc 121 | ('WrappingIncrement', 'add', '&+', "by", "wrapping add"), 122 | ('WrappingDecrement', 'sub', '&-', "by", "wrapping subtract"), 123 | ('BitwiseAnd', 'and', '&', "with", "bitwise AND"), 124 | ('BitwiseOr', 'or', '|', "with", "bitwise OR"), 125 | ('BitwiseXor', 'xor', '^', "with", "bitwise XOR") 126 | ] 127 | 128 | boolOperations = [ 129 | # Swift name, Int8 name, operator, label, doc 130 | ('LogicalAnd', 'BitwiseAnd', '&&', "with", "logical AND"), 131 | ('LogicalOr', 'BitwiseOr', '||', "with", "logical OR"), 132 | ('LogicalXor', 'BitwiseXor', '!=', "with", "logical XOR") 133 | ] 134 | 135 | def lowerFirst(str): 136 | return str[:1].lower() + str[1:] if str else "" 137 | 138 | def argLabel(label): 139 | return label + ": " if label != "_" else "" 140 | -------------------------------------------------------------------------------- /Utilities/run-full-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #===---------------------------------------------------------------------- 3 | # 4 | # This source file is part of the Swift Atomics open source project 5 | # 6 | # Copyright (c) 2021 - 2023 Apple Inc. and the Swift project authors 7 | # Licensed under Apache License v2.0 with Runtime Library Exception 8 | # 9 | # See https://swift.org/LICENSE.txt for license information 10 | # 11 | #===---------------------------------------------------------------------- 12 | 13 | # Build & test this package in as many configurations as possible. 14 | # It is a good idea to run this script before each release to uncover 15 | # potential problems not covered by the usual CI runs. 16 | # 17 | # Note that this is not a fully automated solution -- some manual editing will 18 | # sometimes be required when e.g. testing the package on older Xcode releases. 19 | 20 | set -eu 21 | 22 | cd "$(dirname $0)/.." 23 | 24 | build_dir="$(mktemp -d "/tmp/$(basename $0).XXXXX")" 25 | 26 | bold_on="$(tput bold)" 27 | bold_off="$(tput sgr0)" 28 | 29 | red_on="$(tput setaf 1)" 30 | red_off="$(tput sgr0)" 31 | 32 | spm_flags="" 33 | 34 | if [ "$(uname)" = "Darwin" ]; then 35 | swift="xcrun swift" 36 | else 37 | swift="swift" 38 | spm_flags="$spm_flags -j 1" 39 | fi 40 | 41 | echo "Build output logs are saved in $bold_on$build_dir$bold_off" 42 | $swift --version 43 | 44 | report_failure() { 45 | logs="$1" 46 | } 47 | 48 | _count=0 49 | try() { 50 | label="$1" 51 | shift 52 | _count=$(($_count + 1)) 53 | count="$(printf "%02d" $_count)" 54 | output="$build_dir/$count.$label.log" 55 | echo "$bold_on[$count $label]$bold_off $@" 56 | start="$(date +%s)" 57 | if "$@" >"$output" 2>&1; then 58 | end="$(date +%s)" 59 | echo " Completed in $(($end - $start))s" 60 | else 61 | end="$(date +%s)" 62 | echo " ${red_on}${bold_on}Failed in $(($end - $start))s.${bold_off}${red_off}" \ 63 | "${red_on}See $output for full console output.${red_off}" 64 | tail -10 "$output" | sed 's/^/ /' 65 | fi 66 | } 67 | 68 | # Build using SPM 69 | try "spm.debug.build" $swift build -c debug $spm_flags --build-path "$build_dir/spm.debug" 70 | try "spm.release.build" $swift build -c release $spm_flags --build-path "$build_dir/spm.release" 71 | # Build with CMake 72 | cmake_debug_build_dir="$build_dir/cmake.debug" 73 | try "cmake.debug.generate" cmake -S . -B "$cmake_debug_build_dir" -G Ninja -DCMAKE_BUILD_TYPE=DEBUG 74 | try "cmake.debug.build-with-ninja" ninja -C "$cmake_debug_build_dir" 75 | 76 | cmake_release_build_dir="$build_dir/cmake.release" 77 | try "cmake.release.generate" cmake -S . -B "$cmake_release_build_dir" -G Ninja -DCMAKE_BUILD_TYPE=RELEASE 78 | try "cmake.release.build-with-ninja" ninja -C "$cmake_release_build_dir" 79 | 80 | # Build using xcodebuild 81 | try_xcodebuild() { 82 | label="$1" 83 | destination="$2" 84 | shift 2 85 | 86 | try "$label" \ 87 | xcrun xcodebuild -scheme swift-atomics \ 88 | -configuration Release \ 89 | -destination "$destination" \ 90 | -derivedDataPath "$build_dir/xcodebuild" \ 91 | "$@" 92 | } 93 | try_xcodeproj() { 94 | label="$1" 95 | destination="$2" 96 | shift 2 97 | 98 | try "$label" \ 99 | xcrun xcodebuild \ 100 | -configuration Release \ 101 | -destination "$destination" \ 102 | -derivedDataPath "$build_dir/xcodeproj" \ 103 | "$@" 104 | } 105 | 106 | if [ "$(uname)" = "Darwin" ]; then 107 | try_xcodebuild "xcodebuild.build.macOS" "generic/platform=macOS" build 108 | try_xcodebuild "xcodebuild.build.macCatalyst" "generic/platform=macOS,variant=Mac Catalyst" build 109 | try_xcodebuild "xcodebuild.build.iOS" "generic/platform=iOS" build 110 | try_xcodebuild "xcodebuild.build.iOS-simulator" "generic/platform=iOS Simulator" build 111 | try_xcodebuild "xcodebuild.build.watchOS" "generic/platform=watchOS" build 112 | try_xcodebuild "xcodebuild.build.watchOS-simulator" "generic/platform=watchOS Simulator" build 113 | try_xcodebuild "xcodebuild.build.tvOS" "generic/platform=tvOS" build 114 | try_xcodebuild "xcodebuild.build.tvOS-simulator" "generic/platform=tvOS Simulator" build 115 | 116 | try_xcodeproj "xcodeproj.build.macOS" "generic/platform=macOS" -project Xcode/Atomics.xcodeproj -scheme Atomics build 117 | try_xcodeproj "xcodeproj.build.iOS" "generic/platform=iOS" -project Xcode/Atomics.xcodeproj -scheme Atomics build 118 | try_xcodeproj "xcodeproj.build.watchOS" "generic/platform=watchOS" -project Xcode/Atomics.xcodeproj -scheme Atomics build 119 | try_xcodeproj "xcodeproj.build.tvOS" "generic/platform=tvOS" -project Xcode/Atomics.xcodeproj -scheme Atomics build 120 | fi 121 | 122 | # Build with custom configurations 123 | 124 | # Some people like to build their dependencies in warnings-as-errors mode. 125 | try "spm.warnings-as-errors.debug" $swift build -c debug -Xswiftc -warnings-as-errors $spm_flags --build-path "$build_dir/spm.warnings-as-errors" 126 | try "spm.warnings-as-errors.release" $swift build -c release -Xswiftc -warnings-as-errors $spm_flags --build-path "$build_dir/spm.warnings-as-errors" 127 | 128 | # Build with library evolution enabled. (This configuration is 129 | # unsupported, but let's make some effort not to break it.) 130 | if [ "$(uname)" = "Darwin" ]; then 131 | try "spm.library-evolution" \ 132 | $swift build \ 133 | -c release \ 134 | $spm_flags \ 135 | --build-path "$build_dir/spm.library-evolution" \ 136 | -Xswiftc -enable-library-evolution 137 | try "xcodebuild.library-evolution" \ 138 | xcodebuild -scheme swift-atomics \ 139 | -destination "generic/platform=macOS" \ 140 | -destination "generic/platform=iOS" \ 141 | BUILD_LIBRARY_FOR_DISTRIBUTION=YES 142 | fi 143 | 144 | # Run tests 145 | try "spm.debug.test" $swift test -c debug $spm_flags --build-path "$build_dir/spm.debug" 146 | try "spm.release.test" $swift test -c release $spm_flags --build-path "$build_dir/spm.release" 147 | 148 | if [ "$(uname)" != "Darwin" ]; then # We have not hooked up cmake tests on Darwin yet 149 | try "cmake.release.test" "$cmake_release_build_dir/bin/AtomicsTestBundle" 150 | fi 151 | 152 | if [ "$(uname)" = "Darwin" ]; then 153 | try_xcodebuild "xcodebuild.test.macOS" "platform=macOS" test 154 | try_xcodebuild "xcodebuild.test.macCatalyst" "platform=macOS,variant=Mac Catalyst" test 155 | try_xcodebuild "xcodebuild.test.iOS-simulator" "platform=iOS Simulator,name=iPhone 12" test 156 | try_xcodebuild "xcodebuild.test.watchOS-simulator" "platform=watchOS Simulator,name=Apple Watch Series 6 (44mm)" test 157 | try_xcodebuild "xcodebuild.test.tvOS-simulator" "platform=tvOS Simulator,name=Apple TV 4K (at 1080p)" test 158 | 159 | try_xcodeproj "xcodeproj.test.macOS" "platform=macOS" -project Xcode/Atomics.xcodeproj -scheme Atomics test 160 | fi 161 | 162 | # Run long tests 163 | if [ "$(uname)" = "Darwin" ]; then 164 | try "spm.release.test.long" \ 165 | $swift test -c release \ 166 | $spm_flags \ 167 | -Xswiftc -DSWIFT_ATOMICS_LONG_TESTS \ 168 | --build-path "$build_dir/spm.release.test.long" 169 | try "spm.release.test.long+tsan" \ 170 | $swift test -c release \ 171 | $spm_flags \ 172 | --sanitize=thread \ 173 | -Xswiftc -DSWIFT_ATOMICS_LONG_TESTS \ 174 | --build-path "$build_dir/spm.release.test.long+tsan" 175 | try_xcodebuild \ 176 | "xcodebuild.test.macOS.tsan" \ 177 | "platform=macOS" \ 178 | -enableThreadSanitizer YES \ 179 | test 180 | else 181 | try "spm.release.test.long" \ 182 | $swift test -c release \ 183 | $spm_flags \ 184 | -Xswiftc -DSWIFT_ATOMICS_LONG_TESTS \ 185 | --build-path "$build_dir/spm.release.test.long" 186 | try "spm.release.test.long+tsan" \ 187 | $swift test -c release \ 188 | $spm_flags \ 189 | --sanitize=thread \ 190 | -Xswiftc -DSWIFT_ATOMICS_LONG_TESTS \ 191 | --build-path "$build_dir/spm.release.test.long+tsan" 192 | fi 193 | -------------------------------------------------------------------------------- /Xcode/Atomics.xcconfig: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // 10 | //===----------------------------------------------------------------------===// 11 | 12 | PRODUCT_NAME = Atomics 13 | PRODUCT_BUNDLE_IDENTIFIER = org.swift.Atomics 14 | 15 | SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator watchos watchsimulator appletvos appletvsimulator 16 | ARCHS = $(ARCHS_STANDARD) 17 | 18 | MACOSX_DEPLOYMENT_TARGET = 12.0 19 | IPHONEOS_DEPLOYMENT_TARGET = 15.0 20 | WATCHOS_DEPLOYMENT_TARGET = 8.0 21 | TVOS_DEPLOYMENT_TARGET = 15.0 22 | 23 | MARKETING_VERSION = 1.1 24 | 25 | CURRENT_PROJECT_VERSION = 1 26 | VERSIONING_SYSTEM = apple-generic 27 | VERSION_INFO_PREFIX = 28 | DYLIB_COMPATIBILITY_VERSION = $(CURRENT_PROJECT_VERSION) 29 | DYLIB_CURRENT_VERSION = $(CURRENT_PROJECT_VERSION) 30 | 31 | OTHER_SWIFT_FLAGS = $(inherited) -enable-experimental-feature BuiltinModule 32 | 33 | INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks 34 | SKIP_INSTALL = YES 35 | DYLIB_INSTALL_NAME_BASE = @rpath 36 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/Frameworks 37 | 38 | ENABLE_TESTABILITY = NO 39 | ENABLE_TESTABILITY[config=Debug] = YES 40 | 41 | GENERATE_INFOPLIST_FILE = YES 42 | -------------------------------------------------------------------------------- /Xcode/Atomics.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Xcode/Atomics.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Xcode/Atomics.xcodeproj/xcshareddata/xcschemes/Atomics.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 34 | 35 | 36 | 37 | 40 | 46 | 47 | 48 | 49 | 50 | 60 | 61 | 67 | 68 | 74 | 75 | 76 | 77 | 79 | 80 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /Xcode/Atomics.xctestplan: -------------------------------------------------------------------------------- 1 | { 2 | "configurations" : [ 3 | { 4 | "id" : "CF37E70B-D810-4CF2-AB41-571BAFF72572", 5 | "name" : "Default", 6 | "options" : { 7 | 8 | } 9 | }, 10 | { 11 | "id" : "33436295-E24E-439B-9B8E-4602E0A6C8BB", 12 | "name" : "TSan", 13 | "options" : { 14 | "threadSanitizerEnabled" : true 15 | } 16 | } 17 | ], 18 | "defaultOptions" : { 19 | "codeCoverage" : false 20 | }, 21 | "testTargets" : [ 22 | { 23 | "parallelizable" : true, 24 | "target" : { 25 | "containerPath" : "container:Atomics.xcodeproj", 26 | "identifier" : "7D489E4629CE969D00499B21", 27 | "name" : "AtomicsTests" 28 | } 29 | } 30 | ], 31 | "version" : 1 32 | } 33 | -------------------------------------------------------------------------------- /Xcode/AtomicsTests.xcconfig: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // 10 | //===----------------------------------------------------------------------===// 11 | 12 | PRODUCT_NAME = AtomicsTests 13 | PRODUCT_BUNDLE_IDENTIFIER = org.swift.AtomicsTests 14 | 15 | SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator watchos watchsimulator appletvos appletvsimulator 16 | ARCHS = $(ARCHS_STANDARD) 17 | 18 | CURRENT_PROJECT_VERSION = 1 19 | MARKETING_VERSION = 1.0 20 | 21 | GENERATE_INFOPLIST_FILE = YES 22 | 23 | ENABLE_TESTABILITY = NO 24 | -------------------------------------------------------------------------------- /Xcode/README.md: -------------------------------------------------------------------------------- 1 | # Xcode build files 2 | 3 | The project file here can be used to build a variant of this package with Xcode. The project file is a regular Xcode project that builds the code base producing a single framework bundle. Build settings are entirely configured via the provided xcconfig files. 4 | 5 | Beware! The contents of this directory are not source stable. They are provided as is, with no compatibility promises across package releases. Future versions of this package can arbitrarily change these files or remove them, without any advance notice. (This can include patch releases.) 6 | -------------------------------------------------------------------------------- /Xcode/Shared.xcconfig: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This source file is part of the Swift Atomics open source project 4 | // 5 | // Copyright (c) 2023 Apple Inc. and the Swift project authors 6 | // Licensed under Apache License v2.0 with Runtime Library Exception 7 | // 8 | // See https://swift.org/LICENSE.txt for license information 9 | // 10 | //===----------------------------------------------------------------------===// 11 | 12 | SDKROOT = macosx 13 | 14 | CODE_SIGN_STYLE = Automatic 15 | CODE_SIGN_IDENTITY = - 16 | CODE_SIGN_IDENTITY[sdk=iphoneos*] = "iOS Developer" 17 | CODE_SIGN_IDENTITY[sdk=watchos*] = "iOS Developer" 18 | CODE_SIGN_IDENTITY[sdk=appletvos*] = "iOS Developer" 19 | 20 | SWIFT_VERSION = 5.5 21 | ONLY_ACTIVE_ARCH[config=Debug] = YES 22 | 23 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) ATOMICS_SINGLE_MODULE 24 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) ATOMICS_SINGLE_MODULE=1 25 | 26 | SWIFT_COMPILATION_MODE[config=Release] = wholemodule 27 | SWIFT_COMPILATION_MODE[config=Debug] = singlefile 28 | 29 | SWIFT_OPTIMIZATION_LEVEL[config=Release] = -O 30 | SWIFT_OPTIMIZATION_LEVEL[config=Debug] = -Onone 31 | 32 | SWIFT_EMIT_LOC_STRINGS = NO 33 | SWIFT_INSTALL_OBJC_HEADER = NO 34 | 35 | COPY_PHASE_STRIP = NO 36 | 37 | DEBUG_INFORMATION_FORMAT[config=Release] = dwarf-with-dsym 38 | DEBUG_INFORMATION_FORMAT[config=Debug] = dwarf 39 | 40 | ALWAYS_SEARCH_USER_PATHS = NO 41 | 42 | ENABLE_TESTABILITY = NO 43 | ENABLE_USER_SCRIPT_SANDBOXING = YES 44 | DEAD_CODE_STRIPPING = YES 45 | 46 | GCC_DYNAMIC_NO_PIC = NO 47 | GCC_NO_COMMON_BLOCKS = YES 48 | GCC_OPTIMIZATION_LEVEL[config=Debug] = 0 49 | 50 | GCC_C_LANGUAGE_STANDARD = gnu11 51 | CLANG_CXX_LANGUAGE_STANDARD = gnu++20 52 | CLANG_ENABLE_MODULES = YES 53 | CLANG_ENABLE_OBJC_ARC = YES 54 | CLANG_ENABLE_OBJC_WEAK = YES 55 | ENABLE_NS_ASSERTIONS[config=Release] = NO 56 | ENABLE_STRICT_OBJC_MSGSEND = YES 57 | GCC_PREPROCESSOR_DEFINITIONS[config=Release] = DEBUG=1 $(inherited) 58 | 59 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES 60 | CLANG_WARN_BOOL_CONVERSION = YES 61 | CLANG_WARN_COMMA = YES 62 | CLANG_WARN_CONSTANT_CONVERSION = YES 63 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES 64 | CLANG_WARN_EMPTY_BODY = YES 65 | CLANG_WARN_ENUM_CONVERSION = YES 66 | CLANG_WARN_INFINITE_RECURSION = YES 67 | CLANG_WARN_INT_CONVERSION = YES 68 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES 69 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES 70 | CLANG_WARN_STRICT_PROTOTYPES = YES 71 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 72 | CLANG_WARN_UNREACHABLE_CODE = YES 73 | 74 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES 75 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR 76 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE 77 | GCC_WARN_UNUSED_FUNCTION = YES 78 | GCC_WARN_UNUSED_VARIABLE = YES 79 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES 80 | CLANG_WARN_SUSPICIOUS_MOVE = YES 81 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES 82 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR 83 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES 84 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR 85 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 86 | GCC_WARN_UNDECLARED_SELECTOR = YES 87 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 88 | CLANG_ANALYZER_NONNULL = YES 89 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE 90 | -------------------------------------------------------------------------------- /cmake/modules/SwiftSupport.cmake: -------------------------------------------------------------------------------- 1 | #[[ 2 | This source file is part of the Swift Atomics Open Source Project 3 | 4 | Copyright (c) 2021 Apple Inc. and the Swift project authors 5 | Licensed under Apache License v2.0 with Runtime Library Exception 6 | 7 | See https://swift.org/LICENSE.txt for license information 8 | #]] 9 | 10 | # Returns the architecture name in a variable 11 | # 12 | # Usage: 13 | # get_swift_host_arch(result_var_name) 14 | # 15 | # Sets ${result_var_name} with the converted architecture name derived from 16 | # CMAKE_SYSTEM_PROCESSOR. 17 | function(get_swift_host_arch result_var_name) 18 | if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") 19 | set("${result_var_name}" "x86_64" PARENT_SCOPE) 20 | elseif ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "AArch64|aarch64|arm64") 21 | if(CMAKE_SYSTEM_NAME MATCHES Darwin) 22 | set("${result_var_name}" "arm64" PARENT_SCOPE) 23 | else() 24 | set("${result_var_name}" "aarch64" PARENT_SCOPE) 25 | endif() 26 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64") 27 | set("${result_var_name}" "powerpc64" PARENT_SCOPE) 28 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") 29 | set("${result_var_name}" "powerpc64le" PARENT_SCOPE) 30 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "s390x") 31 | set("${result_var_name}" "s390x" PARENT_SCOPE) 32 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l") 33 | set("${result_var_name}" "armv6" PARENT_SCOPE) 34 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") 35 | set("${result_var_name}" "armv7" PARENT_SCOPE) 36 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7-a") 37 | set("${result_var_name}" "armv7" PARENT_SCOPE) 38 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "amd64") 39 | set("${result_var_name}" "amd64" PARENT_SCOPE) 40 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") 41 | set("${result_var_name}" "x86_64" PARENT_SCOPE) 42 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "IA64") 43 | set("${result_var_name}" "itanium" PARENT_SCOPE) 44 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86") 45 | set("${result_var_name}" "i686" PARENT_SCOPE) 46 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686") 47 | set("${result_var_name}" "i686" PARENT_SCOPE) 48 | elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "riscv64") 49 | set("${result_var_name}" "riscv64" PARENT_SCOPE) 50 | else() 51 | message(FATAL_ERROR "Unrecognized architecture on host system: ${CMAKE_SYSTEM_PROCESSOR}") 52 | endif() 53 | endfunction() 54 | 55 | # Returns the os name in a variable 56 | # 57 | # Usage: 58 | # get_swift_host_os(result_var_name) 59 | # 60 | # 61 | # Sets ${result_var_name} with the converted OS name derived from 62 | # CMAKE_SYSTEM_NAME. 63 | function(get_swift_host_os result_var_name) 64 | if(CMAKE_SYSTEM_NAME STREQUAL Darwin) 65 | set(${result_var_name} macosx PARENT_SCOPE) 66 | else() 67 | string(TOLOWER ${CMAKE_SYSTEM_NAME} cmake_system_name_lc) 68 | set(${result_var_name} ${cmake_system_name_lc} PARENT_SCOPE) 69 | endif() 70 | endfunction() 71 | 72 | function(_install_target module) 73 | get_swift_host_os(swift_os) 74 | get_target_property(type ${module} TYPE) 75 | 76 | if(type STREQUAL STATIC_LIBRARY) 77 | set(swift swift_static) 78 | else() 79 | set(swift swift) 80 | endif() 81 | 82 | install(TARGETS ${module} 83 | ARCHIVE DESTINATION lib/${swift}/${swift_os} 84 | LIBRARY DESTINATION lib/${swift}/${swift_os} 85 | RUNTIME DESTINATION bin) 86 | if(type STREQUAL EXECUTABLE) 87 | return() 88 | endif() 89 | 90 | get_swift_host_arch(swift_arch) 91 | get_target_property(module_name ${module} Swift_MODULE_NAME) 92 | if(NOT module_name) 93 | set(module_name ${module}) 94 | endif() 95 | 96 | install(FILES $/${module_name}.swiftdoc 97 | DESTINATION lib/${swift}/${swift_os}/${module_name}.swiftmodule 98 | RENAME ${swift_arch}.swiftdoc) 99 | install(FILES $/${module_name}.swiftmodule 100 | DESTINATION lib/${swift}/${swift_os}/${module_name}.swiftmodule 101 | RENAME ${swift_arch}.swiftmodule) 102 | endfunction() 103 | --------------------------------------------------------------------------------