diff --git a/lrwl.h b/lrwl.h new file mode 100644 index 0000000..8c01557 --- /dev/null +++ b/lrwl.h @@ -0,0 +1,63 @@ +#pragma omp + +#define LRWL_WRITE_ACTIVE (1UL<<31) +#define LRWL_MASK (LRWL_WRITE_ACTIVE - 1) +#define LRWL_MAX_READERS 1024 + +typedef struct LRWL { + _Atomic uint32_t data; +} LRWL; + +static inline void lrwl_read_lock(LRWL *self) { + while(1) { + uint32_t data = atomic_load(&self->data); + + if((data & LRWL_WRITE_ACTIVE) || (data & LRWL_MASK) >= LRWL_MAX_READERS) { + continue; + } + + if(atomic_compare_exchange_weak(&self->data, &data, data + 1)) { + return; + } + } +} + +static inline void lrwl_read_unlock(LRWL *self) { + while(1) { + uint32_t data = atomic_load(&self->data); + + assert((data & LRWL_MASK) > 0); + + if(atomic_compare_exchange_weak(&self->data, &data, data - 1)) { + return; + } + } +} + +static inline void lrwl_write_lock(LRWL *self) { + while(1) { + uint32_t data = atomic_load(&self->data); + + if(data & LRWL_WRITE_ACTIVE) { + continue; + } + + if(atomic_compare_exchange_weak(&self->data, &data, data | LRWL_WRITE_ACTIVE)) { + while((atomic_load(&self->data) & LRWL_MASK) > 0); + + return; + } + } +} + +static inline void lrwl_write_unlock(LRWL *self) { + while(1) { + uint32_t data = atomic_load(&self->data); + + assert(data & LRWL_WRITE_ACTIVE); + + if(atomic_compare_exchange_weak(&self->data, &data, data & ~LRWL_WRITE_ACTIVE)) { + return; + } + } +} \ No newline at end of file