Skip to content

Commit bcc352d

Browse files
committed
Make jl_spin_mutex_t 8 bytes in 32-bit mode
1 parent 5e76cc8 commit bcc352d

File tree

2 files changed

+35
-25
lines changed

2 files changed

+35
-25
lines changed

src/julia_threads.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ struct _jl_task_t;
116116
// Recursive spin lock with GC integration
117117
typedef struct {
118118
_Atomic(struct _jl_task_t*) owner;
119-
_Atomic(uint32_t) padding;
120-
uint32_t count;
119+
// Count is only ever accessed on the same thread,
120+
// the _Atomic is for parity with sleep_mutex
121+
_Atomic(uint32_t) count;
121122
} jl_spin_mutex_t;
122123

123124
// Recursive sleep lock with GC integration

src/threading.c

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ static void jl_check_tls(void)
589589
JL_DLLEXPORT const int jl_tls_elf_support = 0;
590590
#endif
591591

592+
#define SLEEP_LOCK_BIT ((uint32_t)(1ull << 31))
592593
#define SLEEP_HASH_BITS 6
593594
#define SLEEP_IGNORED_BITS 8
594595
static uv_mutex_t sleep_locks[1 << SLEEP_HASH_BITS];
@@ -737,28 +738,32 @@ JL_DLLEXPORT void jl_exit_threaded_region(void)
737738
}
738739
}
739740

741+
static int is_spin_mutex(void *lock)
742+
{
743+
return (jl_atomic_load_relaxed(&((jl_spin_mutex_t *)lock)->count) & SLEEP_LOCK_BIT) == 0;
744+
}
745+
740746
JL_DLLEXPORT void _jl_spin_mutex_init(jl_spin_mutex_t *lock, const char *name) JL_NOTSAFEPOINT
741747
{
742-
lock->count = 0;
743-
// high bit of padding identifies this as a spin lock
744-
jl_atomic_store_relaxed(&lock->padding, 0);
748+
// high bit of count unset identifies this as a spin lock
749+
jl_atomic_store_relaxed(&lock->count, 0);
745750
jl_atomic_store_release(&lock->owner, (jl_task_t*)NULL);
746751
jl_profile_lock_init(lock, name);
747752
}
748753

