mutex spinning
This commit is contained in:
parent
994ed1e1e1
commit
a397458c72
32
src/snc.c
32
src/snc.c
@ -3,16 +3,21 @@
|
|||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
|
#define DEFAULT_MUTEX_SPIN 4000
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Mutex
|
* Mutex
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct snc_lock snc_lock_e(struct snc_mutex *m)
|
struct snc_lock snc_lock_spin_e(struct snc_mutex *m, i32 spin)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
b32 locked = false;
|
b32 locked = false;
|
||||||
while (!locked) {
|
while (!locked) {
|
||||||
|
/* Spin lock */
|
||||||
|
i32 spin_cnt = 0;
|
||||||
i32 v = atomic_i32_fetch_test_set(&m->v, 0, (1 << 31));
|
i32 v = atomic_i32_fetch_test_set(&m->v, 0, (1 << 31));
|
||||||
|
do {
|
||||||
if (v == 0) {
|
if (v == 0) {
|
||||||
locked = true;
|
locked = true;
|
||||||
} else {
|
} else {
|
||||||
@ -25,7 +30,11 @@ struct snc_lock snc_lock_e(struct snc_mutex *m)
|
|||||||
}
|
}
|
||||||
v = old;
|
v = old;
|
||||||
}
|
}
|
||||||
/* Wait for change */
|
}
|
||||||
|
++spin_cnt;
|
||||||
|
} while (spin_cnt < spin && !locked);
|
||||||
|
/* Wait if not successful */
|
||||||
|
if (!locked) {
|
||||||
sys_wait(&m->v, &v, 4);
|
sys_wait(&m->v, &v, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,19 +44,24 @@ struct snc_lock snc_lock_e(struct snc_mutex *m)
|
|||||||
return lock;
|
return lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct snc_lock snc_lock_s(struct snc_mutex *m)
|
struct snc_lock snc_lock_spin_s(struct snc_mutex *m, i32 spin)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
b32 locked = false;
|
b32 locked = false;
|
||||||
while (!locked) {
|
while (!locked) {
|
||||||
|
/* Spin lock */
|
||||||
|
i32 spin_cnt = 0;
|
||||||
i32 v = atomic_i32_fetch(&m->v);
|
i32 v = atomic_i32_fetch(&m->v);
|
||||||
|
do {
|
||||||
while (!locked && (v & 0xC0000000) == 0) {
|
while (!locked && (v & 0xC0000000) == 0) {
|
||||||
/* Increment shared lock count */
|
/* Lock has no exclusive or pending exclusive lock, increment shared count */
|
||||||
i32 old = atomic_i32_fetch_test_set(&m->v, v, v + 1);
|
i32 old = atomic_i32_fetch_test_set(&m->v, v, v + 1);
|
||||||
if (v == old) {
|
if (v == old) {
|
||||||
locked = true;
|
locked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} while (spin_cnt < spin && !locked);
|
||||||
|
/* Wait if not successful */
|
||||||
if (!locked) {
|
if (!locked) {
|
||||||
sys_wait(&m->v, &v, 4);
|
sys_wait(&m->v, &v, 4);
|
||||||
}
|
}
|
||||||
@ -57,6 +71,16 @@ struct snc_lock snc_lock_s(struct snc_mutex *m)
|
|||||||
return lock;
|
return lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct snc_lock snc_lock_e(struct snc_mutex *m)
|
||||||
|
{
|
||||||
|
return snc_lock_spin_e(m, DEFAULT_MUTEX_SPIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct snc_lock snc_lock_s(struct snc_mutex *m)
|
||||||
|
{
|
||||||
|
return snc_lock_spin_s(m, DEFAULT_MUTEX_SPIN);
|
||||||
|
}
|
||||||
|
|
||||||
void snc_unlock(struct snc_lock *l)
|
void snc_unlock(struct snc_lock *l)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
|
|||||||
@ -14,6 +14,8 @@ struct snc_mutex {
|
|||||||
struct atomic_i32 v;
|
struct atomic_i32 v;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct snc_lock snc_lock_spin_e(struct snc_mutex *m, i32 spin);
|
||||||
|
struct snc_lock snc_lock_spin_s(struct snc_mutex *m, i32 spin);
|
||||||
struct snc_lock snc_lock_e(struct snc_mutex *m);
|
struct snc_lock snc_lock_e(struct snc_mutex *m);
|
||||||
struct snc_lock snc_lock_s(struct snc_mutex *m);
|
struct snc_lock snc_lock_s(struct snc_mutex *m);
|
||||||
void snc_unlock(struct snc_lock *lock);
|
void snc_unlock(struct snc_lock *lock);
|
||||||
|
|||||||
@ -450,6 +450,7 @@ b32 sys_run_command(struct string cmd);
|
|||||||
/* Futex-like wait & wake */
|
/* Futex-like wait & wake */
|
||||||
|
|
||||||
void sys_wait(void *addr, void *cmp, u32 size);
|
void sys_wait(void *addr, void *cmp, u32 size);
|
||||||
|
void sys_wake_single(void *addr);
|
||||||
void sys_wake_all(void *addr);
|
void sys_wake_all(void *addr);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
@ -111,7 +111,6 @@ struct alignas(64) wait_list {
|
|||||||
/* =================================================== */
|
/* =================================================== */
|
||||||
struct yielder *last_yielder; /* 8 bytes */
|
struct yielder *last_yielder; /* 8 bytes */
|
||||||
/* =================================================== */
|
/* =================================================== */
|
||||||
struct yielder *first_free_yielder; /* 8 bytes */
|
|
||||||
/* =================================================== */
|
/* =================================================== */
|
||||||
i32 num_yielders; /* 4 bytes */
|
i32 num_yielders; /* 4 bytes */
|
||||||
u8 _pad0[4]; /* 4 bytes (padding */
|
u8 _pad0[4]; /* 4 bytes (padding */
|
||||||
@ -133,10 +132,12 @@ struct alignas(64) wait_bin {
|
|||||||
/* =================================================== */
|
/* =================================================== */
|
||||||
struct wait_list *first_free_wait_list; /* 8 bytes */
|
struct wait_list *first_free_wait_list; /* 8 bytes */
|
||||||
/* =================================================== */
|
/* =================================================== */
|
||||||
|
struct yielder *first_free_yielder;
|
||||||
|
/* =================================================== */
|
||||||
struct atomic_i32 lock; /* 4 bytes */
|
struct atomic_i32 lock; /* 4 bytes */
|
||||||
u8 _pad0[4]; /* 4 bytes (padding) */
|
u8 _pad0[4]; /* 4 bytes (padding) */
|
||||||
/* =================================================== */
|
/* =================================================== */
|
||||||
u8 _pad1[32]; /* 32 bytes (padding) */
|
u8 _pad1[24]; /* 24 bytes (padding) */
|
||||||
};
|
};
|
||||||
STATIC_ASSERT(sizeof(struct wait_bin) == 64); /* Assume wait_bin fits in one cache line (increase if necessary) */
|
STATIC_ASSERT(sizeof(struct wait_bin) == 64); /* Assume wait_bin fits in one cache line (increase if necessary) */
|
||||||
STATIC_ASSERT(alignof(struct wait_bin) == 64); /* Avoid false sharing */
|
STATIC_ASSERT(alignof(struct wait_bin) == 64); /* Avoid false sharing */
|
||||||
@ -413,9 +414,14 @@ void sys_wait(void *addr, void *cmp, u32 size)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sys_wake_single(void *addr)
|
||||||
|
{
|
||||||
|
ASSERT(false);
|
||||||
|
(UNUSED)addr;
|
||||||
|
}
|
||||||
|
|
||||||
void sys_wake_all(void *addr)
|
void sys_wake_all(void *addr)
|
||||||
{
|
{
|
||||||
#if 1
|
|
||||||
u64 wait_bin_index = (u64)addr % NUM_WAIT_BINS;
|
u64 wait_bin_index = (u64)addr % NUM_WAIT_BINS;
|
||||||
struct wait_bin *bin = &G.wait_bins[wait_bin_index];
|
struct wait_bin *bin = &G.wait_bins[wait_bin_index];
|
||||||
|
|
||||||
@ -480,8 +486,8 @@ void sys_wake_all(void *addr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Free yielders */
|
/* Free yielders */
|
||||||
wait_list->last_yielder->next = wait_list->first_free_yielder;
|
wait_list->last_yielder->next = bin->first_free_yielder;
|
||||||
wait_list->first_free_yielder = wait_list->first_yielder;
|
bin->first_free_yielder = wait_list->first_yielder;
|
||||||
wait_list->first_yielder = NULL;
|
wait_list->first_yielder = NULL;
|
||||||
wait_list->last_yielder = NULL;
|
wait_list->last_yielder = NULL;
|
||||||
wait_list->num_yielders = 0;
|
wait_list->num_yielders = 0;
|
||||||
@ -490,7 +496,6 @@ void sys_wake_all(void *addr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomic_i32_fetch_set(&bin->lock, 0);
|
atomic_i32_fetch_set(&bin->lock, 0);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Wake blocking waiters */
|
/* Wake blocking waiters */
|
||||||
WakeByAddressAll(addr);
|
WakeByAddressAll(addr);
|
||||||
@ -714,6 +719,7 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg)
|
|||||||
(UNUSED)ctx;
|
(UNUSED)ctx;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
/* TODO: Heuristic pinning */
|
||||||
HANDLE thread_handle = GetCurrentThread();
|
HANDLE thread_handle = GetCurrentThread();
|
||||||
b32 success = false;
|
b32 success = false;
|
||||||
(UNUSED)success;
|
(UNUSED)success;
|
||||||
@ -879,9 +885,9 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg)
|
|||||||
|
|
||||||
/* Allocate new yielder */
|
/* Allocate new yielder */
|
||||||
struct yielder *yielder = NULL;
|
struct yielder *yielder = NULL;
|
||||||
if (wait_list->first_free_yielder) {
|
if (bin->first_free_yielder) {
|
||||||
yielder = wait_list->first_free_yielder;
|
yielder = bin->first_free_yielder;
|
||||||
wait_list->first_free_yielder = yielder->next;
|
bin->first_free_yielder = yielder->next;
|
||||||
} else {
|
} else {
|
||||||
while (atomic_i32_fetch_test_set(&G.yielders_arena_lock, 0, 1) != 0) ix_pause();
|
while (atomic_i32_fetch_test_set(&G.yielders_arena_lock, 0, 1) != 0) ix_pause();
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user