Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ Packages/
Package.pins
Package.resolved
.build/
.DS_Store
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
language: objective-c
osx_image: xcode9
osx_image: xcode10.1

env:
- ACTION=test PLATFORM=Mac DESTINATION='platform=OS X'
- ACTION=test PLATFORM=iOS DESTINATION='platform=iOS Simulator,name=iPhone 7'
- ACTION=test PLATFORM=tvOS DESTINATION='platform=tvOS Simulator,name=Apple TV 1080p'
- ACTION=test PLATFORM=iOS DESTINATION='platform=iOS Simulator,name=iPhone XS'
- ACTION=test PLATFORM=tvOS DESTINATION='platform=tvOS Simulator,name=Apple TV 4K'

script:
- swift test
41 changes: 20 additions & 21 deletions Concurrency.xcodeproj/Concurrency_Info.plist
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
<?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>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>0.6.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.6.1</string>
<key>NSPrincipalClass</key>
<string></string>
<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,4 @@
module ObjCBridges {
umbrella "/Users/yiw/Uber/GitHub/swift-concurrency/Sources/ObjCBridges/include"
export *
}
25 changes: 25 additions & 0 deletions Concurrency.xcodeproj/ObjCBridges_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>
466 changes: 326 additions & 140 deletions Concurrency.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
5 changes: 4 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ let package = Package(
],
dependencies: [],
targets: [
.target(
name: "ObjCBridges",
dependencies:[]),
.target(
name: "Concurrency",
dependencies: []),
dependencies: ["ObjCBridges"]),
.testTarget(
name: "ConcurrencyTests",
dependencies: ["Concurrency"]),
Expand Down
50 changes: 27 additions & 23 deletions Sources/Concurrency/AtomicInt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import Foundation
import libkern
import ObjCBridges

/// A concurrency utility class that supports locking-free synchronization on mutating an integer
/// value. Unlike using a lock, concurrent read and write accesses to this class is allowed. At
Expand All @@ -28,8 +29,8 @@ public class AtomicInt {
get {
// Create a memory barrier to ensure the entire memory stack is in sync so we
// can safely retrieve the value. This guarantees the initial value is in sync.
OSMemoryBarrier()
return Int(wrappedValue)
atomic_thread_fence(memory_order_seq_cst)
return wrappedValue
}
set {
while true {
Expand All @@ -45,7 +46,7 @@ public class AtomicInt {
///
/// - parameter initialValue: The initial value.
public init(initialValue: Int) {
wrappedValue = Int64(initialValue)
wrappedValue = initialValue
}

/// Atomically sets the new value, if the current value equals the expected value.
Expand All @@ -55,53 +56,52 @@ public class AtomicInt {
/// - returns: true if the comparison succeeded and the value is set. false otherwise.
@discardableResult
public func compareAndSet(expect: Int, newValue: Int) -> Bool {
return OSAtomicCompareAndSwap64Barrier(Int64(expect), Int64(newValue), &wrappedValue)
var mutableExpected = expect
return AtomicBridges.compare(wrappedValueOpaquePointer, withExpected: UnsafeMutablePointer<Int>(&mutableExpected), andSwap: newValue)
}

/// Atomically increment the value and retrieve the new value.
///
/// - returns: The new value after incrementing.
@discardableResult
public func incrementAndGet() -> Int {
let result = OSAtomicIncrement64Barrier(&wrappedValue)
return Int(result)
while true {
let oldValue = self.value
let newValue = oldValue + 1
if self.compareAndSet(expect: oldValue, newValue: newValue) {
return newValue
}
}
}

/// Atomically decrement the value and retrieve the new value.
///
/// - returns: The new value after decrementing.
@discardableResult
public func decrementAndGet() -> Int {
let result = OSAtomicDecrement64Barrier(&wrappedValue)
return Int(result)
while true {
let oldValue = self.value
let newValue = oldValue - 1
if self.compareAndSet(expect: oldValue, newValue: newValue) {
return newValue
}
}
}

/// Atomically increment the value and retrieve the old value.
///
/// - returns: The old value before incrementing.
@discardableResult
public func getAndIncrement() -> Int {
while true {
let oldValue = self.value
let newValue = oldValue + 1
if self.compareAndSet(expect: oldValue, newValue: newValue) {
return oldValue
}
}
return AtomicBridges.fetchAndIncrementBarrier(wrappedValueOpaquePointer)
}

/// Atomically decrement the value and retrieve the old value.
///
/// - returns: The old value before decrementing.
@discardableResult
public func getAndDecrement() -> Int {
while true {
let oldValue = self.value
let newValue = oldValue - 1
if self.compareAndSet(expect: oldValue, newValue: newValue) {
return oldValue
}
}
return AtomicBridges.fetchAndDecrementBarrier(wrappedValueOpaquePointer)
}

/// Atomically sets to the given new value and returns the old value.
Expand All @@ -120,5 +120,9 @@ public class AtomicInt {

// MARK: - Private

private var wrappedValue: Int64
private var wrappedValue: Int

private var wrappedValueOpaquePointer: OpaquePointer {
return OpaquePointer(UnsafeMutablePointer<Int>(&wrappedValue))
}
}
33 changes: 33 additions & 0 deletions Sources/ObjCBridges/AtomicBridges.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Copyright (c) 2018. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import "AtomicBridges.h"

@implementation AtomicBridges

+ (long)fetchAndIncrementBarrier:(_Atomic(long) *)value {
return atomic_fetch_add(value, 1);
}

+ (long)fetchAndDecrementBarrier:(_Atomic(long) *)value {
return atomic_fetch_sub(value, 1);
}

+ (bool)compare:(_Atomic(long) *)value withExpected:(long *)expected andSwap:(long)desired {
return atomic_compare_exchange_strong(value, expected, desired);
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@
// limitations under the License.
//

import XCTest
@testable import ConcurrencyTests

XCTMain([
testCase(AtomicBoolTests.allTests),
testCase(AtomicIntTests.allTests),
testCase(AtomicReferenceTests.allTests),
testCase(CountDownLatchTests.allTests),
testCase(ConcurrentSequenceExecutorTests.allTests),
])
#import <Foundation/Foundation.h>
#import <stdatomic.h>

NS_ASSUME_NONNULL_BEGIN

@interface AtomicBridges: NSObject

+ (long)fetchAndIncrementBarrier:(_Atomic(long) *)value;

+ (long)fetchAndDecrementBarrier:(_Atomic(long) *)value;

+ (bool)compare:(_Atomic(long) *)value withExpected:(long *)expected andSwap:(long)desired;

@end

NS_ASSUME_NONNULL_END