-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Update Update to RELEASE_2024 * Optimize MovableLock API interface * Add UpdateTests
- Loading branch information
Showing
10 changed files
with
234 additions
and
142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
// | ||
// Update.swift | ||
// OpenSwiftUI | ||
// | ||
// Audited for RELEASE_2024 | ||
// Status: Blocked by Signpost | ||
// ID: EA173074DA35FA471DC70643259B7E74 (RELEASE_2021) | ||
// ID: 61534957AEEC2EDC447ABDC13B4D426F (RELEASE_2024) | ||
|
||
internal import COpenSwiftUICore | ||
internal import OpenGraphShims | ||
import Foundation | ||
|
||
package enum Update { | ||
private final class TraceHost {} | ||
static let trackHost: AnyObject = TraceHost() | ||
|
||
private static var depth = 0 | ||
private static var dispatchDepth = 0 | ||
private static let _lock = MovableLock.create() | ||
private static var actions: [() -> Void] = [] | ||
private static let lockAssertionsAreEnabled = EnvironmentHelper.bool(for: "OPENSWIFTUI_ASSERT_LOCKS") | ||
|
||
@inlinable | ||
package static var isActive: Bool { | ||
depth != 0 | ||
} | ||
|
||
@inlinable | ||
package static var threadIsUpdating: Bool { | ||
depth < dispatchDepth ? isOwner : false | ||
} | ||
|
||
@inlinable | ||
package static func assertIsActive() { | ||
assert(isActive) | ||
} | ||
|
||
package static func lock() { | ||
_lock.lock() | ||
} | ||
package static func unlock() { | ||
_lock.unlock() | ||
} | ||
|
||
package static var isOwner: Bool { | ||
_lock.isOwner | ||
} | ||
|
||
package static func wait() { | ||
_lock.wait() | ||
} | ||
|
||
package static func broadcast() { | ||
_lock.broadcast() | ||
} | ||
|
||
package static func assertIsLocked() { | ||
guard lockAssertionsAreEnabled else { | ||
return | ||
} | ||
guard isOwner else { | ||
fatalError("OpenSwiftUI is active without having taken its own lock - missing Update.ensure()?") | ||
} | ||
} | ||
|
||
package static func begin() { | ||
lock() | ||
depth += 1 | ||
if depth == 1 { | ||
// TODO: Signpost.renderUpdate.trace + trackHost | ||
} | ||
} | ||
|
||
package static func end() { | ||
if depth == 1 { | ||
dispatchActions() | ||
// TODO: Signpost.renderUpdate.trace + trackHost | ||
} | ||
depth -= 1 | ||
unlock() | ||
} | ||
|
||
package static func enqueueAction(_ action: @escaping () -> Void) { | ||
begin() | ||
actions.append(action) | ||
end() | ||
} | ||
|
||
@inlinable | ||
@inline(__always) | ||
package static func locked<T>(_ body: () throws -> T) rethrows -> T { | ||
lock() | ||
defer { unlock() } | ||
return try body() | ||
} | ||
|
||
package static func syncMain(_ body: () -> Void) { | ||
#if os(WASI) | ||
// FIXME: See #76 | ||
body() | ||
#else | ||
if Thread.isMainThread { | ||
body() | ||
} else { | ||
withoutActuallyEscaping(body) { escapableBody in | ||
let context = AnyRuleContext(attribute: AnyOptionalAttribute.current.identifier) | ||
MovableLock.syncMain(lock: _lock) { | ||
#if canImport(Darwin) | ||
context.update(body: escapableBody) | ||
#else | ||
fatalError("See #39") | ||
#endif | ||
} | ||
} | ||
} | ||
#endif | ||
} | ||
|
||
package static func ensure<T>(_ callback: () throws -> T) rethrows -> T { | ||
try locked { | ||
begin() | ||
defer { end() } | ||
return try callback() | ||
} | ||
} | ||
|
||
package static var canDispatch: Bool { | ||
assertIsLocked() | ||
guard depth == 1 else { | ||
return false | ||
} | ||
return !actions.isEmpty | ||
} | ||
|
||
package static func dispatchActions() { | ||
guard canDispatch else { return } | ||
repeat { | ||
let actions = Update.actions | ||
Update.actions = [] | ||
onMainThread { | ||
Signpost.postUpdateActions.traceInterval(object: trackHost, nil) { | ||
begin() | ||
let oldDispatchDepth = dispatchDepth | ||
let oldDepth = depth | ||
dispatchDepth = oldDepth | ||
defer { | ||
dispatchDepth = oldDispatchDepth | ||
end() | ||
} | ||
for action in actions { | ||
action() | ||
let newDepth = depth | ||
guard newDepth == oldDepth else { | ||
fatalError("Action caused unbalanced updates.") | ||
} | ||
} | ||
} | ||
} | ||
} while(!Update.actions.isEmpty) | ||
} | ||
|
||
package static func dispatchImmediately<T>(_ body: () -> T) -> T { | ||
begin() | ||
let oldDispatchDepth = dispatchDepth | ||
dispatchDepth = depth | ||
defer { | ||
dispatchDepth = oldDispatchDepth | ||
end() | ||
} | ||
return body() | ||
} | ||
} | ||
|
||
// FIXME: migrate to use @_extern(c, "xx") in Swift 6 | ||
extension MovableLock { | ||
@_silgen_name("_MovableLockSyncMain") | ||
static func syncMain(lock: MovableLock, body: @escaping () -> Void) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.