Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Experimental] Swift Package Manager / Atomics #26

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
25 changes: 25 additions & 0 deletions BAPromise.xcodeproj/Atomics_Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
25 changes: 25 additions & 0 deletions BAPromise.xcodeproj/BAPromiseTests_Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
25 changes: 25 additions & 0 deletions BAPromise.xcodeproj/BAPromise_Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
25 changes: 25 additions & 0 deletions BAPromise.xcodeproj/_AtomicsShims_Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "9999"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BAPromise::BAPromise"
BuildableName = "BAPromise.framework"
BlueprintName = "BAPromise"
ReferencedContainer = "container:BAPromise.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BAPromise::BAPromiseTests"
BuildableName = "BAPromiseTests.xctest"
BlueprintName = "BAPromiseTests"
ReferencedContainer = "container:BAPromise.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env make

lib:
swift build
linux:
swift build -Xcc -mcx16 -Xswiftc -DENABLE_DOUBLEWIDE_ATOMICS -c release
clean:
rm -rf .build
test:
swift test
test-generate:
swift test --generate-linuxmain
doc:
jazzy
xcode:
swift package generate-xcodeproj --enable-code-coverage --output BAPromise-SwiftPackage.xcodeproj
16 changes: 16 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"object": {
"pins": [
{
"package": "swift-atomics",
"repositoryURL": "https://github.com/apple/swift-atomics.git",
"state": {
"branch": null,
"revision": "26e346cd64f6b92d4089e7fafe2f8e82f60ddb8c",
"version": "0.0.2"
}
}
]
},
"version": 1
}
32 changes: 32 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "BAPromise",
platforms: [
.iOS(.v10), .tvOS(.v10), .watchOS(.v3), .macOS(.v10_15)
],
products: [
.library(
name: "BAPromise",
targets: ["BAPromise"]),
],
dependencies: [
.package(
url: "https://github.com/apple/swift-atomics.git",
from: "0.0.1"
)
],
targets: [
.target(
name: "BAPromise",
dependencies: [
.product(name: "Atomics", package: "swift-atomics")
]),
.testTarget(
name: "BAPromiseTests",
dependencies: ["BAPromise"]),
]
)
34 changes: 26 additions & 8 deletions Classes/Promise.swift → Sources/BAPromise/Promise.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
//

import Foundation
import Atomics

internal class AtomicCancel {

private let underlying = ManagedAtomic<Int>(0)

public var isCanceled: Bool {
atomic_thread_fence(memory_order_seq_cst)
return underlying == 0 ? false : true
return underlying.load(ordering: .relaxed) == 0 ? false : true
}

public func cancel() {
OSAtomicIncrement32Barrier(&underlying);
underlying.wrappingIncrement(ordering: .relaxed)
}

public init() {
underlying = 0
underlying.store(0, ordering: .relaxed)
}

private var underlying: Int32
}

public enum PromiseResult<ValueType> {
Expand Down Expand Up @@ -171,7 +171,7 @@ public class Promise<ValueType> : PromiseCancelToken {
if let queue = queue {
queue.async(execute: block)
} else if let thread = thread {
thread.baAsync(block)
thread.async(block)
}
}
}
Expand Down Expand Up @@ -259,7 +259,7 @@ public class Promise<ValueType> : PromiseCancelToken {

public func cancelled(_ onCancel: @escaping Canceled, thread: Thread) {
let wrappedBlock = {
thread.baAsync(onCancel)
thread.async(onCancel)
}

PromiseCancelToken.queue.async {
Expand Down Expand Up @@ -353,6 +353,7 @@ extension Promise {
extension Promise {
public typealias ThenRejected<ReturnType> = (Error) -> PromiseResult<ReturnType>

@discardableResult
public func then<ReturnType>(_ onFulfilled: @escaping ((ValueType) throws -> PromiseResult<ReturnType>),
rejected: @escaping ThenRejected<ReturnType> = { return .failure($0) },
always: Always? = nil,
Expand All @@ -379,6 +380,7 @@ extension Promise {
return returnedPromise
}

@discardableResult
public func then<ReturnType>(_ onFulfilled: @escaping ((ValueType) throws -> PromiseResult<ReturnType>),
rejected: @escaping ThenRejected<ReturnType> = { return .failure($0) },
always: Always? = nil,
Expand Down Expand Up @@ -560,3 +562,19 @@ extension Array where Element == Completable {
return returnedPromise
}
}

typealias dispatch_block_t_swift = () -> Void

extension Thread {

func runBlock(_ block: @escaping dispatch_block_t_swift) {
block()
}

func async(_ block: @escaping dispatch_block_t_swift) {
perform(Selector(("runBlock:")),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At one point I had this in Swift. I was getting intermittent memory failures, though, and moved it back to ObjC. I'll dig up the commit and see if I can remember why.

That said, Realm 5 finally introduced Queue-specific realm objects in addition to the Thread-specific realm objects, so my primary need for all this thread nonsense could go away soon.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the commit where I had stopped using Swift for this. I think that the Swift compiler was doing the wrong thing with block and leading to occasional memory failures (use after release)
a13148e

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be fixed now with swift 5.3? Release notes mention runtime memory improvements.
Fixed the project file!!

on: self,
with: block,
waitUntilDone: false)
}
}
27 changes: 27 additions & 0 deletions Tests/BAPromiseTests/BAPromiseTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import XCTest
@testable import BAPromise

enum TestError: Error {
case error
}

final class BAPromiseTests: XCTestCase {
func testExample() {
let promise = Promise<Int>()
promise.then({ (myInt) -> PromiseResult<Int> in
XCTAssertEqual(myInt, 42)
return .success(myInt)
}, rejected: { (error) -> PromiseResult<Int> in
XCTFail()
return .failure(TestError.error)
},
always: {
// always
}, queue: .main)
promise.fulfill(with: .success(42))
}

static var allTests = [
("testExample", testExample),
]
}
File renamed without changes.
9 changes: 9 additions & 0 deletions Tests/BAPromiseTests/XCTestManifests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import XCTest

#if !canImport(ObjectiveC)
public func allTests() -> [XCTestCaseEntry] {
return [
testCase(BAPromiseTests.allTests),
]
}
#endif
7 changes: 7 additions & 0 deletions Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import XCTest

import BAPromiseTests

var tests = [XCTestCaseEntry]()
tests += BAPromiseTests.allTests()
XCTMain(tests)