123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- #ifndef __SPINLOCK_H__
- #define __SPINLOCK_H__
- #pragma once
- #include "config.h"
- #include "dbgutil.h"
- #if _WIN32
- #include <intrin.h>
- #endif
- #include <assert.h>
- #include <winpr/interlocked.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- typedef volatile LONG lock_t[1];
- #define FASTLOCK_INIT() {0}
- /* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
- #if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
- #define PAUSE_INSTRUCTION() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */
- #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
- #define PAUSE_INSTRUCTION() _mm_pause() /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */
- #elif defined(__WATCOMC__) && defined(__386__)
- /* watcom assembler rejects PAUSE if CPU < i686, and it refuses REP NOP as an invalid combination. Hardcode the bytes. */
- extern _inline void PAUSE_INSTRUCTION(void);
- #pragma aux PAUSE_INSTRUCTION = "db 0f3h,90h"
- #else
- #define PAUSE_INSTRUCTION()
- #endif
- // non-reentrance
- static __inline void fastlock_init(lock_t l)
- {
- l[0] = 0;
- }
- TOOLKIT_API void fastlock_enter(lock_t l);
- static __inline void fastlock_leave(lock_t l)
- {
- _ReadWriteBarrier();
- InterlockedExchange(l, 0);
- }
- static __inline void fastlock_term(lock_t l)
- {
- TOOLKIT_ASSERT(l[0] == 0);
- }
- /* spin lock, note: reentrance!!!
- * 11 1111 1111
- */
- #define DEFAULT_SPIN_COUNT 0x3ff
- // because zero is invalid thread id, so when a thread retrieve the lock
- // _value is set to the thread's id.
- typedef struct spinlock_t {
- volatile DWORD _value;
- volatile DWORD _reentrance;
- }spinlock_t;
- static __inline void spinlock_init(spinlock_t *plock)
- {
- plock->_value = 0;
- plock->_reentrance = 0;
- }
- /**
- * enter lock
- * @param spin_count -1 use default
- */
- TOOLKIT_API void spinlock_enter(volatile spinlock_t *sl, int spin_count);
- /**
- * leave lock
- */
- TOOLKIT_API void spinlock_leave(volatile spinlock_t *sl);
- union rw_spinlock_barrier {
- struct {
- unsigned int readerCount : 32 / 2;
- unsigned int writerCount : 32 / 2 - 1;
- unsigned int writerActive : 1 ;
- };
- unsigned int nAtomic ;
- };
- typedef volatile struct rw_spinlock_s {
- union rw_spinlock_barrier barrier;
- }rw_spinlock_t;
- static __inline void rw_spinlock_init(rw_spinlock_t *rwlock)
- {
- rwlock->barrier.nAtomic = 0;
- }
- // John M. Mellor-Crummey, Michael L. Scott "Scalable Reader-Writer Synchronization for Shared-Memory Multiprocessors", 1991
- TOOLKIT_API void rw_spinlock_read_lock(rw_spinlock_t *rwlock);
- TOOLKIT_API void rw_spinlock_read_unlock(rw_spinlock_t *rwlock);
- TOOLKIT_API void rw_spinlock_write_lock(rw_spinlock_t *rwlock);
- TOOLKIT_API void rw_spinlock_write_unlock(rw_spinlock_t *rwlock);
- static __inline int rw_spinlock_is_reading(rw_spinlock_t *rwlock)
- {
- return rwlock->barrier.readerCount != 0;
- }
- static __inline int rw_spinlock_is_writing(rw_spinlock_t *rwlock)
- {
- return rwlock->barrier.writerActive == 1 ;
- }
- #ifdef __cplusplus
- } // extern "C" {
- #endif
- #endif //__SPINLOCK_H__
|