Skip to content

Commit 751d20d

Browse files
committed
Fix nsync_mu_unlock_slow_() on Apple Silicon
We torture test dlmalloc() in test/libc/stdio/memory_test.c. That test was crashing on occasion on Apple M1 microprocessors when dlmalloc was using *NSYNC locks. It was relatively easy to spot the cause, which is this one particular compare and swap operation, which needed to change to use sequentially-consistent ordering rather than an acquire barrier
1 parent 3b15d31 commit 751d20d

File tree

5 files changed

+36
-2
lines changed

5 files changed

+36
-2
lines changed

third_party/dlmalloc/dlmalloc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "libc/thread/thread.h"
2424
#include "libc/thread/tls.h"
2525
#include "third_party/dlmalloc/vespene.internal.h"
26+
#include "third_party/nsync/mu.h"
2627
// clang-format off
2728

2829
#define FOOTERS 0

third_party/dlmalloc/locks.inc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
3131
*/
3232

33+
#ifdef USE_SPIN_LOCKS
34+
3335
#define MLOCK_T atomic_uint
3436

3537
static int malloc_wipe(MLOCK_T *lk) {
@@ -51,6 +53,27 @@ static int malloc_unlock(MLOCK_T *lk) {
5153
return 0;
5254
}
5355

56+
#else
57+
58+
#define MLOCK_T nsync_mu
59+
60+
static int malloc_wipe(MLOCK_T *lk) {
61+
bzero(lk, sizeof(*lk));
62+
return 0;
63+
}
64+
65+
static int malloc_lock(MLOCK_T *lk) {
66+
nsync_mu_lock(lk);
67+
return 0;
68+
}
69+
70+
static int malloc_unlock(MLOCK_T *lk) {
71+
nsync_mu_unlock(lk);
72+
return 0;
73+
}
74+
75+
#endif
76+
5477
#define ACQUIRE_LOCK(lk) malloc_lock(lk)
5578
#define RELEASE_LOCK(lk) malloc_unlock(lk)
5679
#define INITIAL_LOCK(lk) malloc_wipe(lk)

third_party/nsync/README.cosmo

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ ORIGIN
1515

1616
LOCAL CHANGES
1717

18+
- Fix nsync_mu_unlock() on Apple Silicon
19+
1820
- Time APIs were so good that they're now in libc
1921

2022
- Double linked list API was so good that it's now in libc

third_party/nsync/atomic.internal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,21 @@ static inline int atm_cas_relacq_u32_(nsync_atomic_uint32_ *p, uint32_t o,
8686
memory_order_relaxed);
8787
}
8888

89+
static inline int atm_cas_seqcst_u32_(nsync_atomic_uint32_ *p, uint32_t o,
90+
uint32_t n) {
91+
return atomic_compare_exchange_strong_explicit(NSYNC_ATOMIC_UINT32_PTR_(p),
92+
&o, n, memory_order_seq_cst,
93+
memory_order_relaxed);
94+
}
95+
8996
#define ATM_CAS_HELPER_(barrier, p, o, n) \
9097
(atm_cas_##barrier##_u32_((p), (o), (n)))
9198

9299
#define ATM_CAS(p, o, n) ATM_CAS_HELPER_(nomb, (p), (o), (n))
93100
#define ATM_CAS_ACQ(p, o, n) ATM_CAS_HELPER_(acq, (p), (o), (n))
94101
#define ATM_CAS_REL(p, o, n) ATM_CAS_HELPER_(rel, (p), (o), (n))
95102
#define ATM_CAS_RELACQ(p, o, n) ATM_CAS_HELPER_(relacq, (p), (o), (n))
103+
#define ATM_CAS_SEQCST(p, o, n) ATM_CAS_HELPER_(seqcst, (p), (o), (n))
96104

97105
/* Need a cast to remove "const" from some uses. */
98106
#define ATM_LOAD(p) \

third_party/nsync/mu.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ void nsync_mu_unlock_slow_ (nsync_mu *mu, lock_type *l_type) {
298298
return;
299299
}
300300
} else if ((old_word&MU_SPINLOCK) == 0 &&
301-
ATM_CAS_ACQ (&mu->word, old_word,
302-
(old_word-early_release_mu)|MU_SPINLOCK|MU_DESIG_WAKER)) {
301+
ATM_CAS_SEQCST (&mu->word, old_word, /* [jart] fixes issues on apple silicon */
302+
(old_word-early_release_mu)|MU_SPINLOCK|MU_DESIG_WAKER)) {
303303
struct Dll *wake;
304304
lock_type *wake_type;
305305
uint32_t clear_on_release;

0 commit comments

Comments
 (0)