-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #20 from ra1028/1.3.0
1.3.0
- Loading branch information
Showing
17 changed files
with
368 additions
and
216 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import Foundation | ||
|
||
final class AtomicBool: ExpressibleByBooleanLiteral { | ||
private let rawValue = UnsafeMutablePointer<Int32>.allocate(capacity: 1) | ||
|
||
var value: Bool { | ||
return rawValue.pointee == true.int32Value | ||
} | ||
|
||
init(booleanLiteral value: Bool) { | ||
rawValue.initialize(to: value.int32Value) | ||
} | ||
|
||
deinit { | ||
rawValue.deinitialize() | ||
rawValue.deallocate(capacity: 1) | ||
} | ||
|
||
func compareAndSwapBarrier(old: Bool, new: Bool) -> Bool { | ||
return OSAtomicCompareAndSwap32Barrier(old.int32Value, new.int32Value, rawValue) | ||
} | ||
} | ||
|
||
private extension Bool { | ||
var int32Value: Int32 { | ||
return self ? 1 : 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import Foundation | ||
|
||
/// Coordinates the operation of multiple threads of execution. | ||
struct Lock { | ||
@available(iOS 10.0, *) | ||
@available(macOS 10.12, *) | ||
@available(tvOS 10.0, *) | ||
@available(watchOS 3.0, *) | ||
private final class OSUnfairLock: NSLocking { | ||
private let _lock = os_unfair_lock_t.allocate(capacity: 1) | ||
|
||
init() { | ||
_lock.initialize(to: os_unfair_lock()) | ||
} | ||
|
||
deinit { | ||
_lock.deinitialize() | ||
_lock.deallocate(capacity: 1) | ||
} | ||
|
||
func lock() { | ||
os_unfair_lock_lock(_lock) | ||
} | ||
|
||
func unlock() { | ||
os_unfair_lock_unlock(_lock) | ||
} | ||
} | ||
|
||
private final class PosixThreadMutex: NSLocking { | ||
private let _lock = UnsafeMutablePointer<pthread_mutex_t>.allocate(capacity: 1) | ||
|
||
init(recursive: Bool = false) { | ||
_lock.initialize(to: pthread_mutex_t()) | ||
|
||
if recursive { | ||
let attributes = UnsafeMutablePointer<pthread_mutexattr_t>.allocate(capacity: 1) | ||
attributes.initialize(to: pthread_mutexattr_t()) | ||
pthread_mutexattr_init(attributes) | ||
pthread_mutexattr_settype(attributes, Int32(PTHREAD_MUTEX_RECURSIVE)) | ||
pthread_mutex_init(_lock, attributes) | ||
|
||
pthread_mutexattr_destroy(attributes) | ||
attributes.deinitialize() | ||
attributes.deallocate(capacity: 1) | ||
} else { | ||
pthread_mutex_init(_lock, nil) | ||
} | ||
} | ||
|
||
deinit { | ||
pthread_mutex_destroy(_lock) | ||
_lock.deinitialize() | ||
_lock.deallocate(capacity: 1) | ||
} | ||
|
||
func lock() { | ||
pthread_mutex_lock(_lock) | ||
} | ||
|
||
func unlock() { | ||
pthread_mutex_unlock(_lock) | ||
} | ||
} | ||
|
||
private let inner: NSLocking | ||
|
||
/// Attempts to acquire a lock, blocking a thread’s execution until the lock can be acquired. | ||
func lock() { | ||
inner.lock() | ||
} | ||
|
||
/// Relinquishes a previously acquired lock. | ||
func unlock() { | ||
inner.unlock() | ||
} | ||
|
||
/// Create a lock. | ||
/// | ||
/// - Parameters: | ||
/// - recursive: A Bool value indicating whether locking is recursive. | ||
/// - usePosixThreadMutexForced: Force to use Posix thread mutex. | ||
init(recursive: Bool, usePosixThreadMutexForced: Bool = false) { | ||
if #available(*, iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0), !usePosixThreadMutexForced, !recursive { | ||
inner = OSUnfairLock() | ||
} else { | ||
inner = PosixThreadMutex(recursive: recursive) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import XCTest | ||
@testable import VueFlux | ||
@testable import VueFluxReactive | ||
|
||
protocol AtomicBoolProtocol: ExpressibleByBooleanLiteral { | ||
var value: Bool { get } | ||
|
||
func compareAndSwapBarrier(old: Bool, new: Bool) -> Bool | ||
} | ||
|
||
extension VueFlux.AtomicBool: AtomicBoolProtocol {} | ||
extension VueFluxReactive.AtomicBool: AtomicBoolProtocol {} | ||
|
||
final class AtomicBoolTests: XCTestCase { | ||
func testAtomicBool() { | ||
func runTest<AtomicBool: AtomicBoolProtocol>(for type: AtomicBool.Type) { | ||
let atomicBool: AtomicBool = true | ||
|
||
XCTAssertTrue(atomicBool.value) | ||
|
||
let result1 = atomicBool.compareAndSwapBarrier(old: true, new: false) | ||
|
||
XCTAssertFalse(atomicBool.value) | ||
XCTAssertTrue(result1) | ||
|
||
let result2 = atomicBool.compareAndSwapBarrier(old: true, new: false) | ||
|
||
XCTAssertFalse(atomicBool.value) | ||
XCTAssertFalse(result2) | ||
} | ||
|
||
runTest(for: VueFlux.AtomicBool.self) | ||
runTest(for: VueFluxReactive.AtomicBool.self) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import XCTest | ||
@testable import VueFlux | ||
@testable import VueFluxReactive | ||
|
||
protocol LockProtocol { | ||
func lock() | ||
func unlock() | ||
} | ||
|
||
extension VueFlux.Lock: LockProtocol {} | ||
extension VueFluxReactive.Lock: LockProtocol {} | ||
|
||
final class LockTests: XCTestCase { | ||
func testLock() { | ||
func runTest(synchronized: @escaping (() -> Void) -> Void) { | ||
let queue = DispatchQueue(label: "testLock", attributes: .concurrent) | ||
let group = DispatchGroup() | ||
|
||
var value = 0 | ||
for _ in (1...100) { | ||
queue.async(group: group) { | ||
synchronized { | ||
value += 1 | ||
value -= 1 | ||
value += 2 | ||
value -= 2 | ||
} | ||
} | ||
} | ||
|
||
_ = group.wait(timeout: .now() + 10) | ||
XCTAssertEqual(value, 0) | ||
} | ||
|
||
func runNonRecursiveTest<Lock: LockProtocol>(for lock: Lock) { | ||
runTest { criticalSection in | ||
lock.lock() | ||
criticalSection() | ||
lock.unlock() | ||
} | ||
} | ||
|
||
func runRecursiveTest<Lock: LockProtocol>(for lock: Lock) { | ||
runTest { criticalSection in | ||
lock.lock() | ||
lock.lock() | ||
criticalSection() | ||
lock.unlock() | ||
lock.unlock() | ||
} | ||
} | ||
|
||
runNonRecursiveTest(for: VueFlux.Lock(recursive: false)) | ||
runNonRecursiveTest(for: VueFluxReactive.Lock(recursive: false)) | ||
runNonRecursiveTest(for: VueFlux.Lock(recursive: false, usePosixThreadMutexForced: true)) | ||
runNonRecursiveTest(for: VueFluxReactive.Lock(recursive: false, usePosixThreadMutexForced: true)) | ||
|
||
runRecursiveTest(for: VueFlux.Lock(recursive: true)) | ||
runRecursiveTest(for: VueFluxReactive.Lock(recursive: true)) | ||
runRecursiveTest(for: VueFlux.Lock(recursive: true, usePosixThreadMutexForced: true)) | ||
runRecursiveTest(for: VueFluxReactive.Lock(recursive: true, usePosixThreadMutexForced: true)) | ||
} | ||
} |
Oops, something went wrong.