@@ -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
807821extern " C" int __ulock_wait (uint32_t operation, void *addr, uint64_t value, uint32_t timeout); /* timeout is specified in microseconds */
808822extern " 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