Use a State struct for mutable properties in Sendable types (#191)

This PR introduces a pattern of grouping mutable properties within the
`Sendable` types, encapsulated within a `State` struct. This approach
enables simultaneous updates to multiple properties and serves as a tool
against reentrancy issues.
This commit is contained in:
Dmitry Kovba
2025-07-03 01:19:55 -07:00
committed by GitHub
parent 633205f171
commit 8573b80fac
+13 -9
View File
@@ -52,16 +52,20 @@ final class VsockProxy: Sendable {
private let action: Action
private let port: UInt32
private let udsPerms: UInt32?
@SendableProperty
private var listener: Socket?
private let log: Logger?
@SendableProperty
private var t: Task<(), Never>?
private var state = State()
private struct State {
var listener: Socket?
var task: Task<(), Never>?
}
}
extension VsockProxy {
func close() throws {
guard let listener else {
guard let listener = state.listener else {
return
}
@@ -70,7 +74,7 @@ extension VsockProxy {
if fm.fileExists(atPath: self.path.path) {
try FileManager.default.removeItem(at: self.path)
}
self.t?.cancel()
state.task?.cancel()
}
func start() throws {
@@ -98,7 +102,7 @@ extension VsockProxy {
)
let uds = try Socket(type: type)
try uds.listen()
self.listener = uds
state.listener = uds
try self.acceptLoop(socketType: .unix)
}
@@ -110,18 +114,18 @@ extension VsockProxy {
)
let vsock = try Socket(type: type)
try vsock.listen()
self.listener = vsock
state.listener = vsock
try self.acceptLoop(socketType: .vsock)
}
private func acceptLoop(socketType: SocketType) throws {
guard let listener else {
guard let listener = state.listener else {
return
}
let stream = try listener.acceptStream()
self.t = Task {
state.task = Task {
do {
for try await conn in stream {
Task {