Skip to content
Merged
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
7 changes: 7 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,19 @@ let cfCGTypes = envBoolValue("CF_CGTYPES", default: buildForDarwinPlatform)

var sharedCSettings: [CSetting] = [
.define("NDEBUG", .when(configuration: .release)),
// Rewrite malloc() to malloc_type_malloc() for type-isolated allocation buckets (xzone malloc).
.unsafeFlags(["-ftyped-memory-operations"], .when(platforms: .darwinPlatforms)),
.unsafeFlags(["-fmodules"]),
.define("_WASI_EMULATED_SIGNAL", .when(platforms: [.wasi])),
.unsafeFlags(["-isystem", swiftCorelibsPath], .when(platforms: .nonDarwinPlatforms)),
]

var sharedCxxSettings: [CXXSetting] = [
.define("NDEBUG", .when(configuration: .release)),
// Rewrite malloc() to malloc_type_malloc() for type-isolated allocation buckets (xzone malloc).
.unsafeFlags(["-ftyped-memory-operations"], .when(platforms: .darwinPlatforms)),
// Rewrite operator new/delete to typed variants (operator new(size_t, std::__type_descriptor_t)).
.unsafeFlags(["-ftyped-cxx-new-delete"], .when(platforms: .darwinPlatforms)),
.unsafeFlags(["-fcxx-modules"]),
.define("_WASI_EMULATED_SIGNAL", .when(platforms: [.wasi])),
.unsafeFlags(["-isystem", swiftCorelibsPath], .when(platforms: .nonDarwinPlatforms)),
Expand Down
2 changes: 1 addition & 1 deletion Sources/OpenSwiftUICore/Data/Update.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ package enum Update {

private static var depth = 0
private static var dispatchDepth = 0
private static let _lock = MovableLock.create()
private static let _lock = MovableLock()
private static var actions: [() -> Void] = []
private static let lockAssertionsAreEnabled = EnvironmentHelper.bool(for: "OPENSWIFTUI_ASSERT_LOCKS")

Expand Down
143 changes: 76 additions & 67 deletions Sources/OpenSwiftUI_SPI/Util/MovableLock.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// MovableLock.c
// OpenSwiftUI
//
// Audited for 3.5.2
// Audited for 6.5.4
// Status: Complete

#include "MovableLock.h"
Expand All @@ -17,8 +17,8 @@
extern pthread_t pthread_main_thread_np(void);
#endif

void wait_for_lock(MovableLock lock, pthread_t thread);
void sync_main_callback(MovableLock lock);
static void wait_for_lock(MovableLock lock, pthread_t thread);
static void sync_main_callback(MovableLock lock);

MovableLock _MovableLockCreate() {
#if OPENSWIFTUI_TARGET_OS_DARWIN
Expand All @@ -29,79 +29,82 @@ MovableLock _MovableLockCreate() {
abort();
}
pthread_mutex_init(&lock->mutex, NULL);
pthread_cond_init(&lock->cond1, NULL);
pthread_cond_init(&lock->cond2, NULL);
pthread_cond_init(&lock->cond3, NULL);
pthread_cond_init(&lock->lock_condition, NULL);
pthread_cond_init(&lock->main_callback_condition, NULL);
pthread_cond_init(&lock->broadcast_condition, NULL);
#if OPENSWIFTUI_TARGET_OS_DARWIN
lock->main = pthread_main_thread_np();
lock->main_thread = pthread_main_thread_np();
#endif
return lock;
}

void _MovableLockDestroy(MovableLock lock) {
pthread_cond_destroy(&lock->cond1);
pthread_cond_destroy(&lock->cond2);
pthread_cond_destroy(&lock->cond3);
pthread_cond_destroy(&lock->lock_condition);
pthread_cond_destroy(&lock->main_callback_condition);
pthread_cond_destroy(&lock->broadcast_condition);
pthread_mutex_destroy(&lock->mutex);
free(lock);
}

bool _MovableLockIsOwner(MovableLock lock) {
return pthread_self() == lock->owner;
pthread_t owner = lock->owner_thread;
return pthread_self() == owner;
}

bool _MovableLockIsOuterMostOwner(MovableLock lock) {
return pthread_self() == lock->owner && lock->level == 1;
bool _MovableLockIsOutermostOwner(MovableLock lock) {
pthread_t owner = lock->owner_thread;
return pthread_self() == owner && lock->lock_level == 1;
}

void _MovableLockLock(MovableLock lock) {
#if OPENSWIFTUI_TARGET_OS_DARWIN
pthread_t owner = pthread_self();
if (owner == lock->owner) {
lock->level += 1;
if (owner == lock->owner_thread) {
lock->lock_level += 1;
return;
}
pthread_mutex_lock(&lock->mutex);
while (lock->owner) {
while (lock->owner_thread) {
[[clang::noinline]]
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sources/OpenSwiftUI_SPI/Util/MovableLock.c:68: [[clang::noinline]] is used as a standalone statement attribute here; depending on the C standard/toolchain this can be rejected or downgraded to a warning (which may become an error under -Werror). If the intent is to prevent inlining, it’s safer to ensure noinline is applied in a compiler-supported way for C (also applies to the other occurrences in this PR).

Severity: medium

Other Locations
  • Sources/OpenSwiftUI_SPI/Util/MovableLock.c:124
  • Sources/OpenSwiftUI_SPI/Util/MovableLock.c:169
  • Sources/OpenSwiftUI_SPI/Util/MovableLock.c:172

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

wait_for_lock(lock, owner);
}
lock->owner = owner;
lock->level = 1;
lock->owner_thread = owner;
lock->lock_level = 1;
#endif
}

void _MovableLockUnlock(MovableLock lock) {
#if OPENSWIFTUI_TARGET_OS_DARWIN
lock->level -= 1;
if (lock->level != 0) {
lock->lock_level -= 1;
if (lock->lock_level != 0) {
return;
}
if (lock->unknown != 0) {
pthread_cond_signal(&lock->cond1);
if (lock->waiter_count != 0) {
pthread_cond_signal(&lock->lock_condition);
}
lock->owner = NULL;
lock->owner_thread = NULL;
pthread_mutex_unlock(&lock->mutex);
#endif
}

void _MovableLockSyncMain(MovableLock lock, const void *context, void (*function)(const void *context)) {
void _MovableLockSyncMain(MovableLock lock, const void *main_callback_context, void (*main_callback)(const void *main_callback_context)) {
#if OPENSWIFTUI_TARGET_OS_DARWIN
if (pthread_self() == lock->main) {
function(context);
if (pthread_self() == lock->main_thread) {
main_callback(main_callback_context);
} else {
lock->function = function;
lock->context = context;
if (lock->unknown5) {
pthread_cond_signal_thread_np(&lock->cond1, lock->main);
} else if (!lock->unknown4) {
lock->unknown4 = true;
lock->main_callback = main_callback;
lock->main_callback_context = main_callback_context;
if (lock->main_thread_waiting) {
pthread_cond_signal_thread_np(&lock->lock_condition, lock->main_thread);
} else if (!lock->main_callback_pending) {
lock->main_callback_pending = true;
dispatch_async_f(dispatch_get_main_queue(), lock, (dispatch_function_t)&sync_main_callback);
if (lock->unknown5) {
pthread_cond_signal_thread_np(&lock->cond1, lock->main);
if (lock->main_thread_waiting) {
pthread_cond_signal_thread_np(&lock->lock_condition, lock->main_thread);
}
}
while (lock->function) {
pthread_cond_wait(&lock->cond2, &lock->mutex);
while (lock->main_callback) {
pthread_cond_wait(&lock->main_callback_condition, &lock->mutex);
}
}
#endif
Expand All @@ -110,57 +113,63 @@ void _MovableLockSyncMain(MovableLock lock, const void *context, void (*function
void _MovableLockWait(MovableLock lock) {
#if OPENSWIFTUI_TARGET_OS_DARWIN
pthread_t owner = pthread_self();
uint32_t level = lock->level;
lock->level = 0;
lock->owner = NULL;
if (lock->unknown != 0) {
pthread_cond_broadcast(&lock->cond1);
uint32_t level = lock->lock_level;
lock->lock_level = 0;
lock->owner_thread = NULL;
if (lock->waiter_count != 0) {
pthread_cond_broadcast(&lock->lock_condition);
}
pthread_cond_wait(&lock->cond3, &lock->mutex);
while (lock->owner) {
pthread_cond_wait(&lock->broadcast_condition, &lock->mutex);
while (lock->owner_thread) {
[[clang::noinline]]
wait_for_lock(lock, owner);
}
lock->owner = owner;
lock->level = level;
lock->owner_thread = owner;
lock->lock_level = level;
#endif
}

void _MovableLockBroadcast(MovableLock lock) {
#if OPENSWIFTUI_TARGET_OS_DARWIN
pthread_cond_broadcast(&lock->cond3);
pthread_cond_broadcast(&lock->broadcast_condition);
#endif
}

void wait_for_lock(MovableLock lock, pthread_t owner) {
static void wait_for_lock(MovableLock lock, pthread_t owner) {
#if OPENSWIFTUI_TARGET_OS_DARWIN
lock->unknown += 1;
if (lock->main == owner) {
lock->unknown5 = 1;
if (lock->function) {
uint32_t original_level = lock->level;
pthread_t original_owner = lock->owner;
lock->owner = lock->main;
lock->level = original_level + 1;
lock->function(lock->context);
lock->level = original_level;
lock->owner = original_owner;
lock->function = NULL;
lock->context = NULL;
pthread_cond_signal(&lock->cond2);
lock->waiter_count += 1;
if (lock->main_thread == owner) {
lock->main_thread_waiting = true;
if (lock->main_callback) {
pthread_t original_owner = __atomic_load_n(&lock->owner_thread, __ATOMIC_SEQ_CST);
uint32_t original_level = lock->lock_level;
pthread_t main_thread = lock->main_thread;
lock->owner_thread = main_thread;
lock->lock_level = original_level + 1;
void (*main_callback)(const void *) = lock->main_callback;
const void *main_callback_context = lock->main_callback_context;
main_callback(main_callback_context);
lock->lock_level = original_level;
lock->owner_thread = original_owner;
lock->main_callback = NULL;
lock->main_callback_context = NULL;
pthread_cond_signal(&lock->main_callback_condition);
}
}
pthread_cond_wait(&lock->cond1, &lock->mutex);
if (lock->main == owner) {
lock->unknown5 = 0;
pthread_cond_wait(&lock->lock_condition, &lock->mutex);
if (lock->main_thread == owner) {
lock->main_thread_waiting = false;
}
lock->unknown -= 1;
lock->waiter_count -= 1;
#endif
}

void sync_main_callback(MovableLock lock) {
static void sync_main_callback(MovableLock lock) {
#if OPENSWIFTUI_TARGET_OS_DARWIN
[[clang::noinline]]
_MovableLockLock(lock);
lock->unknown4 = 0;
lock->main_callback_pending = false;
[[clang::noinline]]
_MovableLockUnlock(lock);
#endif
}
41 changes: 22 additions & 19 deletions Sources/OpenSwiftUI_SPI/Util/MovableLock.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// MovableLock.h
// OpenSwiftUI
//
// Audited for 3.5.2
// Audited for 6.5.4
// Status: Complete

#ifndef MovableLock_h
Expand All @@ -15,34 +15,37 @@ OPENSWIFTUI_ASSUME_NONNULL_BEGIN

typedef struct MovableLock_s {
pthread_mutex_t mutex;
pthread_cond_t cond1;
pthread_cond_t cond2;
pthread_cond_t cond3;
pthread_t main;
pthread_t owner;
uint32_t level;
uint32_t unknown;
void (* _Nullable function)(const void *context);
const void * _Nullable context;
bool unknown4;
bool unknown5;
pthread_cond_t lock_condition;
pthread_cond_t main_callback_condition;
pthread_cond_t broadcast_condition;
pthread_t main_thread;
pthread_t owner_thread;
uint32_t lock_level;
uint32_t waiter_count;
void (* _Nullable main_callback)(const void *main_callback_context);
const void * _Nullable main_callback_context;
bool main_callback_pending;
bool main_thread_waiting;
} MovableLock_t;

typedef MovableLock_t *MovableLock __attribute((swift_newtype(struct)));

OPENSWIFTUI_EXPORT
OPENSWIFTUI_REFINED_FOR_SWIFT
MovableLock _MovableLockCreate(void) OPENSWIFTUI_SWIFT_NAME(MovableLock.create());
MovableLock _MovableLockCreate(void) OPENSWIFTUI_SWIFT_NAME(MovableLock.init());
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sources/OpenSwiftUI_SPI/Util/MovableLock.h:33: Removing OPENSWIFTUI_EXPORT from these declarations may change DLL import/export behavior on Windows (OPENSWIFTUI_EXPORT maps to __declspec(dllexport/dllimport) there). If OpenSwiftUI_SPI is ever built as a Windows DLL, it’s worth double-checking that these C symbols remain exported as intended.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.


OPENSWIFTUI_EXPORT
OPENSWIFTUI_REFINED_FOR_SWIFT
void _MovableLockDestroy(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.destroy(self:));

bool _MovableLockIsOwner(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(getter:MovableLock.isOwner(self:));
bool _MovableLockIsOuterMostOwner(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(getter:MovableLock.isOuterMostOwner(self:));

bool _MovableLockIsOutermostOwner(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(getter:MovableLock.isOutermostOwner(self:));

void _MovableLockLock(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.lock(self:));

void _MovableLockUnlock(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.unlock(self:));
void _MovableLockSyncMain(MovableLock lock, const void *context, void (*function)(const void *context)) OPENSWIFTUI_SWIFT_NAME(MovableLock.syncMain(self:_:function:));

void _MovableLockSyncMain(MovableLock lock, const void *main_callback_context, void (*main_callback)(const void *main_callback_context)) OPENSWIFTUI_SWIFT_NAME(MovableLock.syncMain(self:_:function:));

void _MovableLockWait(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.wait(self:));

void _MovableLockBroadcast(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.broadcast(self:));

OPENSWIFTUI_ASSUME_NONNULL_END
Expand Down
8 changes: 4 additions & 4 deletions Tests/OpenSwiftUI_SPITests/Util/MovableLockTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ final class MovableLockTests {
let lock: MovableLock

init() {
lock = MovableLock.create()
lock = MovableLock()
}

deinit {
Expand All @@ -20,13 +20,13 @@ final class MovableLockTests {
@Test
func owner() {
#expect(lock.isOwner == false)
#expect(lock.isOuterMostOwner == false)
#expect(lock.isOutermostOwner == false)
lock.lock()
#expect(lock.isOwner == true)
#expect(lock.isOuterMostOwner == true)
#expect(lock.isOutermostOwner == true)
lock.unlock()
#expect(lock.isOwner == false)
#expect(lock.isOuterMostOwner == false)
#expect(lock.isOutermostOwner == false)
}
}
#endif
Loading