Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
56fc64e
Unchecked sendable everywhere but builds with a change in C and a lot…
waahm7 Dec 27, 2024
2e659ac
some docs
waahm7 Dec 28, 2024
16c705b
warning fix plus tests in progress
waahm7 Dec 30, 2024
149abc4
non working
waahm7 Dec 30, 2024
853fa9e
More fixes
waahm7 Dec 30, 2024
b12eebd
more fixes
waahm7 Jan 6, 2025
5b3f624
more fixes
waahm7 Jan 6, 2025
2f3aac0
update comment
waahm7 Jan 6, 2025
703b650
fix test
waahm7 Jan 6, 2025
2478627
more fixes
waahm7 Jan 6, 2025
2aa220f
reset package.swift
waahm7 Jan 6, 2025
75aea3f
fix stuff
waahm7 Jan 6, 2025
e35ed11
unchecked
waahm7 Jan 6, 2025
015d98c
Some ifdef
waahm7 Jan 7, 2025
54d17c3
try swift 6
waahm7 Jan 7, 2025
82f02db
try ci
waahm7 Jan 7, 2025
28d5c83
sed mac
waahm7 Jan 7, 2025
2c7b1e3
remove it
waahm7 Jan 7, 2025
45cf8d8
Merge branch 'main' into swift6-support
waahm7 Apr 3, 2025
b179c0a
MQTT changes for Swift 6
waahm7 Apr 3, 2025
3322408
unchecked sendable for FileBasedConfiguration
waahm7 Apr 3, 2025
054f55b
manager sendable
waahm7 Apr 3, 2025
ddb7601
gen ai stop adding unnecassary code
waahm7 Apr 3, 2025
8ed9511
Use argument parser for ElasticCurl
waahm7 Apr 4, 2025
dbeeb11
red code is best code
waahm7 Apr 4, 2025
35827ab
huh?
waahm7 Apr 4, 2025
851e492
lint
waahm7 Apr 4, 2025
b047034
try swift 6 CI
waahm7 Apr 4, 2025
a62b69e
checkout
waahm7 Apr 4, 2025
2a50b11
15?15?15?15?15?15?15?15?15?15?15?15?15?15?15?
waahm7 Apr 4, 2025
d708dd7
submodules
waahm7 Apr 4, 2025
6928a56
remove mqtt test for now, too many changes required
waahm7 Apr 4, 2025
62cbbab
disable warning
waahm7 Apr 7, 2025
451d671
request option sendable
waahm7 Apr 8, 2025
ee67970
Expose Endpoint Property directly?
waahm7 Apr 8, 2025
9b16f05
Update signing config
waahm7 Apr 14, 2025
b606679
enable dispatch queue on apple platforms
xiazhvera Apr 15, 2025
f7ea06a
Merge remote-tracking branch 'origin/default_eventloop' into swift6-s…
waahm7 Apr 16, 2025
a8cb8a8
cleanup
waahm7 Apr 28, 2025
3d9150d
try failing one
waahm7 Apr 28, 2025
f3a1b10
try this
waahm7 Apr 28, 2025
d8c8ae5
try two commands
waahm7 Apr 28, 2025
de6e771
does it fail?
waahm7 Apr 28, 2025
44d1ce0
works
waahm7 Apr 28, 2025
7ba5ac8
no need for cat
waahm7 Apr 28, 2025
208c468
add sleep before retry
waahm7 Apr 28, 2025
9f44a03
Unchecked Date is not Sendable on Linux
waahm7 Apr 28, 2025
c1c2486
Swift6 Support for Mqtt (#328)
xiazhvera Apr 28, 2025
58ae842
Merge branch 'main' into swift6-support
waahm7 Apr 28, 2025
87fbc7b
Mark OnWebSocketHandshakeInterceptComplete as Sendable (#333)
xiazhvera Apr 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,35 @@ jobs:
chmod a+x builder
./builder build -p ${{ env.PACKAGE_NAME }}

# Test that everything works with Swift 6 strict concurrency. We can remove this CI in the future once we raise our minimum Swift version to Swift 6.
macos-swift6:
runs-on: macos-15
env:
DEVELOPER_DIR: /Applications/Xcode.app
XCODE_DESTINATION: 'OS X'
NSUnbufferedIO: YES
strategy:
fail-fast: false
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.CRT_CI_ROLE }}
aws-region: ${{ env.AWS_DEFAULT_REGION }}
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0
- name: Set Swift version to 6
run: |
sed -i '' 's/swift-tools-version:5\.[0-9][0-9]*/swift-tools-version:6\.0/' Package.swift
# Verify that substitution was successful
grep -q 'swift-tools-version:6\.0' Package.swift || (echo "No version 5.x found to update" && exit 1)
- name: Build ${{ env.PACKAGE_NAME }} + consumers
run: |
swift build
swift test

