Skip to content

Commit b55fe6a

Browse files
committed
Further streamlined the signal termination logic.
1 parent 85f41d5 commit b55fe6a

File tree

1 file changed

+27
-36
lines changed

1 file changed

+27
-36
lines changed

Sources/Signal.swift

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ public final class Signal<Value, Error: Swift.Error> {
8888
// `updateLock` must be acquired, and should fail gracefully if the
8989
// signal has terminated.
9090
//
91-
// - Check if the signal is terminating, and transition from `terminating`
92-
// to `terminated` if it is. Deliver the termination event after the
93-
// transitioning.
91+
// - Check if the signal is terminating. If it is, invoke `tryTerminate`
92+
// which transitions the state from `terminating` to `terminated`, and
93+
// delivers the termination event.
9494
//
9595
// Both `sendLock` and `updateLock` must be acquired. The check can be
9696
// relaxed, but the state must be checked again after the locks are
@@ -102,32 +102,37 @@ public final class Signal<Value, Error: Swift.Error> {
102102
// are intentionally allowed in the `terminating` checks below. As a
103103
// result, normal event deliveries need not acquire `updateLock`.
104104
// Nevertheless, this should not cause the termination event being
105-
// sent multiple times, since `shouldReallyTerminate` would not
106-
// respond to false positives.
105+
// sent multiple times, since `tryTerminate` would not respond to false
106+
// positives.
107107

108-
/// Return the terminating state if the signal is terminating , or `nil`
109-
/// otherwise.
108+
/// Try to terminate the signal.
110109
///
111-
/// Calling this method as a result of a false positive `terminating` check
112-
/// is permitted. `nil` would be returned in this case.
110+
/// If the signal is alive or has terminated, it fails gracefully. In
111+
/// other words, calling this method as a result of a false positive
112+
/// `terminating` check is permitted.
113113
///
114114
/// - note: The `updateLock` would be acquired.
115115
///
116-
/// - returns: The terminating state or `nil`.
116+
/// - returns: `true` if the attempt succeeds. `false` otherwise.
117117
@inline(__always)
118-
func shouldReallyTerminate() -> TerminatingState<Value, Error>? {
118+
func tryTerminate() -> Bool {
119119
// Acquire `updateLock`. If the termination has still not yet been
120120
// handled, take it over and bump the status to `terminated`.
121121
signal.updateLock.lock()
122122

123123
if case let .terminating(state) = signal.state {
124124
signal.state = .terminated
125125
signal.updateLock.unlock()
126-
return state
126+
127+
for observer in state.observers {
128+
observer.action(state.event)
129+
}
130+
131+
return true
127132
}
128-
133+
129134
signal.updateLock.unlock()
130-
return nil
135+
return false
131136
}
132137

133138
if event.isTerminating {
@@ -160,14 +165,12 @@ public final class Signal<Value, Error: Swift.Error> {
160165
if signal.sendLock.try() {
161166
// Check whether the terminating state has been handled by a
162167
// concurrent sender. If not, handle it.
163-
if let terminatingState = shouldReallyTerminate() {
164-
for observer in terminatingState.observers {
165-
observer.action(terminatingState.event)
166-
}
167-
}
168-
168+
let shouldDispose = tryTerminate()
169169
signal.sendLock.unlock()
170-
signal.swapDisposable()?.dispose()
170+
171+
if shouldDispose {
172+
signal.swapDisposable()?.dispose()
173+
}
171174
}
172175
} else {
173176
signal.updateLock.unlock()
@@ -203,12 +206,8 @@ public final class Signal<Value, Error: Swift.Error> {
203206

204207
// Check if the status has been bumped to `terminating` due to a
205208
// concurrent or a recursive termination event.
206-
if case .terminating = signal.state, let terminatingState = shouldReallyTerminate() {
207-
for observer in terminatingState.observers {
208-
observer.action(terminatingState.event)
209-
}
210-
211-
shouldDispose = true
209+
if case .terminating = signal.state {
210+
shouldDispose = tryTerminate()
212211
}
213212
}
214213

@@ -220,15 +219,7 @@ public final class Signal<Value, Error: Swift.Error> {
220219
// protected section.
221220
if !shouldDispose, case .terminating = signal.state {
222221
signal.sendLock.lock()
223-
224-
if let terminatingState = shouldReallyTerminate() {
225-
for observer in terminatingState.observers {
226-
observer.action(terminatingState.event)
227-
}
228-
229-
shouldDispose = true
230-
}
231-
222+
shouldDispose = tryTerminate()
232223
signal.sendLock.unlock()
233224
}
234225

0 commit comments

Comments
 (0)