Skip to content

Commit 225a326

Browse files
Seweryn Plażuksewerynplazuk
authored andcommitted
Add thread safety to Clock
Signed-off-by: Seweryn Plażuk <seweryn.plazuk@gmail.com>
1 parent 1b2d25b commit 225a326

3 files changed

Lines changed: 45 additions & 4 deletions

File tree

Sources/Clock.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,20 @@ public typealias AnnotatedTime = (
2525
/// print(Clock.now)
2626
/// ```
2727
public struct Clock {
28-
private static var stableTime: TimeFreeze? {
29-
didSet {
30-
self.storage.stableTime = self.stableTime
28+
private static let syncQueue = DispatchQueue(label: "kronos.stable.time", attributes: .concurrent)
29+
30+
private static var _stableTime: TimeFreeze?
31+
static var stableTime: TimeFreeze? {
32+
get {
33+
self.syncQueue.sync {
34+
return self._stableTime
35+
}
36+
}
37+
set {
38+
self.syncQueue.async(flags: .barrier) {
39+
self._stableTime = newValue
40+
self.storage.stableTime = newValue
41+
}
3142
}
3243
}
3344

Sources/TimeFreeze.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ private let kOffsetKey = "Offset"
77
struct TimeFreeze {
88
private let uptime: TimeInterval
99
private let timestamp: TimeInterval
10-
private let offset: TimeInterval
10+
let offset: TimeInterval
1111

1212
/// The stable timestamp adjusted by the most accurate offset known so far.
1313
var adjustedTimestamp: TimeInterval {

Tests/KronosTests/ClockTests.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,34 @@ final class ClockTests: XCTestCase {
3838

3939
self.waitForExpectations(timeout: 20)
4040
}
41+
42+
func testStableTimeThreadSafety() {
43+
let expectation = self.expectation(description: "Concurrent access to stableTime")
44+
expectation.expectedFulfillmentCount = 10
45+
46+
let incrementBlock = {
47+
for _ in 0..<1000 {
48+
let newOffset = {
49+
if let offset = Clock.stableTime?.offset {
50+
return offset + 1
51+
} else {
52+
return 0
53+
}
54+
}()
55+
Clock.stableTime = TimeFreeze(offset: newOffset)
56+
}
57+
}
58+
59+
for _ in 0..<10 {
60+
DispatchQueue.global().async {
61+
incrementBlock()
62+
expectation.fulfill()
63+
}
64+
}
65+
66+
self.waitForExpectations(timeout: 2)
67+
68+
XCTAssertEqual(Clock.stableTime?.offset, 1000)
69+
}
70+
4171
}

0 commit comments

Comments
 (0)