Skip to content

Commit

Permalink
Add thread safety to Clock
Browse files Browse the repository at this point in the history
Signed-off-by: Seweryn Plażuk <[email protected]>
  • Loading branch information
Seweryn Plażuk authored and sewerynplazuk committed Feb 1, 2024
1 parent a46542c commit 256fbb6
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 3 deletions.
4 changes: 4 additions & 0 deletions Kronos.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
930B39DD2051E6D300360BA2 /* TimeStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 930B39DC2051E6D300360BA2 /* TimeStorage.swift */; };
930B39E02051F26500360BA2 /* TimeStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 930B39DE2051F25300360BA2 /* TimeStorageTests.swift */; };
C201748E1BD5509D00E4FE18 /* Kronos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C20174831BD5509D00E4FE18 /* Kronos.framework */; };
E5481CD32B6BF3010072186E /* UnfairLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5481CD22B6BF3010072186E /* UnfairLock.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -57,6 +58,7 @@
C2C036D41C2B180D003FB853 /* UniversalFramework_Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = UniversalFramework_Base.xcconfig; sourceTree = "<group>"; };
C2C036D51C2B180D003FB853 /* UniversalFramework_Framework.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = UniversalFramework_Framework.xcconfig; sourceTree = "<group>"; };
C2C036D61C2B180D003FB853 /* UniversalFramework_Test.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = UniversalFramework_Test.xcconfig; sourceTree = "<group>"; };
E5481CD22B6BF3010072186E /* UnfairLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnfairLock.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -122,6 +124,7 @@
26447D7A1D6E54D400159BEE /* NTPProtocol.swift */,
26447D7B1D6E54D400159BEE /* TimeFreeze.swift */,
930B39DC2051E6D300360BA2 /* TimeStorage.swift */,
E5481CD22B6BF3010072186E /* UnfairLock.swift */,
);
path = Sources;
sourceTree = "<group>";
Expand Down Expand Up @@ -230,6 +233,7 @@
26447D7C1D6E54D400159BEE /* Clock.swift in Sources */,
26447D7D1D6E54D400159BEE /* DNSResolver.swift in Sources */,
26447D7E1D6E54D400159BEE /* InternetAddress.swift in Sources */,
E5481CD32B6BF3010072186E /* UnfairLock.swift in Sources */,
26447D811D6E54D400159BEE /* NTPClient.swift in Sources */,
26447D7F1D6E54D400159BEE /* Data+Bytes.swift in Sources */,
26447D841D6E54D400159BEE /* TimeFreeze.swift in Sources */,
Expand Down
29 changes: 26 additions & 3 deletions Sources/Clock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,38 @@ public typealias AnnotatedTime = (
/// print(Clock.now)
/// ```
public struct Clock {
private static var unfairLock = UnfairLock()
private static var _stableTime: TimeFreeze?
private static var _storage = TimeStorage(storagePolicy: .standard)

private static var stableTime: TimeFreeze? {
didSet {
self.storage.stableTime = self.stableTime
get {
self.unfairLock.synchronized {
return self._stableTime
}
}
set {
self.unfairLock.synchronized {
self._stableTime = newValue
self._storage.stableTime = newValue
}
}
}

/// Determines where the most current stable time is stored. Use TimeStoragePolicy.appGroup to share
/// between your app and an extension.
public static var storage = TimeStorage(storagePolicy: .standard)
public static var storage: TimeStorage {
get {
self.unfairLock.synchronized {
return self._storage
}
}
set {
self.unfairLock.synchronized {
self._storage = newValue
}
}
}

/// The most accurate timestamp that we have so far (nil if no synchronization was done yet)
public static var timestamp: TimeInterval? {
Expand Down
29 changes: 29 additions & 0 deletions Sources/UnfairLock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import os.lock

final class UnfairLock {
private let lockPointer: os_unfair_lock_t

init() {
self.lockPointer = .allocate(capacity: 1)
self.lockPointer.initialize(to: os_unfair_lock())
}

deinit {
self.lockPointer.deinitialize(count: 1)
self.lockPointer.deallocate()
}

func lock() {
os_unfair_lock_lock(self.lockPointer)
}

func unlock() {
os_unfair_lock_unlock(self.lockPointer)
}

func synchronized<T>(_ block: () -> T) -> T {
self.lock()
defer { self.unlock() }
return block()
}
}

0 comments on commit 256fbb6

Please sign in to comment.