Skip to content

Commit

Permalink
add workaround for kernel panics on MacOS
Browse files Browse the repository at this point in the history
  • Loading branch information
laytan committed Jul 15, 2024
1 parent 0a9c150 commit 0342617
Showing 1 changed file with 22 additions and 8 deletions.
30 changes: 22 additions & 8 deletions src/threading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,13 +796,27 @@ gb_internal void futex_wait(Futex *f, Footex val) {

#elif defined(GB_SYSTEM_OSX)

// IMPORTANT NOTE(laytan): We use `OS_SYNC_*_SHARED` and `UL_COMPARE_AND_WAIT_SHARED` flags here.
// these flags tell the kernel that we are using these futexes across different processes which
// causes it to opt-out of some optimisations.
//
// BUT this is not actually the case! We should be using the normal non-shared version and letting
// the kernel optimize (I've measured it to be about 10% faster at the parsing/type checking stages).
//
// However we have reports of people on MacOS running into kernel panics, and this seems to fix it for them.
// Which means there is probably a bug in the kernel in one of these non-shared optimisations causing the panic.
//
// The panic also doesn't seem to happen on normal M1 CPUs, and happen more on later CPUs or pro/max series.
// Probably because they have more going on in terms of threads etc.

#if __has_include(<os/os_sync_wait_on_address.h>)
#define DARWIN_WAIT_ON_ADDRESS_AVAILABLE
#include <os/os_sync_wait_on_address.h>
#endif

#define UL_COMPARE_AND_WAIT 0x00000001
#define ULF_NO_ERRNO 0x01000000
#define UL_COMPARE_AND_WAIT 0x00000001
#define UL_COMPARE_AND_WAIT_SHARED 0x00000003
#define ULF_NO_ERRNO 0x01000000

extern "C" int __ulock_wait(uint32_t operation, void *addr, uint64_t value, uint32_t timeout); /* timeout is specified in microseconds */
extern "C" int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value);
Expand All @@ -811,7 +825,7 @@ gb_internal void futex_signal(Futex *f) {
#ifdef DARWIN_WAIT_ON_ADDRESS_AVAILABLE
if (__builtin_available(macOS 14.4, *)) {
for (;;) {
int ret = os_sync_wake_by_address_any(f, sizeof(Futex), OS_SYNC_WAKE_BY_ADDRESS_NONE);
int ret = os_sync_wake_by_address_any(f, sizeof(Futex), OS_SYNC_WAKE_BY_ADDRESS_SHARED);
if (ret >= 0) {
return;
}
Expand All @@ -826,7 +840,7 @@ gb_internal void futex_signal(Futex *f) {
} else {
#endif
for (;;) {
int ret = __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0);
int ret = __ulock_wake(UL_COMPARE_AND_WAIT_SHARED | ULF_NO_ERRNO, f, 0);
if (ret >= 0) {
return;
}
Expand All @@ -847,7 +861,7 @@ gb_internal void futex_broadcast(Futex *f) {
#ifdef DARWIN_WAIT_ON_ADDRESS_AVAILABLE
if (__builtin_available(macOS 14.4, *)) {
for (;;) {
int ret = os_sync_wake_by_address_all(f, sizeof(Footex), OS_SYNC_WAKE_BY_ADDRESS_NONE);
int ret = os_sync_wake_by_address_all(f, sizeof(Footex), OS_SYNC_WAKE_BY_ADDRESS_SHARED);
if (ret >= 0) {
return;
}
Expand All @@ -863,7 +877,7 @@ gb_internal void futex_broadcast(Futex *f) {
#endif
for (;;) {
enum { ULF_WAKE_ALL = 0x00000100 };
int ret = __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0);
int ret = __ulock_wake(UL_COMPARE_AND_WAIT_SHARED | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0);
if (ret == 0) {
return;
}
Expand All @@ -884,7 +898,7 @@ gb_internal void futex_wait(Futex *f, Footex val) {
#ifdef DARWIN_WAIT_ON_ADDRESS_AVAILABLE
if (__builtin_available(macOS 14.4, *)) {
for (;;) {
int ret = os_sync_wait_on_address(f, cast(uint64_t)(val), sizeof(Footex), OS_SYNC_WAIT_ON_ADDRESS_NONE);
int ret = os_sync_wait_on_address(f, cast(uint64_t)(val), sizeof(Footex), OS_SYNC_WAIT_ON_ADDRESS_SHARED);
if (ret >= 0) {
if (*f != val) {
return;
Expand All @@ -902,7 +916,7 @@ gb_internal void futex_wait(Futex *f, Footex val) {
} else {
#endif
for (;;) {
int ret = __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, val, 0);
int ret = __ulock_wait(UL_COMPARE_AND_WAIT_SHARED | ULF_NO_ERRNO, f, val, 0);
if (ret >= 0) {
if (*f != val) {
return;
Expand Down

0 comments on commit 0342617

Please sign in to comment.