Skip to content

Commit 0342617

Browse files
committed
add workaround for kernel panics on MacOS
1 parent 0a9c150 commit 0342617

File tree

1 file changed

+22
-8
lines changed

1 file changed

+22
-8
lines changed

src/threading.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -796,13 +796,27 @@ gb_internal void futex_wait(Futex *f, Footex val) {
796796

797797
#elif defined(GB_SYSTEM_OSX)
798798

799+
// IMPORTANT NOTE(laytan): We use `OS_SYNC_*_SHARED` and `UL_COMPARE_AND_WAIT_SHARED` flags here.
800+
// these flags tell the kernel that we are using these futexes across different processes which
801+
// causes it to opt-out of some optimisations.
802+
//
803+
// BUT this is not actually the case! We should be using the normal non-shared version and letting
804+
// the kernel optimize (I've measured it to be about 10% faster at the parsing/type checking stages).
805+
//
806+
// However we have reports of people on MacOS running into kernel panics, and this seems to fix it for them.
807+
// Which means there is probably a bug in the kernel in one of these non-shared optimisations causing the panic.
808+
//
809+
// The panic also doesn't seem to happen on normal M1 CPUs, and happen more on later CPUs or pro/max series.
810+
// Probably because they have more going on in terms of threads etc.
811+
799812
#if __has_include(<os/os_sync_wait_on_address.h>)
800813
#define DARWIN_WAIT_ON_ADDRESS_AVAILABLE
801814
#include <os/os_sync_wait_on_address.h>
802815
#endif
803816

804-
#define UL_COMPARE_AND_WAIT 0x00000001
805-
#define ULF_NO_ERRNO 0x01000000
817+
#define UL_COMPARE_AND_WAIT 0x00000001
818+
#define UL_COMPARE_AND_WAIT_SHARED 0x00000003
819+
#define ULF_NO_ERRNO 0x01000000
806820

807821
extern "C" int __ulock_wait(uint32_t operation, void *addr, uint64_t value, uint32_t timeout); /* timeout is specified in microseconds */
808822
extern "C" int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value);
@@ -811,7 +825,7 @@ gb_internal void futex_signal(Futex *f) {
811825
#ifdef DARWIN_WAIT_ON_ADDRESS_AVAILABLE
812826
if (__builtin_available(macOS 14.4, *)) {
813827
for (;;) {
814-
int ret = os_sync_wake_by_address_any(f, sizeof(Futex), OS_SYNC_WAKE_BY_ADDRESS_NONE);
828+
int ret = os_sync_wake_by_address_any(f, sizeof(Futex), OS_SYNC_WAKE_BY_ADDRESS_SHARED);
815829
if (ret >= 0) {
816830
return;
817831
}
@@ -826,7 +840,7 @@ gb_internal void futex_signal(Futex *f) {
826840
} else {
827841
#endif
828842
for (;;) {
829-
int ret = __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0);
843+
int ret = __ulock_wake(UL_COMPARE_AND_WAIT_SHARED | ULF_NO_ERRNO, f, 0);
830844
if (ret >= 0) {
831845
return;
832846
}
@@ -847,7 +861,7 @@ gb_internal void futex_broadcast(Futex *f) {
847861
#ifdef DARWIN_WAIT_ON_ADDRESS_AVAILABLE
848862
if (__builtin_available(macOS 14.4, *)) {
849863
for (;;) {
850-
int ret = os_sync_wake_by_address_all(f, sizeof(Footex), OS_SYNC_WAKE_BY_ADDRESS_NONE);
864+
int ret = os_sync_wake_by_address_all(f, sizeof(Footex), OS_SYNC_WAKE_BY_ADDRESS_SHARED);
851865
if (ret >= 0) {
852866
return;
853867
}
@@ -863,7 +877,7 @@ gb_internal void futex_broadcast(Futex *f) {
863877
#endif
864878
for (;;) {
865879
enum { ULF_WAKE_ALL = 0x00000100 };
866-
int ret = __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0);
880+
int ret = __ulock_wake(UL_COMPARE_AND_WAIT_SHARED | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0);
867881
if (ret == 0) {
868882
return;
869883
}
@@ -884,7 +898,7 @@ gb_internal void futex_wait(Futex *f, Footex val) {
884898
#ifdef DARWIN_WAIT_ON_ADDRESS_AVAILABLE
885899
if (__builtin_available(macOS 14.4, *)) {
886900
for (;;) {
887-
int ret = os_sync_wait_on_address(f, cast(uint64_t)(val), sizeof(Footex), OS_SYNC_WAIT_ON_ADDRESS_NONE);
901+
int ret = os_sync_wait_on_address(f, cast(uint64_t)(val), sizeof(Footex), OS_SYNC_WAIT_ON_ADDRESS_SHARED);
888902
if (ret >= 0) {
889903
if (*f != val) {
890904
return;
@@ -902,7 +916,7 @@ gb_internal void futex_wait(Futex *f, Footex val) {
902916
} else {
903917
#endif
904918
for (;;) {
905-
int ret = __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, val, 0);
919+
int ret = __ulock_wait(UL_COMPARE_AND_WAIT_SHARED | ULF_NO_ERRNO, f, val, 0);
906920
if (ret >= 0) {
907921
if (*f != val) {
908922
return;

0 commit comments

Comments
 (0)