Skip to content

Commit

Permalink
Replace NSRecursiveLock with pthread mutex in PropertyBox.
Browse files Browse the repository at this point in the history
  • Loading branch information
andersio committed May 12, 2017
1 parent 4510c3b commit b395238
Showing 1 changed file with 43 additions and 4 deletions.
47 changes: 43 additions & 4 deletions Sources/Property.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import Foundation
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Darwin.POSIX.pthread
#else
import Glibc
#endif
import enum Result.NoError

/// Represents a property that allows observation of its changes.
Expand Down Expand Up @@ -698,16 +702,51 @@ public final class MutableProperty<Value>: ComposableMutablePropertyProtocol {
/// The requirement of a `Value?` storage from composed properties prevents further
/// implementation sharing with `MutableProperty`.
private final class PropertyBox<Value> {
private let lock = NSRecursiveLock()
private let mutex: UnsafeMutablePointer<pthread_mutex_t>
private var _value: Value
var value: Value { return modify { $0 } }

init(_ value: Value) {
self._value = value
_value = value
mutex = .allocate(capacity: 1)
mutex.initialize(to: pthread_mutex_t())

let attr = UnsafeMutablePointer<pthread_mutexattr_t>.allocate(capacity: 1)
attr.initialize(to: pthread_mutexattr_t())

defer {
attr.deinitialize()
attr.deallocate(capacity: 1)
}

pthread_mutexattr_init(attr)
pthread_mutexattr_settype(attr, Int32(PTHREAD_MUTEX_RECURSIVE))
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
// The pthread mutex implementation of Darwin guarantees fairness by
// default. Since fairness is not a concern of properties anyway, it can
// be disabled.
pthread_mutexattr_setpolicy_np(attr, _PTHREAD_MUTEX_POLICY_FIRSTFIT)
#endif

pthread_mutex_init(mutex, attr)
pthread_mutexattr_destroy(attr)
}

deinit {
pthread_mutex_destroy(mutex)
mutex.deinitialize()
mutex.deallocate(capacity: 1)
}

func modify<Result>(didSet: (Value) -> Void = { _ in }, _ action: (inout Value) throws -> Result) rethrows -> Result {
lock.lock(); defer { didSet(_value); lock.unlock() }
let status = pthread_mutex_lock(mutex)
assert(status == 0, "Failed to acquire the property box recursive lock. Status code: \(status)")

defer {
didSet(_value)
pthread_mutex_unlock(mutex)
}

return try action(&_value)
}
}
Expand Down

0 comments on commit b395238

Please sign in to comment.