2022-04-12 12:20:17 +00:00
|
|
|
#ifndef COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
|
|
|
|
#define COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_
|
2022-05-19 23:57:49 +00:00
|
|
|
#include "libc/assert.h"
|
2022-05-14 11:33:58 +00:00
|
|
|
#include "libc/calls/calls.h"
|
2022-05-17 11:14:28 +00:00
|
|
|
#include "libc/intrin/lockcmpxchg.h"
|
2022-05-19 23:57:49 +00:00
|
|
|
#include "libc/intrin/lockcmpxchgp.h"
|
2022-05-17 11:14:28 +00:00
|
|
|
|
|
|
|
#if IsModeDbg() && !defined(_SPINLOCK_DEBUG)
|
|
|
|
#define _SPINLOCK_DEBUG
|
|
|
|
#endif
|
2022-04-12 12:20:17 +00:00
|
|
|
|
2022-05-14 11:33:58 +00:00
|
|
|
#if defined(_SPINLOCK_DEBUG)
|
2022-05-17 11:14:28 +00:00
|
|
|
#define _spinlock(lock) _spinlock_ndebug(lock)
|
2022-05-18 23:41:29 +00:00
|
|
|
#define _spinlock_ndebug(lock) _spinlock_cooperative(lock)
|
2022-05-14 11:33:58 +00:00
|
|
|
#elif defined(TINY)
|
2022-05-17 11:14:28 +00:00
|
|
|
#define _spinlock(lock) _spinlock_tiny(lock)
|
|
|
|
#define _spinlock_ndebug(lock) _spinlock_tiny(lock)
|
2022-04-20 16:56:53 +00:00
|
|
|
#else
|
2022-05-18 23:41:29 +00:00
|
|
|
#define _spinlock(lock) _spinlock_cooperative(lock)
|
|
|
|
#define _spinlock_ndebug(lock) _spinlock_cooperative(lock)
|
2022-04-20 16:56:53 +00:00
|
|
|
#endif
|
2022-04-12 12:20:17 +00:00
|
|
|
|
2022-05-14 11:33:58 +00:00
|
|
|
#define _trylock(lock) __atomic_test_and_set(lock, __ATOMIC_SEQ_CST)
|
|
|
|
|
2022-05-19 23:57:49 +00:00
|
|
|
#define _spunlock(lock) \
|
|
|
|
do { \
|
|
|
|
autotype(lock) __lock = (lock); \
|
|
|
|
typeof(*__lock) __x = 0; \
|
|
|
|
__atomic_store(__lock, &__x, __ATOMIC_RELAXED); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define _seizelock(lock) \
|
|
|
|
do { \
|
|
|
|
autotype(lock) __lock = (lock); \
|
|
|
|
typeof(*__lock) __x = 1; \
|
|
|
|
__atomic_store(__lock, &__x, __ATOMIC_RELEASE); \
|
2022-05-13 00:52:13 +00:00
|
|
|
} while (0)
|
2022-04-12 12:20:17 +00:00
|
|
|
|
2022-05-19 23:57:49 +00:00
|
|
|
#define _spinlock_tiny(lock) \
|
|
|
|
do { \
|
|
|
|
autotype(lock) __lock = (lock); \
|
|
|
|
while (_trylock(__lock)) { \
|
|
|
|
__builtin_ia32_pause(); \
|
|
|
|
} \
|
2022-05-14 11:33:58 +00:00
|
|
|
} while (0)
|
|
|
|
|
2022-05-19 23:57:49 +00:00
|
|
|
#define _spinlock_cooperative(lock) \
|
|
|
|
do { \
|
|
|
|
autotype(lock) __lock = (lock); \
|
|
|
|
typeof(*__lock) __x; \
|
|
|
|
int __tries = 0; \
|
|
|
|
for (;;) { \
|
|
|
|
__atomic_load(__lock, &__x, __ATOMIC_RELAXED); \
|
|
|
|
if (!__x && !_trylock(__lock)) { \
|
|
|
|
break; \
|
|
|
|
} else if (++__tries & 7) { \
|
|
|
|
__builtin_ia32_pause(); \
|
|
|
|
} else { \
|
|
|
|
sched_yield(); \
|
|
|
|
} \
|
|
|
|
} \
|
2022-05-14 11:33:58 +00:00
|
|
|
} while (0)
|
|
|
|
|
2022-05-19 23:57:49 +00:00
|
|
|
void _spinlock_debug_1(void *, const char *, const char *, int, const char *);
|
|
|
|
void _spinlock_debug_4(void *, const char *, const char *, int, const char *);
|
|
|
|
|
|
|
|
#define _spinlock_debug(lock) \
|
|
|
|
do { \
|
|
|
|
switch (sizeof(*(lock))) { \
|
|
|
|
case 1: \
|
|
|
|
_spinlock_debug_1(lock, #lock, __FILE__, __LINE__, __FUNCTION__); \
|
|
|
|
break; \
|
|
|
|
case 4: \
|
|
|
|
_spinlock_debug_4(lock, #lock, __FILE__, __LINE__, __FUNCTION__); \
|
|
|
|
break; \
|
|
|
|
default: \
|
|
|
|
assert(!"unsupported size"); \
|
|
|
|
} \
|
2022-05-14 11:33:58 +00:00
|
|
|
} while (0)
|
|
|
|
|
2022-04-12 12:20:17 +00:00
|
|
|
#endif /* COSMOPOLITAN_LIBC_INTRIN_SPINLOCK_H_ */
|