Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changes/fix-room-lazy-init-race
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
patch type="fixed" "Fix data races on Room's lazily initialized members (localParticipant, data channels, outgoingStreamManager, preConnectBuffer, metricsManager): concurrent first access could run a lazy initializer twice; they are now initialized eagerly in Room's initializer"
15 changes: 14 additions & 1 deletion Sources/LiveKit/Core/Room.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class Room: NSObject, @unchecked Sendable, ObservableObject, Loggable {

// MARK: - Metrics

lazy var metricsManager = MetricsManager()
let metricsManager = MetricsManager()

// MARK: - Public

Expand Down Expand Up @@ -270,6 +270,19 @@ public class Room: NSObject, @unchecked Sendable, ObservableObject, Loggable {
// log sdk & os versions
log("sdk: \(LiveKitSDK.version), ffi: \(LiveKitSDK.ffiVersion), os: \(String(describing: Utils.os()))(\(Utils.osVersionString())), modelId: \(String(describing: Utils.modelIdentifier() ?? "unknown"))")

// Force initialization of lazy members while `self` is still exclusively
// owned by this initializer. Lazy initialization is not atomic, and these
// members are reachable from isolation domains that do not serialize with
// each other, so a first touch after init could otherwise run an
// initializer twice. After this block every access is a plain read of
// already-initialized storage. The members stay `lazy` only because their
// initializers capture `self`, which a stored property cannot do.
_ = localParticipant
_ = subscriberDataChannel
_ = publisherDataChannel
_ = outgoingStreamManager
_ = preConnectBuffer

signalClient._delegate.set(delegate: self)

log()
Expand Down
Loading