Skip to content

Commit 372314d

Browse files
authored
avoid race conditions in stream (#173)
* avoid race conditions in stream * fix
1 parent 1024df2 commit 372314d

File tree

2 files changed

+31
-10
lines changed

2 files changed

+31
-10
lines changed

Networking/Sources/Networking/Stream.swift

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,32 +62,45 @@ public final class Stream: Sendable {
6262
}
6363

6464
public func receive() async -> Data? {
65-
if let data = nextData.value {
66-
nextData.value = nil
65+
if let data = nextData.exchange(nil) {
6766
return data
6867
}
6968
return await channel.receive()
7069
}
7170

7271
public func receiveByte() async -> UInt8? {
73-
if var data = nextData.value {
74-
let byte = data.removeFirst()
75-
if data.isEmpty {
76-
nextData.value = nil
72+
let byte = nextData.write { nextData -> UInt8? in
73+
if var data = nextData {
74+
let byte = data.removeFirst()
75+
if data.isEmpty {
76+
nextData = nil
77+
} else {
78+
nextData = data
79+
}
80+
return byte
7781
} else {
78-
nextData.value = data
82+
return nil
7983
}
84+
}
85+
if let byte {
8086
return byte
8187
}
8288

8389
guard var data = await receive() else {
8490
return nil
8591
}
8692

87-
let byte = data.removeFirst()
93+
let byte2 = data.removeFirst()
8894
if !data.isEmpty {
89-
nextData.value = data
95+
// TODO: this can append data in wrong order if receiveByte is called concurrently
96+
nextData.write { nextData in
97+
if let currentData = nextData {
98+
nextData = currentData + data
99+
} else {
100+
nextData = data
101+
}
102+
}
90103
}
91-
return byte
104+
return byte2
92105
}
93106
}

Utils/Sources/Utils/ThreadSafeContainer.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ public final class ThreadSafeContainer<T>: @unchecked Sendable {
2424
}
2525
}
2626

27+
public func exchange(_ value: T) -> T {
28+
lock.withWriteLock {
29+
let ret = self.storage
30+
self.storage = value
31+
return ret
32+
}
33+
}
34+
2735
public var value: T {
2836
get {
2937
read { $0 }

0 commit comments

Comments
 (0)