749754
JL_DLLEXPORT void _jl_spin_mutex_wait(jl_task_t *self, jl_spin_mutex_t *lock, int safepoint)
750755
{
751-
assert(jl_atomic_load_relaxed(&lock->padding) == 0 && "Spin lock not initialized!");
756+
assert(is_spin_mutex(lock) && "Spin lock corrupted!");
752757
jl_task_t *owner = jl_atomic_load_relaxed(&lock->owner);
753758
if (owner == self) {
754-
lock->count++;
759+
jl_atomic_store_relaxed(&lock->count, jl_atomic_load_relaxed(&lock->count) + 1);
755760
return;
756761
}
757762
JL_TIMING(LOCK_SPIN, LOCK_SPIN);
758763
jl_profile_lock_start_wait(lock);
759764
while (1) {
760765
if (owner == NULL && jl_atomic_cmpswap(&lock->owner, &owner, self)) {
761-
lock->count = 1;
766+
jl_atomic_store_relaxed(&lock->count, 1);
762767
jl_profile_lock_acquired(lock);
763768
return;
764769
}
@@ -807,14 +812,14 @@ JL_DLLEXPORT void _jl_spin_mutex_lock(jl_task_t *self, jl_spin_mutex_t *lock)
807812

808813
JL_DLLEXPORT int _jl_spin_mutex_trylock_nogc(jl_task_t *self, jl_spin_mutex_t *lock)
809814
{
810-
assert(jl_atomic_load_relaxed(&lock->padding) == 0 && "Spin lock not initialized!");
815+
assert(is_spin_mutex(lock) && "Spin lock corrupted!");
811816
jl_task_t *owner = jl_atomic_load_acquire(&lock->owner);
812817
if (owner == self) {
813-
lock->count++;
818+
jl_atomic_store_relaxed(&lock->count, jl_atomic_load_relaxed(&lock->count) + 1);
814819
return 1;
815820
}
816821
if (owner == NULL && jl_atomic_cmpswap(&lock->owner, &owner, self)) {
817-
lock->count = 1;
822+
jl_atomic_store_relaxed(&lock->count, 1);
818823
return 1;
819824
}
820825
return 0;
@@ -832,11 +837,13 @@ JL_DLLEXPORT int _jl_spin_mutex_trylock(jl_task_t *self, jl_spin_mutex_t *lock)
832837

833838
JL_DLLEXPORT void _jl_spin_mutex_unlock_nogc(jl_spin_mutex_t *lock)
834839
{
835-
assert(jl_atomic_load_relaxed(&lock->padding) == 0 && "Spin lock not initialized!");
840+
assert(is_spin_mutex(lock) && "Spin lock corrupted!");
836841
#ifndef __clang_gcanalyzer__
837842
assert(jl_atomic_load_relaxed(&lock->owner) == jl_current_task &&
838843
"Unlocking a lock in a different thread.");
839-
if (--lock->count == 0) {
844+
uint32_t count = jl_atomic_load_relaxed(&lock->count);
845+
jl_atomic_store_relaxed(&lock->count, count - 1);
846+
if (count == 1) {
840847
jl_profile_lock_release_start(lock);
841848
jl_atomic_store_release(&lock->owner, (jl_task_t*)NULL);
842849
jl_cpu_wake();
@@ -861,8 +868,6 @@ JL_DLLEXPORT void _jl_spin_mutex_unlock(jl_task_t *self, jl_spin_mutex_t *lock)
861868
}
862869
}
863870

864-
#define SLEEP_LOCK_BIT ((uint32_t)(1ull << 31))
865-
866871
JL_DLLEXPORT void _jl_sleep_mutex_init(jl_sleep_mutex_t *lock, const char *name) JL_NOTSAFEPOINT
867872
{
868873
// waiters is overloaded:
@@ -877,8 +882,10 @@ JL_DLLEXPORT void _jl_sleep_mutex_init(jl_sleep_mutex_t *lock, const char *name)
877882

878883
JL_DLLEXPORT void _jl_sleep_mutex_wait(jl_task_t *self, jl_sleep_mutex_t *lock, int safepoint)
879884
{
880-
// high bit of padding identifies this as a spin lock
881-
assert((jl_atomic_load_relaxed(&lock->waiters) & SLEEP_LOCK_BIT) && "Unexpected spin lock in sleeping wait!");
885+
// high bit of waiters identifies this as a sleep lock
886+
// call out the uninitialized case specially
887+
assert(jl_atomic_load_relaxed(&lock->waiters) != 0 && "Sleep lock not initialized!");
888+
assert(!is_spin_mutex(lock) && "Unexpected spin lock in sleeping wait!");
882889
uint32_t old_waiters = SLEEP_LOCK_BIT;
883890
if (jl_atomic_cmpswap_acqrel(&lock->waiters, &old_waiters, SLEEP_LOCK_BIT | 1)) {
884891
// no one is waiting, we just took the lock
@@ -930,8 +937,10 @@ JL_DLLEXPORT void _jl_sleep_mutex_lock(jl_task_t *self, jl_sleep_mutex_t *lock)
930937

931938
JL_DLLEXPORT int _jl_sleep_mutex_trylock_nogc(jl_task_t *self, jl_sleep_mutex_t *lock)
932939
{
933-
// high bit of padding identifies this as a spin lock
934-
assert((jl_atomic_load_relaxed(&lock->waiters) & SLEEP_LOCK_BIT) && "Unexpected spin lock in sleeping trylock!");
940+
// high bit of waiters identifies this as a sleep lock
941+
// call out the uninitialized case specially
942+
assert(jl_atomic_load_relaxed(&lock->waiters) != 0 && "Sleep lock not initialized!");
943+
assert(!is_spin_mutex(lock) && "Unexpected spin lock in trylock!");
935944
uint32_t none = SLEEP_LOCK_BIT;
936945
if (jl_atomic_cmpswap_acqrel(&lock->waiters, &none, SLEEP_LOCK_BIT | 1)) {
937946
// no one is waiting, we just took the lock
@@ -959,8 +968,10 @@ JL_DLLEXPORT int _jl_sleep_mutex_trylock(jl_task_t *self, jl_sleep_mutex_t *lock
959968

960969
JL_DLLEXPORT void _jl_sleep_mutex_unlock_nogc(jl_sleep_mutex_t *lock)
961970
{
962-
// high bit of padding identifies this as a spin lock
963-
assert((jl_atomic_load_relaxed(&lock->waiters) & SLEEP_LOCK_BIT) && "Unexpected spin lock in sleeping unlock!");
971+
// high bit of waiters identifies this as a sleep lock
972+
// call out the uninitialized case specially
973+
assert(jl_atomic_load_relaxed(&lock->waiters) != 0 && "Sleep lock not initialized!");
974+
assert(!is_spin_mutex(lock) && "Unexpected spin lock in unlock!");
964975
if (--lock->count == 0) {
965976
//Do the release
966977
jl_profile_lock_release_start(lock);
@@ -1006,8 +1017,7 @@ JL_DLLEXPORT void _jl_sleep_mutex_unlock(jl_task_t *self, jl_sleep_mutex_t *lock
10061017

10071018
void _jl_dyn_mutex_unlock(jl_task_t *self, void *lock)
10081019
{
1009-
int is_sleep_mutex = jl_atomic_load_relaxed(&((jl_spin_mutex_t*)lock)->padding) & SLEEP_LOCK_BIT;
1010-
if (is_sleep_mutex) {
1020+
if (!is_spin_mutex(lock)) {
10111021
_jl_sleep_mutex_unlock(self, (jl_sleep_mutex_t*)lock);
10121022
} else {
10131023
_jl_spin_mutex_unlock(self, (jl_spin_mutex_t*)lock);
@@ -1016,8 +1026,7 @@ void _jl_dyn_mutex_unlock(jl_task_t *self, void *lock)
10161026

10171027
void _jl_dyn_mutex_unlock_nogc(void *lock)
10181028
{
1019-
int is_sleep_mutex = jl_atomic_load_relaxed(&((jl_spin_mutex_t*)lock)->padding) & SLEEP_LOCK_BIT;
1020-
if (is_sleep_mutex) {
1029+
if (!is_spin_mutex(lock)) {
10211030
_jl_sleep_mutex_unlock_nogc((jl_sleep_mutex_t*)lock);
10221031
} else {
10231032
_jl_spin_mutex_unlock_nogc((jl_spin_mutex_t*)lock);

0 commit comments

Comments
 (0)