mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Implement Mutex in Synchronization
This commit is contained in:
@@ -1823,6 +1823,42 @@ endfunction()
|
||||
# Presence of a build flavor requires SWIFT_MODULE_DEPENDS_MACCATALYST to be
|
||||
# defined and have values.
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_MACOS
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_IOS
|
||||
# Sources that are built when this library is being built for iOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_TVOS
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_WATCHOS
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_FREESTANDING
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_FREEBSD
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_OPENBSD
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_LINUX
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_CYGWIN
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_HAIKU
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_WASI
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# SWIFT_SOURCES_DEPENDS_WINDOWS
|
||||
# Sources that are built when this library is being built for macOS
|
||||
#
|
||||
# source1 ...
|
||||
# Sources to add into this library.
|
||||
function(add_swift_target_library name)
|
||||
@@ -1898,7 +1934,19 @@ function(add_swift_target_library name)
|
||||
TARGET_SDKS
|
||||
SWIFT_COMPILE_FLAGS_MACCATALYST
|
||||
SWIFT_MODULE_DEPENDS_MACCATALYST
|
||||
SWIFT_MODULE_DEPENDS_MACCATALYST_UNZIPPERED)
|
||||
SWIFT_MODULE_DEPENDS_MACCATALYST_UNZIPPERED
|
||||
SWIFT_SOURCES_DEPENDS_MACOS
|
||||
SWIFT_SOURCES_DEPENDS_IOS
|
||||
SWIFT_SOURCES_DEPENDS_TVOS
|
||||
SWIFT_SOURCES_DEPENDS_WATCHOS
|
||||
SWIFT_SOURCES_DEPENDS_FREESTANDING
|
||||
SWIFT_SOURCES_DEPENDS_FREEBSD
|
||||
SWIFT_SOURCES_DEPENDS_OPENBSD
|
||||
SWIFT_SOURCES_DEPENDS_LINUX
|
||||
SWIFT_SOURCES_DEPENDS_CYGWIN
|
||||
SWIFT_SOURCES_DEPENDS_HAIKU
|
||||
SWIFT_SOURCES_DEPENDS_WASI
|
||||
SWIFT_SOURCES_DEPENDS_WINDOWS)
|
||||
|
||||
cmake_parse_arguments(SWIFTLIB
|
||||
"${SWIFTLIB_options}"
|
||||
@@ -2169,6 +2217,33 @@ function(add_swift_target_library name)
|
||||
list(APPEND swiftlib_link_flags_all "-Xlinker" "-ignore_auto_link")
|
||||
endif()
|
||||
|
||||
# Append SDK specific sources to the full list of sources
|
||||
if(sdk STREQUAL "OSX")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_MACOS})
|
||||
elseif(sdk STREQUAL "IOS" OR sdk STREQUAL "IOS_SIMULATOR")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_IOS})
|
||||
elseif(sdk STREQUAL "TVOS" OR sdk STREQUAL "TVOS_SIMULATOR")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_TVOS})
|
||||
elseif(sdk STREQUAL "WATCHOS" OR sdk STREQUAL "WATCHOS_SIMULATOR")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_WATCHOS})
|
||||
elseif(sdk STREQUAL "FREESTANDING")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_FREESTANDING})
|
||||
elseif(sdk STREQUAL "FREEBSD")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_FREEBSD})
|
||||
elseif(sdk STREQUAL "OPENBSD")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_OPENBSD})
|
||||
elseif(sdk STREQUAL "LINUX" OR sdk STREQUAL "ANDROID")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_LINUX})
|
||||
elseif(sdk STREQUAL "CYGWIN")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_CYGWIN})
|
||||
elseif(sdk STREQUAL "HAIKU")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_HAIKU})
|
||||
elseif(sdk STREQUAL "WASI")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_WASI})
|
||||
elseif(sdk STREQUAL "WINDOWS")
|
||||
list(APPEND SWIFTLIB_SOURCES ${SWIFTLIB_SWIFT_SOURCES_DEPENDS_WINDOWS})
|
||||
endif()
|
||||
|
||||
# We unconditionally removed "-z,defs" from CMAKE_SHARED_LINKER_FLAGS in
|
||||
# swift_common_standalone_build_config_llvm within
|
||||
# SwiftSharedCMakeConfig.cmake, where it was added by a call to
|
||||
|
||||
@@ -17,6 +17,7 @@ set(sources
|
||||
SwiftStdbool.h
|
||||
SwiftStddef.h
|
||||
SwiftStdint.h
|
||||
SynchronizationShims.h
|
||||
System.h
|
||||
Target.h
|
||||
ThreadLocalStorage.h
|
||||
|
||||
38
stdlib/public/SwiftShims/swift/shims/SynchronizationShims.h
Normal file
38
stdlib/public/SwiftShims/swift/shims/SynchronizationShims.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_STDLIB_SYNCHRONIZATION_SHIMS_H
|
||||
#define SWIFT_STDLIB_SYNCHRONIZATION_SHIMS_H
|
||||
|
||||
#include "SwiftStdbool.h"
|
||||
#include "SwiftStdint.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/futex.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SWIFT_FUTEX_WAITERS FUTEX_WAITERS
|
||||
|
||||
static inline __swift_bool _swift_stdlib_wait(__swift_uint32_t *lock) {
|
||||
return syscall(SYS_futex, lock, FUTEX_LOCK_PI_PRIVATE,
|
||||
/* val */ 0, // this value is ignored by this futex op
|
||||
/* timeout */ NULL); // block indefinitely
|
||||
}
|
||||
|
||||
static inline __swift_bool _swift_stdlib_wake(__swift_uint32_t *lock) {
|
||||
return syscall(SYS_futex, lock, FUTEX_UNLOCK_PI_PRIVATE);
|
||||
}
|
||||
|
||||
#endif // defined(__linux__)
|
||||
|
||||
#endif // SWIFT_STDLIB_SYNCHRONIZATION_SHIMS_H
|
||||
@@ -31,3 +31,8 @@ module SwiftOverlayShims {
|
||||
header "LibcOverlayShims.h"
|
||||
export *
|
||||
}
|
||||
|
||||
module SynchronizationShims {
|
||||
header "SynchronizationShims.h"
|
||||
export *
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
#===----------------------------------------------------------------------===#
|
||||
|
||||
set(swift_synchronization_sources
|
||||
set(SWIFT_SYNCHRONIZATION_ATOMIC_SOURCES
|
||||
Atomic.swift
|
||||
AtomicBool.swift
|
||||
AtomicFloats.swift
|
||||
@@ -21,11 +21,50 @@ set(swift_synchronization_sources
|
||||
AtomicRepresentable.swift
|
||||
WordPair.swift
|
||||
)
|
||||
set(swift_synchronization_gyb_sources
|
||||
|
||||
set(SWIFT_SYNCHRONIZATION_SOURCES
|
||||
${SWIFT_SYNCHRONIZATION_ATOMIC_SOURCES}
|
||||
|
||||
Cell.swift
|
||||
Mutex/Mutex.swift
|
||||
)
|
||||
|
||||
set(SWIFT_SYNCHRONIZATION_GYB_SOURCES
|
||||
AtomicIntegers.swift.gyb
|
||||
AtomicStorage.swift.gyb
|
||||
)
|
||||
set(swift_synchronization_swift_compile_flags
|
||||
|
||||
# Darwin dependencies and sources
|
||||
|
||||
set(SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES)
|
||||
|
||||
if(SWIFT_BUILD_SDK_OVERLAY)
|
||||
set(SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES Darwin)
|
||||
endif()
|
||||
|
||||
set(SWIFT_SYNCHRONIZATION_DARWIN_SOURCES
|
||||
Mutex/DarwinImpl.swift
|
||||
)
|
||||
|
||||
# Linux dependencies and sources
|
||||
|
||||
set(SWIFT_SYNCHRONIZATION_LINUX_SOURCES
|
||||
Mutex/LinuxImpl.swift
|
||||
)
|
||||
|
||||
# Windows depdencies and sources
|
||||
|
||||
set(SWIFT_SYNCHRONIZATION_WINDOWS_DEPENDENCIES)
|
||||
|
||||
if(SWIFT_BUILD_SDK_OVERLAY)
|
||||
set(SWIFT_SYNCHRONIZATION_WINDOWS_DEPENDENCIES WinSDK)
|
||||
endif()
|
||||
|
||||
set(SWIFT_SYNCHRONIZATION_WINDOWS_SOURCES
|
||||
Mutex/WindowsImpl.swift
|
||||
)
|
||||
|
||||
set(SWIFT_SYNCHRNOIZATION_SWIFT_FLAGS
|
||||
${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS}
|
||||
"-enable-builtin-module"
|
||||
"-enable-experimental-feature" "RawLayout"
|
||||
@@ -33,9 +72,35 @@ set(swift_synchronization_swift_compile_flags
|
||||
)
|
||||
|
||||
add_swift_target_library(swiftSynchronization ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB
|
||||
${swift_synchronization_sources}
|
||||
GYB_SOURCES ${swift_synchronization_gyb_sources}
|
||||
SWIFT_COMPILE_FLAGS ${swift_synchronization_swift_compile_flags}
|
||||
${SWIFT_SYNCHRONIZATION_SOURCES}
|
||||
|
||||
GYB_SOURCES
|
||||
${SWIFT_SYNCHRONIZATION_GYB_SOURCES}
|
||||
|
||||
SWIFT_SOURCES_DEPENDS_MACOS
|
||||
${SWIFT_SYNCHRONIZATION_DARWIN_SOURCES}
|
||||
SWIFT_SOURCES_DEPENDS_IOS
|
||||
${SWIFT_SYNCHRONIZATION_DARWIN_SOURCES}
|
||||
SWIFT_SOURCES_DEPENDS_TVOS
|
||||
${SWIFT_SYNCHRONIZATION_DARWIN_SOURCES}
|
||||
SWIFT_SOURCES_DEPENDS_WATCHOS
|
||||
${SWIFT_SYNCHRONIZATION_DARWIN_SOURCES}
|
||||
SWIFT_SOURCES_DEPENDS_LINUX
|
||||
${SWIFT_SYNCHRONIZATION_LINUX_SOURCES}
|
||||
SWIFT_SOURCES_DEPENDS_WINDOWS
|
||||
${SWIFT_SYNCHRONIZATION_WINDOWS_SOURCES}
|
||||
|
||||
SWIFT_MODULE_DEPENDS_OSX
|
||||
${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES}
|
||||
SWIFT_MODULE_DEPENDS_IOS
|
||||
${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES}
|
||||
SWIFT_MODULE_DEPENDS_TVOS
|
||||
${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES}
|
||||
SWIFT_MODULE_DEPENDS_WATCHOS
|
||||
${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES}
|
||||
|
||||
SWIFT_COMPILE_FLAGS
|
||||
${SWIFT_SYNCHRNOIZATION_SWIFT_FLAGS}
|
||||
LINK_FLAGS
|
||||
"${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
|
||||
INSTALL_IN_COMPONENT
|
||||
@@ -68,11 +133,12 @@ if(SWIFT_SHOULD_BUILD_EMBEDDED_STDLIB)
|
||||
ONLY_SWIFTMODULE
|
||||
IS_FRAGILE
|
||||
|
||||
${swift_synchronization_sources}
|
||||
GYB_SOURCES ${swift_synchronization_gyb_sources}
|
||||
${SWIFT_SYNCHRONIZATION_ATOMIC_SOURCES}
|
||||
GYB_SOURCES
|
||||
${SWIFT_SYNCHRONIZATION_GYB_SOURCES}
|
||||
|
||||
SWIFT_COMPILE_FLAGS
|
||||
${swift_synchronization_swift_compile_flags}
|
||||
${SWIFT_SYNCHRNOIZATION_SWIFT_FLAGS}
|
||||
-Xcc -D__MACH__ -Xcc -D__APPLE__ -Xcc -ffreestanding -enable-experimental-feature Embedded
|
||||
|
||||
MODULE_DIR "${CMAKE_BINARY_DIR}/lib/swift/embedded"
|
||||
|
||||
33
stdlib/public/Synchronization/Cell.swift
Normal file
33
stdlib/public/Synchronization/Cell.swift
Normal file
@@ -0,0 +1,33 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift Atomics open source project
|
||||
//
|
||||
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Builtin
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@frozen
|
||||
@usableFromInline
|
||||
@_rawLayout(like: Value)
|
||||
internal struct _Cell<Value: ~Copyable>: ~Copyable {
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
var rawAddress: Builtin.RawPointer {
|
||||
Builtin.unprotectedAddressOfBorrow(self)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
init(_ initialValue: consuming Value) {
|
||||
Builtin.initialize(initialValue, rawAddress)
|
||||
}
|
||||
}
|
||||
51
stdlib/public/Synchronization/Mutex/DarwinImpl.swift
Normal file
51
stdlib/public/Synchronization/Mutex/DarwinImpl.swift
Normal file
@@ -0,0 +1,51 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift Atomics open source project
|
||||
//
|
||||
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Builtin
|
||||
import Darwin
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@frozen
|
||||
@usableFromInline
|
||||
@_staticExclusiveOnly
|
||||
internal struct _MutexHandle: ~Copyable {
|
||||
@usableFromInline
|
||||
let value: _Cell<os_unfair_lock>
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
init() {
|
||||
value = _Cell(os_unfair_lock())
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
borrowing func lock() {
|
||||
os_unfair_lock_lock(os_unfair_lock_t(value.rawAddress))
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
borrowing func tryLock() -> Bool {
|
||||
os_unfair_lock_trylock(os_unfair_lock_t(value.rawAddress))
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
borrowing func unlock() {
|
||||
os_unfair_lock_unlock(os_unfair_lock_t(value.rawAddress))
|
||||
}
|
||||
}
|
||||
137
stdlib/public/Synchronization/Mutex/LinuxImpl.swift
Normal file
137
stdlib/public/Synchronization/Mutex/LinuxImpl.swift
Normal file
@@ -0,0 +1,137 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift Atomics open source project
|
||||
//
|
||||
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import SynchronizationShims
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
@_extern(c, "gettid")
|
||||
func _gettid() -> UInt32
|
||||
|
||||
extension Atomic where Value == UInt32 {
|
||||
borrowing func wait() {
|
||||
_swift_stdlib_wait(.init(rawAddress))
|
||||
}
|
||||
|
||||
borrowing func wake() {
|
||||
_swift_stdlib_wake(.init(rawAddress))
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@frozen
|
||||
@usableFromInline
|
||||
@_staticExclusiveOnly
|
||||
internal struct _MutexHandle: ~Copyable {
|
||||
// There are only 3 different values that storage can hold at a single time.
|
||||
// 0: unlocked
|
||||
// _gettid: locked, current thread's id (uncontended)
|
||||
// (_gettid | SWIFT_FUTEX_WAITERS): locked, current thread's id (contended)
|
||||
@usableFromInline
|
||||
let storage: Atomic<UInt32>
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
init() {
|
||||
storage = Atomic(0)
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@usableFromInline
|
||||
borrowing func lock() {
|
||||
// TODO: Is it worth caching this value in TLS?
|
||||
let selfId = _gettid()
|
||||
|
||||
// Note: We could probably merge this cas into a do/while style loop, but we
|
||||
// really want to perform the strong variant before attempting to do weak
|
||||
// ones in the loop.
|
||||
|
||||
var (exchanged, state) = storage.compareExchange(
|
||||
expected: 0,
|
||||
desired: selfId,
|
||||
successOrdering: .acquiring,
|
||||
failureOrdering: .relaxed
|
||||
)
|
||||
|
||||
if _fastPath(exchanged) {
|
||||
// Locked!
|
||||
return
|
||||
}
|
||||
|
||||
while !exchanged {
|
||||
// Clear the waiter bit, if we have one, and check to see if this is a
|
||||
// recursive call to lock.
|
||||
let currentOwner = state & ~SWIFT_FUTEX_WAITERS
|
||||
if _slowPath(currentOwner == selfId) {
|
||||
// TODO: Need a colder function.
|
||||
fatalError("Recursive call to lock")
|
||||
}
|
||||
|
||||
// Block until unlock has been called. This will return early if the call
|
||||
// to unlock happened between attempting to acquire and attempting to
|
||||
// wait while nobody else managed to acquire it yet.
|
||||
storage.wait()
|
||||
|
||||
(exchanged, state) = storage.weakCompareExchange(
|
||||
expected: 0,
|
||||
desired: selfId,
|
||||
successOrdering: .acquiring,
|
||||
failureOrdering: .relaxed
|
||||
)
|
||||
}
|
||||
|
||||
// Locked!
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@usableFromInline
|
||||
borrowing func tryLock() -> Bool {
|
||||
storage.compareExchange(
|
||||
expected: 0,
|
||||
desired: _gettid(),
|
||||
successOrdering: .acquiring,
|
||||
failureOrdering: .relaxed
|
||||
).exchanged
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@usableFromInline
|
||||
borrowing func unlock() {
|
||||
// TODO: Is it worth caching this value in TLS?
|
||||
let selfId = _gettid()
|
||||
// Unconditionally update the storage to be unlocked. At this point, the
|
||||
// lock is acquirable.
|
||||
let oldValue = storage.exchange(0, ordering: .releasing)
|
||||
|
||||
if _fastPath(oldValue == selfId) {
|
||||
// No waiters, unlocked!
|
||||
return
|
||||
}
|
||||
|
||||
// Clear the waiter bit from the old value and check to ensure we were the
|
||||
// previous owner of the lock.
|
||||
let oldOwner = oldValue & ~SWIFT_FUTEX_WAITERS
|
||||
guard _fastPath(oldOwner == selfId) else {
|
||||
// Either we called unlock while being unacquired, or another thread who
|
||||
// didn't have ownership of the lock called unlock.
|
||||
if oldOwner == 0 {
|
||||
// TODO: Need a colder function.
|
||||
fatalError("Call to unlock on an already unlocked mutex")
|
||||
} else {
|
||||
fatalError("Call to unlock on thread who wasn't holding the lock")
|
||||
}
|
||||
}
|
||||
|
||||
// Wake up the next highest priority waiter.
|
||||
storage.wake()
|
||||
}
|
||||
}
|
||||
208
stdlib/public/Synchronization/Mutex/Mutex.swift
Normal file
208
stdlib/public/Synchronization/Mutex/Mutex.swift
Normal file
@@ -0,0 +1,208 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift Atomics open source project
|
||||
//
|
||||
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Builtin
|
||||
|
||||
/// A synchronization primitive that protects shared mutable state via
|
||||
/// mutual exclusion.
|
||||
///
|
||||
/// The `Mutex` type offers non-recursive exclusive access to the state
|
||||
/// it is protecting by blocking threads attempting to acquire the lock.
|
||||
/// Only one execution context at a time has access to the value stored
|
||||
/// within the `Mutex` allowing for exclusive access.
|
||||
///
|
||||
/// An example use of `Mutex` in a class used simultaneously by many
|
||||
/// threads protecting a `Dictionary` value:
|
||||
///
|
||||
/// class Manager {
|
||||
/// let cache = Mutex<[Key: Resource]>([:])
|
||||
///
|
||||
/// func saveResouce(_ resource: Resouce, as key: Key) {
|
||||
/// cache.withLock {
|
||||
/// $0[key] = resource
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@frozen
|
||||
@_staticExclusiveOnly
|
||||
public struct Mutex<Value: ~Copyable>: ~Copyable {
|
||||
@usableFromInline
|
||||
let value: _Cell<Value>
|
||||
|
||||
@usableFromInline
|
||||
let handle = _MutexHandle()
|
||||
|
||||
/// Initializes a value of this mutex with the given initial state.
|
||||
///
|
||||
/// - Parameter initialValue: The initial value to give to the mutex.
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public init(_ initialValue: consuming Value) {
|
||||
value = _Cell(initialValue)
|
||||
}
|
||||
|
||||
/// Attempts to acquire the lock and then calls the given closure if
|
||||
/// successful.
|
||||
///
|
||||
/// If the calling thread was successful in acquiring the lock, the
|
||||
/// closure will be executed and then immediately after it will
|
||||
/// release ownership of the lock. If we were unable to acquire the
|
||||
/// lock, this will return `nil`.
|
||||
///
|
||||
/// This method is equivalent to the following sequence of code:
|
||||
///
|
||||
/// guard mutex.tryLock() else {
|
||||
/// return nil
|
||||
/// }
|
||||
/// defer {
|
||||
/// mutex.unlock()
|
||||
/// }
|
||||
/// return try body(&value)
|
||||
///
|
||||
/// - Warning: Recursive calls to `tryWithLock` within the
|
||||
/// closure parameter has behavior that is platform dependent.
|
||||
/// Some platforms may choose to panic the process, deadlock,
|
||||
/// or leave this behavior unspecified.
|
||||
///
|
||||
/// - Parameter body: A closure with a parameter of `Value`
|
||||
/// that has exclusive access to the value being stored within
|
||||
/// this mutex. This closure is considered the critical section
|
||||
/// as it will only be executed if the calling thread acquires
|
||||
/// the lock.
|
||||
///
|
||||
/// - Returns: The return value, if any, of the `body` closure parameter
|
||||
/// or nil if the lock couldn't be acquired.
|
||||
// @available(SwiftStdlib 6.0, *)
|
||||
// @_alwaysEmitIntoClient
|
||||
// @_transparent
|
||||
// public borrowing func tryWithLock<Result: ~Copyable & Sendable, E>(
|
||||
// _ body: @Sendable (inout Value) throws(E) -> Result
|
||||
// ) throws(E) -> Result? {
|
||||
// fatalError()
|
||||
// }
|
||||
|
||||
/// Attempts to acquire the lock and then calls the given closure if
|
||||
/// successful.
|
||||
///
|
||||
/// If the calling thread was successful in acquiring the lock, the
|
||||
/// closure will be executed and then immediately after it will
|
||||
/// release ownership of the lock. If we were unable to acquire the
|
||||
/// lock, this will return `nil`.
|
||||
///
|
||||
/// This method is equivalent to the following sequence of code:
|
||||
///
|
||||
/// guard mutex.tryLock() else {
|
||||
/// return nil
|
||||
/// }
|
||||
/// defer {
|
||||
/// mutex.unlock()
|
||||
/// }
|
||||
/// return try body(&value)
|
||||
///
|
||||
/// - Note: This version of `withLock` is unchecked because it does
|
||||
/// not enforce any sendability guarantees.
|
||||
///
|
||||
/// - Warning: Recursive calls to `tryWithLockUnchecked` within the
|
||||
/// closure parameter has behavior that is platform dependent.
|
||||
/// Some platforms may choose to panic the process, deadlock,
|
||||
/// or leave this behavior unspecified.
|
||||
///
|
||||
/// - Parameter body: A closure with a parameter of `Value`
|
||||
/// that has exclusive access to the value being stored within
|
||||
/// this mutex. This closure is considered the critical section
|
||||
/// as it will only be executed if the calling thread acquires
|
||||
/// the lock.
|
||||
///
|
||||
/// - Returns: The return value, if any, of the `body` closure parameter
|
||||
/// or nil if the lock couldn't be acquired.
|
||||
// @available(SwiftStdlib 6.0, *)
|
||||
// @_alwaysEmitIntoClient
|
||||
// @_transparent
|
||||
// public borrowing func tryWithLock<Result: ~Copyable, E>(
|
||||
// _ body: (inout Value) throws(E) -> Result
|
||||
// ) throws(E) -> Result? {
|
||||
// fatalError()
|
||||
// }
|
||||
|
||||
/// Calls the given closure after acquring the lock and then releases
|
||||
/// ownership.
|
||||
///
|
||||
/// This method is equivalent to the following sequence of code:
|
||||
///
|
||||
/// mutex.lock()
|
||||
/// defer {
|
||||
/// mutex.unlock()
|
||||
/// }
|
||||
/// return try body(&value)
|
||||
///
|
||||
/// - Warning: Recursive calls to `withLock` within the
|
||||
/// closure parameter has behavior that is platform dependent.
|
||||
/// Some platforms may choose to panic the process, deadlock,
|
||||
/// or leave this behavior unspecified.
|
||||
///
|
||||
/// - Parameter body: A closure with a parameter of `Value`
|
||||
/// that has exclusive access to the value being stored within
|
||||
/// this mutex. This closure is considered the critical section
|
||||
/// as it will only be executed once the calling thread has
|
||||
/// acquired the lock.
|
||||
///
|
||||
/// - Returns: The return value, if any, of the `body` closure parameter.
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public borrowing func withLock<Result: ~Copyable & Sendable, E>(
|
||||
_ body: @Sendable (inout Value) throws(E) -> Result
|
||||
) throws(E) -> Result {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
/// Calls the given closure after acquring the lock and then releases
|
||||
/// ownership.
|
||||
///
|
||||
/// This method is equivalent to the following sequence of code:
|
||||
///
|
||||
/// mutex.lock()
|
||||
/// defer {
|
||||
/// mutex.unlock()
|
||||
/// }
|
||||
/// return try body(&value)
|
||||
///
|
||||
/// - Warning: Recursive calls to `withLockUnchecked` within the
|
||||
/// closure parameter has behavior that is platform dependent.
|
||||
/// Some platforms may choose to panic the process, deadlock,
|
||||
/// or leave this behavior unspecified.
|
||||
///
|
||||
/// - Note: This version of `withLock` is unchecked because it does
|
||||
/// not enforce any sendability guarantees.
|
||||
///
|
||||
/// - Parameter body: A closure with a parameter of `Value`
|
||||
/// that has exclusive access to the value being stored within
|
||||
/// this mutex. This closure is considered the critical section
|
||||
/// as it will only be executed once the calling thread has
|
||||
/// acquired the lock.
|
||||
///
|
||||
/// - Returns: The return value, if any, of the `body` closure parameter.
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
public borrowing func withLock<Result: ~Copyable, E>(
|
||||
_ body: (inout Value) throws(E) -> Result
|
||||
) throws(E) -> Result {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
extension Mutex: @unchecked Sendable where Value: Sendable {}
|
||||
51
stdlib/public/Synchronization/Mutex/WindowsImpl.swift
Normal file
51
stdlib/public/Synchronization/Mutex/WindowsImpl.swift
Normal file
@@ -0,0 +1,51 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift Atomics open source project
|
||||
//
|
||||
// Copyright (c) 2024 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import WinSDK.core.synch
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@frozen
|
||||
@usableFromInline
|
||||
@_staticExclusiveOnly
|
||||
internal struct _MutexHandle: ~Copyable {
|
||||
@usableFromInline
|
||||
let value: _Cell<SRWLOCK>
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
init() {
|
||||
value = _Cell(SRWLOCK())
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
borrowing func lock() {
|
||||
AcquireSRWLockExclusive(PSRWLOCK(value.rawAddress))
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
borrowing func tryLock() -> Bool {
|
||||
// Windows BOOLEAN gets imported as 'UInt8'...
|
||||
TryAcquireSRWLockExclusive(PSRWLOCK(value.rawAddress)) != 0
|
||||
}
|
||||
|
||||
@available(SwiftStdlib 6.0, *)
|
||||
@_alwaysEmitIntoClient
|
||||
@_transparent
|
||||
borrowing func unlock() {
|
||||
ReleaseSRWLockExclusive(PSRWLOCK(value.rawAddress))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user