@@ -100,7 +100,12 @@ public final class Signal<Value, Error: Swift.Error> {
100100 /// Nevertheless, this should not cause the termination event being
101101 /// sent multiple times, since `tryTerminate` would not respond to false
102102 /// positives.
103- private var state : State
103+ private var state : State {
104+ get { return _state. value }
105+ set { _state. value = newValue }
106+ }
107+
108+ private let _state : Atomic < State >
104109
105110 /// Used to ensure that state updates are serialized.
106111 private let updateLock : Lock
@@ -112,7 +117,7 @@ public final class Signal<Value, Error: Swift.Error> {
112117 private var hasDeinitialized : Bool
113118
114119 fileprivate init ( _ generator: ( Observer ) -> Disposable ? ) {
115- state = . alive( AliveState ( observers: Bag ( ) ) )
120+ _state = Atomic ( . alive( AliveState ( observers: Bag ( ) ) ) )
116121
117122 updateLock = Lock . make ( )
118123 sendLock = Lock . make ( )
@@ -163,43 +168,19 @@ public final class Signal<Value, Error: Swift.Error> {
163168 } else {
164169 var result = OperationResult . none
165170
166- // The `terminating` status check is performed twice for two different
167- // purposes:
168- //
169- // 1. Within the main protected section
170- // It guarantees that a recursive termination event sent by a
171- // downstream consumer, is immediately processed and need not compete
172- // with concurrent pending senders (if any).
173- //
174- // Termination events sent concurrently may also be caught here, but
175- // not necessarily all of them due to data races.
176- //
177- // 2. After the main protected section
178- // It ensures the termination event sent concurrently that are not
179- // caught by (1) due to data races would still be processed.
180- //
181- // The related PR on the race conditions:
182- // https://github.com/ReactiveCocoa/ReactiveSwift/pull/112
183-
184171 self . sendLock. lock ( )
185172
186173 if case let . alive( state) = self . state {
187174 for observer in state. observers {
188175 observer. action ( event)
189176 }
190-
191- // Check if the status has been bumped to `terminating` due to a
192- // concurrent or a recursive termination event.
193- if case . terminating = self . state {
194- result = self . tryToCommitTermination ( acquired: self . sendLock)
195- }
196177 }
197178
198179 self . sendLock. unlock ( )
199180
200- // Check if the status has been bumped to `terminating` due to a
201- // concurrent termination event that has not been caught in the main
202- // protected section.
181+ // Check if any observer or any concurrent sender has been bumped to
182+ // `terminating` due to a concurrent termination event that has not been
183+ // caught in the main protected section.
203184 if result == . none, case . terminating = self . state {
204185 result = self . tryToCommitTermination ( )
205186 }
0 commit comments