Implement Mutex in Synchronization

This commit is contained in:
Alejandro Alonso
2024-02-04 23:57:16 -08:00
parent 083fdaa0de
commit 2a60c88457
10 changed files with 675 additions and 10 deletions

View File

@@ -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

View File

@@ -17,6 +17,7 @@ set(sources
SwiftStdbool.h
SwiftStddef.h
SwiftStdint.h
SynchronizationShims.h
System.h
Target.h
ThreadLocalStorage.h

View 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

View File

@@ -31,3 +31,8 @@ module SwiftOverlayShims {
header "LibcOverlayShims.h"
export *
}
module SynchronizationShims {
header "SynchronizationShims.h"
export *
}

View File

@@ -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"

View 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)
}
}

View 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))
}
}

View 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()
}
}

View 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 {}

View 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))
}
}