devices:
runs-on: ${{ matrix.runner }}
env:
Expand Down
9 changes: 8 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ var package = Package(name: "aws-crt-swift",
products: [
.library(name: "AwsCommonRuntimeKit", targets: ["AwsCommonRuntimeKit"]),
.executable(name: "Elasticurl", targets: ["Elasticurl"])
],
dependencies: [
// Arugment Parser Dependency for ElasticCurl
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMajor(from: "1.5.0"))
]
)

Expand Down Expand Up @@ -332,7 +336,10 @@ packageTargets.append(contentsOf: [
),
.executableTarget(
name: "Elasticurl",
dependencies: ["AwsCommonRuntimeKit"],
dependencies: [
"AwsCommonRuntimeKit",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
],
path: "Source/Elasticurl"
)
] )
Expand Down
19 changes: 10 additions & 9 deletions Source/AwsCommonRuntimeKit/CommonRuntimeKit.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import AwsCEventStream
import AwsCAuth
import AwsCEventStream
import AwsCMqtt
import LibNative

/**
* Initializes the library.
* `CommonRuntimeKit.initialize` must be called before using any other functionality.
*/
/// Initializes the library.
/// `CommonRuntimeKit.initialize` must be called before using any other functionality.
public struct CommonRuntimeKit {

/// Initializes the library.
Expand All @@ -15,20 +13,23 @@ public struct CommonRuntimeKit {
aws_auth_library_init(allocator.rawValue)
aws_event_stream_library_init(allocator.rawValue)
aws_mqtt_library_init(allocator.rawValue)
aws_register_error_info(&s_crt_swift_error_list)
withUnsafePointer(to: s_crt_swift_error_list) { ptr in
aws_register_error_info(ptr)
}
}

/**
* This is an optional cleanup function which will block until all the CRT resources have cleaned up.
* Use this function only if you want to make sure that there are no memory leaks at the end of the application.
* Warning: It will hang if you are still holding references to any CRT objects such as HostResolver.
*/
public static func cleanUp() {
aws_unregister_error_info(&s_crt_swift_error_list)
public static nonisolated func cleanUp() {
withUnsafePointer(to: s_crt_swift_error_list) { ptr in
aws_unregister_error_info(ptr)
}
aws_mqtt_library_clean_up()
aws_event_stream_library_clean_up()
aws_auth_library_clean_up()

}

private init() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import AwsCAuth
import Foundation

public final class Credentials {
// We can't mutate this class after initialization. Swift can not verify the sendability due to OpaquePointer,
// So mark it unchecked Sendable
public final class Credentials: @unchecked Sendable {

let rawValue: OpaquePointer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ public struct CognitoLoginPair: CStruct {
}
}

public class CredentialsProvider: CredentialsProviding {

// We can't mutate this class after initialization. Swift can not verify the sendability due to pointer,
// So mark it unchecked Sendable
public class CredentialsProvider: CredentialsProviding, @unchecked Sendable {
let rawValue: UnsafeMutablePointer<aws_credentials_provider>

init(credentialsProvider: UnsafeMutablePointer<aws_credentials_provider>) {
Expand Down Expand Up @@ -667,25 +668,19 @@ private func onGetCredentials(credentials: OpaquePointer?,
continuationCore.continuation.resume(returning: Credentials(rawValue: credentials!))
}

// We need to share this pointer to C in a task block but Swift compiler complains
// that Pointer does not conform to Sendable. Wrap the pointer in a @unchecked Sendable block
// for Swift compiler to stop complaining.
struct SendablePointer: @unchecked Sendable {
let pointer: UnsafeMutableRawPointer
}

private func getCredentialsDelegateFn(_ delegatePtr: UnsafeMutableRawPointer!,
_ callbackFn: (@convention(c) (
OpaquePointer?,
Int32,
UnsafeMutableRawPointer?) -> Void)!,
_ userData: UnsafeMutableRawPointer!) -> Int32 {
let delegate = Unmanaged<Box<CredentialsProviding>>
.fromOpaque(delegatePtr)
.takeUnretainedValue().contents
let userData = SendablePointer(pointer: userData)
let userData = SendableRawPointer(pointer: userData)
let delegatePtr = SendableRawPointer(pointer: delegatePtr)
Task {
do {
let delegate = Unmanaged<Box<CredentialsProviding>>
.fromOpaque(delegatePtr.pointer!)
.takeUnretainedValue().contents
let credentials = try await delegate.getCredentials()
callbackFn(credentials.rawValue, AWS_OP_SUCCESS, userData.pointer)
} catch CommonRunTimeError.crtError(let crtError) {
Expand Down
2 changes: 1 addition & 1 deletion Source/AwsCommonRuntimeKit/auth/imds/IAMProfile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import AwsCAuth
import Foundation

public struct IAMProfile {
public struct IAMProfile: @unchecked Sendable {
public let lastUpdated: Date
public let profileArn: String
public let profileId: String
Expand Down
4 changes: 3 additions & 1 deletion Source/AwsCommonRuntimeKit/auth/imds/IMDSClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import AwsCAuth

// swiftlint:disable type_body_length
public class IMDSClient {
// We can't mutate this class after initialization. Swift can not verify the sendability due to OpaquePointer,
// So mark it unchecked Sendable
public class IMDSClient: @unchecked Sendable {
let rawValue: OpaquePointer

/// Creates an IMDSClient that always uses IMDSv2
Expand Down
5 changes: 3 additions & 2 deletions Source/AwsCommonRuntimeKit/auth/imds/IMDSInstanceInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import AwsCAuth
import Foundation

public struct IMDSInstanceInfo {
public struct IMDSInstanceInfo: @unchecked Sendable {
public let marketPlaceProductCodes: [String]
public let availabilityZone: String
public let privateIp: String
Expand All @@ -21,7 +21,8 @@ public struct IMDSInstanceInfo {
public let region: String

init(instanceInfo: aws_imds_instance_info) {
self.marketPlaceProductCodes = instanceInfo.marketplace_product_codes.byteCursorListToStringArray()
self.marketPlaceProductCodes = instanceInfo.marketplace_product_codes
.byteCursorListToStringArray()
self.availabilityZone = instanceInfo.availability_zone.toString()
self.privateIp = instanceInfo.private_ip.toString()
self.version = instanceInfo.version.toString()
Expand Down
10 changes: 7 additions & 3 deletions Source/AwsCommonRuntimeKit/auth/signing/Signer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,11 @@ public class Signer {
}
}

class SignRequestCore {
// After signing, we mutate the request and resume the continuation, which may result in a thread change.
// We won't modify it after continuation.resume is called. So we can mark it @unchecked Sendable
class SignRequestCore: @unchecked Sendable {
let request: HTTPRequestBase
var continuation: CheckedContinuation<HTTPRequestBase, Error>
let continuation: CheckedContinuation<HTTPRequestBase, Error>
let shouldSignHeader: ((String) -> Bool)?
init(request: HTTPRequestBase,
continuation: CheckedContinuation<HTTPRequestBase, Error>,
Expand Down Expand Up @@ -207,6 +209,7 @@ private func onRequestSigningComplete(signingResult: UnsafeMutablePointer<aws_si
} else {
signRequestCore.continuation.resume(throwing: CommonRunTimeError.crtError(.makeFromLastError()))
}
// It's not thread-safe to modify `signingRequestCore.request` after continuation.resume
}

private func onSigningComplete(signingResult: UnsafeMutablePointer<aws_signing_result>?,
Expand All @@ -220,9 +223,10 @@ private func onSigningComplete(signingResult: UnsafeMutablePointer<aws_signing_r

// Success
var awsStringPointer: UnsafeMutablePointer<aws_string>!
let signature = AWSString("signature")
guard aws_signing_result_get_property(
signingResult!,
g_aws_signature_property_name,
signature.rawValue,
&awsStringPointer) == AWS_OP_SUCCESS else {
chunkSignerCore.continuation.resume(throwing: CommonRunTimeError.crtError(.makeFromLastError()))
return
Expand Down
10 changes: 5 additions & 5 deletions Source/AwsCommonRuntimeKit/auth/signing/SigningConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import AwsCAuth
import Foundation

public struct SigningConfig: CStructWithUserData {
public struct SigningConfig: CStructWithUserData, @unchecked Sendable {

/// What signing algorithm to use.
public var algorithm: SigningAlgorithmType
Expand Down Expand Up @@ -136,7 +136,7 @@ private func onShouldSignHeader(nameCursor: UnsafePointer<aws_byte_cursor>!,
return signRequestCore.shouldSignHeader!(name)
}

public enum SignatureType {
public enum SignatureType: Sendable {

/// A signature for a full http request should be computed, with header updates applied to the signing result.
case requestHeaders
Expand All @@ -162,7 +162,7 @@ public enum SignatureType {
case requestEvent
}

public enum SignedBodyHeaderType {
public enum SignedBodyHeaderType: Sendable {

/// Do not add a header
case none
Expand All @@ -174,7 +174,7 @@ public enum SignedBodyHeaderType {
/// Optional string to use as the canonical request's body value.
/// Typically, this is the SHA-256 of the (request/chunk/event) payload, written as lowercase hex.
/// If this has been precalculated, it can be set here. Special values used by certain services can also be set.
public enum SignedBodyValue: CustomStringConvertible, Equatable {
public enum SignedBodyValue: CustomStringConvertible, Equatable, Sendable {
/// if empty, a public value will be calculated from the payload during signing
case empty
/// For empty sha256
Expand Down Expand Up @@ -226,7 +226,7 @@ public enum SignedBodyValue: CustomStringConvertible, Equatable {
}
}

public enum SigningAlgorithmType {
public enum SigningAlgorithmType: Sendable {
case signingV4
case signingV4Asymmetric
case signingV4S3Express
Expand Down
12 changes: 9 additions & 3 deletions Source/AwsCommonRuntimeKit/crt/Allocator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@
// SPDX-License-Identifier: Apache-2.0.
import AwsCCommon

/**
The default allocator.
You are probably looking to use `allocator` instead.
/*
* The default allocator.
* We need to declare `allocator` as mutable (`var`) instead of `let` because we override it with a tracing allocator in tests. This is not mutated anywhere else apart from the start of tests.
* Swift compiler doesn't let us compile this code in Swift 6 due to global shared mutable state without locks, and complains that this is not safe. Disable the safety here since we won't modify it.
* Remove the Ifdef once our minimum supported Swift version reaches 5.10
*/
#if swift(>=5.10)
nonisolated(unsafe) var allocator = aws_default_allocator()!
#else
var allocator = aws_default_allocator()!
#endif

/// An allocator is used to allocate memory on the heap.
protocol Allocator {
Expand Down
2 changes: 1 addition & 1 deletion Source/AwsCommonRuntimeKit/crt/CommonRuntimeError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public enum CommonRunTimeError: Error {
case crtError(CRTError)
}

public struct CRTError: Equatable {
public struct CRTError: Equatable, Sendable {
public let code: Int32
public let message: String
public let name: String
Expand Down
4 changes: 2 additions & 2 deletions Source/AwsCommonRuntimeKit/crt/Logger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public enum LogTarget {
case filePath(String)
}

public struct Logger {
public actor Logger {
private static var logger: aws_logger?
private static let lock = NSLock()

Expand Down Expand Up @@ -55,7 +55,7 @@ public struct Logger {
}
}

public enum LogLevel {
public enum LogLevel: Sendable {
case none
case fatal
case error
Expand Down
10 changes: 10 additions & 0 deletions Source/AwsCommonRuntimeKit/crt/Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ class Box<T> {
}
}

// We need to share this pointer to C in a task block but Swift compiler complains
// that Pointer does not conform to Sendable. Wrap the pointer in a @unchecked Sendable block
// for Swift compiler to stop complaining.
struct SendableRawPointer: @unchecked Sendable {
let pointer: UnsafeMutableRawPointer?
}

extension String {

func withByteCursor<Result>(_ body: (aws_byte_cursor) -> Result
Expand Down Expand Up @@ -194,6 +201,9 @@ extension aws_byte_cursor {
}

let data = Data(bytesNoCopy: self.ptr, count: self.len, deallocator: .none)
// Using non-failable String(decoding:as:) to handle invalid UTF-8 with replacement characters.
// Disable warning as it's a false positive.
// swiftlint:disable:next optional_data_string_conversion
return String(decoding: data, as: UTF8.self)
}

Expand Down
4 changes: 3 additions & 1 deletion Source/AwsCommonRuntimeKit/http/HTTP1Stream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import AwsCHttp
import Foundation

// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer.
// So mark it as unchecked Sendable.
/// An HTTP1Stream represents a single HTTP/1.1 specific Http Request/Response.
public class HTTP1Stream: HTTPStream {
public class HTTP1Stream: HTTPStream, @unchecked Sendable {
/// Stream keeps a reference to HttpConnection to keep it alive
private let httpConnection: HTTPClientConnection

Expand Down
4 changes: 3 additions & 1 deletion Source/AwsCommonRuntimeKit/http/HTTP2ClientConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import AwsCHttp
import AwsCIo
import Foundation

public class HTTP2ClientConnection: HTTPClientConnection {
// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer.
// So mark it as unchecked Sendable.
public class HTTP2ClientConnection: HTTPClientConnection, @unchecked Sendable {

/// Creates a new http2 stream from the `HTTPRequestOptions` given.
/// - Parameter requestOptions: An `HTTPRequestOptions` struct containing callbacks on
Expand Down
4 changes: 3 additions & 1 deletion Source/AwsCommonRuntimeKit/http/HTTP2Stream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import AwsCHttp
import Foundation

// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer.
// So mark it as unchecked Sendable.
/// An HTTP2Stream represents a single HTTP/2 specific HTTP Request/Response.
public class HTTP2Stream: HTTPStream {
public class HTTP2Stream: HTTPStream, @unchecked Sendable {
private let httpConnection: HTTPClientConnection?

// Called by Connection Manager
Expand Down
4 changes: 3 additions & 1 deletion Source/AwsCommonRuntimeKit/http/HTTP2StreamManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// SPDX-License-Identifier: Apache-2.0.
import AwsCHttp

// Swift cannot verify the sendability due to a pointer, and thread safety is handled in the C layer.
// So mark it as unchecked Sendable.
/// Manages a Pool of HTTP/2 Streams. Creates and manages HTTP/2 connections under the hood.
public class HTTP2StreamManager {
public class HTTP2StreamManager: @unchecked Sendable {
let rawValue: UnsafeMutablePointer<aws_http2_stream_manager>

public init(options: HTTP2StreamManagerOptions) throws {
Expand Down
Loading